diff --git a/.gitignore b/.gitignore index 981818a..cf10da8 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,6 @@ cython_debug/ .vscode/ examples/basic_usage.ipynb + +#Test files +test.py diff --git a/.pylintrc b/.pylintrc index 070db46..a17714e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -77,6 +77,9 @@ disable= no-name-in-module, too-many-public-methods, too-many-locals, no-value-for-parameter, + too-many-branches, + too-many-lines, + too-many-statements, diff --git a/README.md b/README.md index ee26a21..fd89adc 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,16 @@ The SDK provides a general Python interface to a remote DSMS deployment, allowin Please have a look at our documentation on _readthedocs_: https://dsms-python-sdk.readthedocs.io +## Compatibility + +Please take the compability of the SDK version with the DSMS version into account: + +| SDK Version | DSMS Version | +| --- | --- | +| <2.0.0 | <2.0.0 | +| >=2.0.0, <3.0.0 | >=2.0.0, <3.0.0 | +| >=3.0.0 | >=3.0.0 | + ## Tutorials Please have a look at our tutorials on _readthedocs_: @@ -48,12 +58,13 @@ Please have a look at our tutorials on _readthedocs_: * [6. Apps](https://dsms-python-sdk.readthedocs.io/en/latest/dsms_sdk/tutorials/6_apps.html) Or try our Jupyter Notebooks: -* [1. Introduction](examples/tutorials/1_introduction.ipynb) -* [2. Creation](examples/tutorials/2_creation.ipynb) -* [3. Updation](examples/tutorials/3_updation.ipynb) -* [4. Deletion](examples/tutorials/4_deletion.ipynb) -* [5. Search](examples/tutorials/5_search.ipynb) -* [6. Apps](examples/tutorials/6_apps.ipynb) +* [1. Introduction](docs/dsms_sdk/tutorials/1_introduction.ipynb) +* [2. Creation](docs/dsms_sdk/tutorials/2_creation.ipynb) +* [3. Updation](docs/dsms_sdk/tutorials/3_updation.ipynb) +* [4. Deletion](docs/dsms_sdk/tutorials/4_deletion.ipynb) +* [5. Search](docs/dsms_sdk/tutorials/5_search.ipynb) +* [6. Apps](docs/dsms_sdk/tutorials/6_apps.ipynb) +* [7. KTypes](docs/dsms_sdk/tutorials/7_ktypes.ipynb) ## Authors @@ -65,6 +76,8 @@ Or try our Jupyter Notebooks: [Priyabrat Mishra](mailto:priyabrat.mishra@iwm.fraunhofer.de) (Fraunhofer Institute for Mechanics of Materials IWM) +[Arjun Gopalakrishnan](mailto:arjun.gopalakrishnan@iwm.fraunhofer.de) (Fraunhofer Institute for Mechanics of Materials IWM) + ## License This project is licensed under the BSD 3-Clause. See the LICENSE file for more information. diff --git a/docs/dsms_sdk/dsms_sdk.md b/docs/dsms_sdk/dsms_sdk.md index abd904e..5677ace 100644 --- a/docs/dsms_sdk/dsms_sdk.md +++ b/docs/dsms_sdk/dsms_sdk.md @@ -48,6 +48,16 @@ Before using DSMS-SDK make sure to register an account in a DSMS Instance of you After following the above steps, you could use either of the two ways to install DSMS-SDK to your machine. +### Compatibility + +Please take the compability of the SDK version with the DSMS version into account: + +| SDK Version | DSMS Version | +| --- | --- | +| <2.0.0 | <2.0.0 | +| >=2.0.0, <3.0.0 | >=2.0.0, <3.0.0 | +| >=3.0.0 | >=3.0.0 | + #### Method 1: Via PyPI To install the [DSMS Python SDK](https://pypi.org/project/dsms-sdk/), you can use the Python Package Index (PyPI). Copy the below command to install DSMS SDK from PyPI: diff --git a/docs/dsms_sdk/tutorials/1_introduction.ipynb b/docs/dsms_sdk/tutorials/1_introduction.ipynb index b9bcb50..13d44cd 100644 --- a/docs/dsms_sdk/tutorials/1_introduction.ipynb +++ b/docs/dsms_sdk/tutorials/1_introduction.ipynb @@ -21,11 +21,11 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "from dsms import DSMS, KItem" + "from dsms import DSMS" ] }, { @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -55,27 +55,28 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can see which kind of DSMS-object we own as a user (in the beginning, we own none):" + "We can see which kitems we own as a user (in the beginning, we own none):" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "kitems: []\n", + "total_count: 0" ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dsms.kitems" + "dsms.get_kitems(limit=100)" ] }, { @@ -91,23 +92,399 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "KTypes.Organization\n", - "KTypes.App\n", - "KTypes.Dataset\n", - "KTypes.DatasetCatalog\n", - "KTypes.Expert\n", - "KTypes.Test\n", - "KTypes.Specimen\n", - "KTypes.Batch\n", - "KTypes.Resource\n", - "KTypes.TestingMachine\n" + "ktype:\n", + " id: organization\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: expert\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: app\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: dataset\n", + " name: dataset\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: dataset-catalog\n", + " name: dataset catalog\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: material\n", + " name: Material\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: true\n", + " class_mapping:\n", + " - https://w3id.org/emmo#EMMO_4207e895_8b83_4318_996a_72cfb32acd94\n", + " sections:\n", + " - id: id37bef167f3118\n", + " name: Material spec\n", + " inputs:\n", + " - id: idd4eca7fb62c54\n", + " label: Material type\n", + " widget: Select\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Crystal\n", + " disabled: false\n", + " - key: option2\n", + " label: Liquid\n", + " disabled: false\n", + " - key: option3\n", + " label: Gas\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasMaterialClass_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_39348191_08fd_4bb6_9b1e_012d5b2f1ff6\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " - id: id0ff68b6b11bf4\n", + " label: Supplier\n", + " widget: Multi-select\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Company 1\n", + " disabled: false\n", + " - key: option2\n", + " label: Company 2\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasSupplier_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/Supplier\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " - id: id8cc24aecb9282\n", + " label: Product form\n", + " widget: Radio\n", + " required: false\n", + " value: Sheet\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Sheet\n", + " disabled: false\n", + " - key: option2\n", + " label: Block\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/emmo#EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_dd4b7d81_28a9_4801_8831_4cbab217e362\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/emmo#EMMO_4207e895_8b83_4318_996a_72cfb32acd94\n", + " suffix: slug\n", + " source: material[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: material-type\n", + " relation: https://w3id.org/steel/ProcessOntology/hasMaterialClass_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_39348191_08fd_4bb6_9b1e_012d5b2f1ff6\n", + " - object_location: supplier\n", + " relation: https://w3id.org/steel/ProcessOntology/hasSupplier_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/steel/ProcessOntology/Supplier\n", + " - object_location: product-form\n", + " relation: https://w3id.org/emmo#EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_dd4b7d81_28a9_4801_8831_4cbab217e362\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-09T23:14:18.843010'\n", + " updated_at: '2025-01-17T09:57:57.584798'\n", + "\n", + "ktype:\n", + " id: testingmachine\n", + " name: Testing machine\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: id18d888a9c9fa48\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: ida450e96a27a6e8\n", + " label: Machine\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/Machine\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: testingmachine\n", + " range_options: null\n", + " placeholder: null\n", + " - id: idba8e853b2fdbe\n", + " label: Specimen\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/pmd/co/Specimen\n", + " relation_mapping_extra: null\n", + " multiple_selection: true\n", + " knowledge_type: specimen\n", + " range_options: null\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: testingmachine[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: machine\n", + " relation: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: specimen\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-12T17:56:45.095403'\n", + " updated_at: '2025-01-16T15:19:06.989779'\n", + "\n", + "ktype:\n", + " id: specimen\n", + " name: Specimen\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: id175f885f8dda58\n", + " label: Width\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " - id: idef5a37328789f\n", + " label: Length\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " relation_mapping_extra:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: true\n", + " placeholder: null\n", + " - id: id54decb9641f9a\n", + " label: Radius\n", + " widget: Number\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: specimen[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: width\n", + " relation: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: length[0]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " suffix: min\n", + " - object_location: length[1]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " suffix: max\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: radius\n", + " relation: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-17T11:00:34.924035'\n", + " updated_at: '2025-01-16T18:25:33.054442'\n", + "\n" ] } ], @@ -119,7 +496,7 @@ ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -133,7 +510,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/2_creation.ipynb b/docs/dsms_sdk/tutorials/2_creation.ipynb index e97199e..896f7bd 100644 --- a/docs/dsms_sdk/tutorials/2_creation.ipynb +++ b/docs/dsms_sdk/tutorials/2_creation.ipynb @@ -21,7 +21,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -62,75 +62,53 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 6a5fd4a4-4dc0-4643-84eb-1e35513974ba, \n", - "\n", - "\tktype_id = KTypes.TestingMachine, \n", - "\n", - "\tin_backend = False, \n", - "\n", - "\tslug = machine-1-6a5fd4a4, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = None, \n", - "\n", - "\tupdated_at = None, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Specimen123\n", + " ktype_id: specimen\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit" ] }, - "execution_count": 3, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "item = KItem(\n", - " name=\"Machine-1\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", - " custom_properties={\"Producer\": \"TestingLab GmBH\",\n", - " \"Location\": \"A404\",\n", - " \"Model Number\" : \"Bending Test Machine No 777\"\n", - " },\n", + " name=\"Specimen123\",\n", + " ktype_id=dsms.ktypes.Specimen,\n", + " custom_properties = {\n", + " \"Width\": 0.5,\n", + " \"Length\": [0.1, 0.2],\n", + " }\n", ")\n", "\n", "item" @@ -145,16 +123,16 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'https://stahldigital.materials-data.space/knowledge/testing-machine/machine-1-6a5fd4a4'" + "'https://bue.materials-data.space/knowledge/specimen/specimen123-73d648b4'" ] }, - "execution_count": 4, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -173,67 +151,60 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 6a5fd4a4-4dc0-4643-84eb-1e35513974ba, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-6a5fd4a4, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: aa97bc4c-939e-4142-8f22-c6be8c0df228\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:24.190604, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:24.190604, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Specimen123\n", + " id: 73d648b4-4619-4a02-a0da-64818df3851e\n", + " ktype_id: specimen\n", + " in_backend: true\n", + " slug: specimen123-73d648b4\n", + " annotations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:56:08.681238\n", + " updated_at: 2025-01-17 10:56:08.681238\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true" ] }, - "execution_count": 5, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -251,16 +222,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'Machine-1'" + "'Specimen123'" ] }, - "execution_count": 6, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -278,16 +249,16 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "UUID('6a5fd4a4-4dc0-4643-84eb-1e35513974ba')" + "UUID('73d648b4-4619-4a02-a0da-64818df3851e')" ] }, - "execution_count": 7, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -305,16 +276,153 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KType(id='testing-machine', name='Testing Machine', webform=, json_schema=None)" + "ktype:\n", + " id: specimen\n", + " name: Specimen\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: id175f885f8dda58\n", + " label: Width\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " - id: idef5a37328789f\n", + " label: Length\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " relation_mapping_extra:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: true\n", + " placeholder: null\n", + " - id: id54decb9641f9a\n", + " label: Radius\n", + " widget: Number\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: specimen[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: width\n", + " relation: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: length[0]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " suffix: min\n", + " - object_location: length[1]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " suffix: max\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: radius\n", + " relation: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-17T11:00:34.924035'\n", + " updated_at: '2025-01-16T18:25:33.054442'" ] }, - "execution_count": 8, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -332,7 +440,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -341,13 +449,60 @@ "True" ] }, - "execution_count": 9, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "item.is_a(dsms.ktypes.TestingMachine)" + "item.is_a(dsms.ktypes.Specimen)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can convert the units:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0005" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "item.custom_properties.Width.convert_to(\"m\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[0.0001, 0.0002]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "item.custom_properties.Length.convert_to(\"m\")" ] }, { @@ -365,7 +520,7 @@ ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -379,7 +534,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/3_updation.ipynb b/docs/dsms_sdk/tutorials/3_updation.ipynb index cfa9245..e2c0705 100644 --- a/docs/dsms_sdk/tutorials/3_updation.ipynb +++ b/docs/dsms_sdk/tutorials/3_updation.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -55,20 +55,82 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "item = dsms.get_kitems(limit=100)[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Machine-1\n" - ] + "data": { + "text/plain": [ + "kitem:\n", + " name: Specimen123\n", + " id: 8ba20087-210d-482c-a847-6f80c20b7d51\n", + " ktype_id: specimen\n", + " slug: specimen123-8ba20087\n", + " annotations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:44:42.478274\n", + " updated_at: 2025-01-17 10:44:42.478274\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: id54decb9641f9a\n", + " type: Number\n", + " label: Radius\n", + " value: 10\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "item = dsms.kitems[-1]\n", - "print(item.name)" + "item" ] }, { @@ -91,25 +153,23 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ - "item.name = \"Machine-1\"\n", - "item.custom_properties.Producer = \"Machinery GmBH\"\n", + "item.name = \"Specimen-123\"\n", + "item.custom_properties.Width = 1\n", "item.attachments.append(\"testfile.txt\")\n", - "item.annotations.append(\"www.machinery.org/\")\n", + "item.annotations.append(\"https://w3id.org/pmd/co/Specimen\")\n", "item.external_links.append(\n", - " {\"url\": \"http://machine.org\", \"label\": \"machine-link\"}\n", + " {\"url\": \"http://specimens.org\", \"label\": \"specimen-link\"}\n", ")\n", - "item.contacts.append({\"name\": \"machinesupport\", \"email\": \"machinesupport@group.mail\"})\n", - "item.affiliations.append(\"machine-team\")\n", - "item.user_groups.append({\"name\": \"machinegroup\", \"group_id\": \"123\"})" + "item.contacts.append({\"name\": \"Specimen preparation\", \"email\": \"specimenpreparation@group.mail\"})" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -132,98 +192,78 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.machinery.org/,\n", - "\t\t\tname: ,\n", - "\t\t\tnamespace: www.machinery.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [\n", - "\t\t{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: Machinery GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Specimen-123\n", + " id: 8ba20087-210d-482c-a847-6f80c20b7d51\n", + " ktype_id: specimen\n", + " in_backend: true\n", + " slug: specimen123-8ba20087\n", + " annotations:\n", + " - iri: https://w3id.org/pmd/co/Specimen\n", + " label: Specimen\n", + " namespace: https://w3id.org/pmd/co\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " - name: testfile.txt\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts:\n", + " - name: Specimen preparation\n", + " email: specimenpreparation@group.mail\n", + " user_id: null\n", + " created_at: 2025-01-17 10:44:42.478274\n", + " updated_at: 2025-01-17 10:51:55.054607\n", + " external_links:\n", + " - label: specimen-link\n", + " url: http://specimens.org\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 1\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: id54decb9641f9a\n", + " type: Number\n", + " label: Radius\n", + " value: 10\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true" ] }, - "execution_count": 19, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -241,19 +281,54 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\t\t\t Downloaded file: {\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", + "\t\t\t Downloaded file: subgraph.ttl\n", + "|------------------------------------Beginning of file------------------------------------|\n", + "@prefix ns1: .\n", + "@prefix ns2: .\n", + "@prefix rdfs: .\n", + "@prefix xsd: .\n", + "\n", + " a ;\n", + " rdfs:label \"Specimen-123\"^^xsd:string ;\n", + " ns2:hasRadius_Object ;\n", + " ns2:hasTotalLength_Object ,\n", + " ;\n", + " ns2:hasWidth_Object .\n", + "\n", + " a ;\n", + " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI ;\n", + " ns1:value 10 .\n", + "\n", + " a ;\n", + " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI ;\n", + " ns1:value 1 .\n", + "\n", + " a ns2:TotalLength ;\n", + " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI ;\n", + " ns1:value \"0.2\"^^xsd:float .\n", + "\n", + " a ns2:TotalLength ;\n", + " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI ;\n", + " ns1:value \"0.1\"^^xsd:float .\n", + "\n", + "\n", + "|---------------------------------------End of file---------------------------------------|\n", + "\n", + "\n", + "\t\t\t Downloaded file: testfile.txt\n", "|------------------------------------Beginning of file------------------------------------|\n", - "This is a calibration protocol!\n", - "|---------------------------------------End of file---------------------------------------|\n" + "This is a specimen preparation protocol!\n", + "\n", + "|---------------------------------------End of file---------------------------------------|\n", + "\n", + "\n" ] } ], @@ -261,16 +336,16 @@ "for file in item.attachments:\n", " download = file.download()\n", "\n", - " print(\"\\t\\t\\t Downloaded file:\", file)\n", + " print(\"\\t\\t\\t Downloaded file:\", file.name)\n", " print(\"|------------------------------------Beginning of file------------------------------------|\")\n", " print(download)\n", - " print(\"|---------------------------------------End of file---------------------------------------|\")" + " print(\"|---------------------------------------End of file---------------------------------------|\\n\\n\")" ] } ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -284,7 +359,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/4_deletion.ipynb b/docs/dsms_sdk/tutorials/4_deletion.ipynb index fe44b17..9a0d699 100644 --- a/docs/dsms_sdk/tutorials/4_deletion.ipynb +++ b/docs/dsms_sdk/tutorials/4_deletion.ipynb @@ -56,100 +56,9 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.machinery.org/,\n", - "\t\t\tname: ,\n", - "\t\t\tnamespace: www.machinery.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [\n", - "\t\t{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: Machinery GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n" - ] - } - ], + "outputs": [], "source": [ - "item = dsms.kitems[-1]\n", - "print(item)" + "item = dsms.get_kitems(limit=100)[-1]" ] }, { @@ -180,10 +89,10 @@ { "data": { "text/plain": [ - "{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}" + "contact:\n", + " name: Specimen preparation\n", + " email: specimenpreparation@group.mail\n", + " user_id: null" ] }, "execution_count": 4, @@ -195,8 +104,7 @@ "item.attachments.pop(0)\n", "item.annotations.pop(0)\n", "item.external_links.pop(0)\n", - "item.contacts.pop(0)\n", - "item.user_groups.pop(0)" + "item.contacts.pop(0)" ] }, { @@ -226,7 +134,17 @@ "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/app/dsms/knowledge/kitem.py:570: UserWarning: A flat dictionary was provided for custom properties.\n", + " Will be transformed into `KItemCustomPropertiesModel`.\n", + " warnings.warn(\n" + ] + } + ], "source": [ "item.custom_properties = {}" ] @@ -240,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -256,81 +174,73 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tid: dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\t\tcontent: {}\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Specimen-123\n", + " id: 8ba20087-210d-482c-a847-6f80c20b7d51\n", + " ktype_id: specimen\n", + " in_backend: true\n", + " slug: specimen123-8ba20087\n", + " annotations: []\n", + " attachments:\n", + " - name: testfile.txt\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts:\n", + " - name: Specimen preparation\n", + " email: specimenpreparation@group.mail\n", + " user_id: null\n", + " created_at: 2025-01-17 10:44:42.478274\n", + " updated_at: 2025-01-17 10:51:55.054607\n", + " external_links:\n", + " - label: specimen-link\n", + " url: http://specimens.org\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 1\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: id54decb9641f9a\n", + " type: Number\n", + " label: Radius\n", + " value: 10\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true" ] }, - "execution_count": 11, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -386,7 +296,7 @@ ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -400,7 +310,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/5_search.ipynb b/docs/dsms_sdk/tutorials/5_search.ipynb index f72fac7..42cef86 100644 --- a/docs/dsms_sdk/tutorials/5_search.ipynb +++ b/docs/dsms_sdk/tutorials/5_search.ipynb @@ -69,11 +69,27 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/app/dsms/knowledge/kitem.py:570: UserWarning: A flat dictionary was provided for custom properties.\n", + " Will be transformed into `KItemCustomPropertiesModel`.\n", + " warnings.warn(\n", + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Producer`. Cannot check if value is of correct type.\n", + " warnings.warn(\n", + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Room Number`. Cannot check if value is of correct type.\n", + " warnings.warn(\n", + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Description`. Cannot check if value is of correct type.\n", + " warnings.warn(\n" + ] + } + ], "source": [ "item1 = KItem(\n", " name=\"Machine-1\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", + " ktype_id=dsms.ktypes.Testingmachine,\n", " annotations=[\"https://w3id.org/steel/ProcessOntology/TestingMachine\"],\n", " custom_properties={\"Producer\": \"TestingLab GmBH\",\n", " \"Room Number\": \"A404\",\n", @@ -83,7 +99,7 @@ "\n", "item2 = KItem(\n", " name=\"Machine-2\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", + " ktype_id=dsms.ktypes.Testingmachine,\n", " annotations=[\"https://w3id.org/steel/ProcessOntology/TestingMachine\"],\n", " custom_properties={\"Producer\": \"StressStrain GmBH\",\n", " \"Room Number\": \"B500\",\n", @@ -96,9 +112,9 @@ " ktype_id=dsms.ktypes.Specimen,\n", " linked_kitems=[item1],\n", " annotations=[\"https://w3id.org/steel/ProcessOntology/TestPiece\"],\n", - " custom_properties={\"Geometry\": \"Cylindrical 150mm x 20mm x 40mm\",\n", - " \"Material\": \"Concrete\",\n", - " \"Project ID\": \"ConstructionProject2024\"\n", + " custom_properties = {\n", + " \"Width\": 0.5,\n", + " \"Length\": [0.1, 0.2],\n", " }\n", "\n", ")\n", @@ -107,10 +123,10 @@ " ktype_id=dsms.ktypes.Specimen,\n", " linked_kitems=[item2],\n", " annotations=[\"https://w3id.org/steel/ProcessOntology/TestPiece\"],\n", - " custom_properties={\"Geometry\": \"Rectangular 200mm x 30mm x 20mm\",\n", - " \"Material\": \"Metal\",\n", - " \"Project ID\": \"MetalBlenders2024\"\n", - " }\n", + " custom_properties = {\n", + " \"Width\": 0.8,\n", + " \"Length\": [0.8, 0.9],\n", + " }\n", ")\n", "\n", "item5 = KItem(\n", @@ -143,218 +159,252 @@ "name": "stdout", "output_type": "stream", "text": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = d1524272-5f34-454b-bb61-7b0ab3a825a7, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-d1524272, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-ba1a7871\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:46.876917\n", - "\t\t\tupdated_at: 2024-08-23T17:15:46.876917\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-2335f57a\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T17:15:47.998202\n", - "\t\t\tupdated_at: 2024-08-23T17:15:47.998202\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:45.431622, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:45.431622, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n" + "hits:\n", + "- kitem:\n", + " name: Specimen123\n", + " id: 54ff62d5-38f7-474c-856e-fa9c8be96a7c\n", + " ktype_id: specimen\n", + " slug: specimen123-54ff62d5\n", + " annotations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:43:36.912252\n", + " updated_at: 2025-01-17 10:43:36.912252\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: id54decb9641f9a\n", + " type: Number\n", + " label: Radius\n", + " value: 10\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true\n", + " fuzzy: false\n", + "- kitem:\n", + " name: Specimen123\n", + " id: 73d648b4-4619-4a02-a0da-64818df3851e\n", + " ktype_id: specimen\n", + " slug: specimen123-73d648b4\n", + " annotations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:56:08.681238\n", + " updated_at: 2025-01-17 10:56:08.681238\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true\n", + " fuzzy: false\n", + "total_count: 8\n", + "\n", + "Name of the first kitem:\n", + "Specimen123\n" ] } ], "source": [ - "for result in dsms.search(ktypes=[dsms.ktypes.TestingMachine], limit=1):\n", - " print(result.hit)\n", - " print(\"\\n\")" + "result = dsms.search(ktypes=[dsms.ktypes.Specimen], limit=2)\n", + "print(result)\n", + "print(\"Name of the first kitem:\")\n", + "print(result.hits[0].kitem.name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "... and for all of type `Organization` and `DatasetCatalog`:" + "... and for all of type `Organization` and `Testingmachine`:" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 2335f57a-efc2-47ce-83b3-866cdeb6d30d, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-2335f57a, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-d1524272\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t}, {\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\tupdated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:47.998202, \n", + "kitem:\n", + " name: Research Institute ABC\n", + " id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " ktype_id: organization\n", + " slug: researchinstituteabc-56a1243e\n", + " annotations:\n", + " - iri: www.researchBACiri.org/foo\n", + " label: foo\n", + " namespace: www.researchBACiri.org\n", + " attachments: []\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " name: Machine-1\n", + " slug: machine-1-7d04a850\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:49.875245'\n", + " updated_at: '2025-01-17T10:57:49.875245'\n", + " - id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " name: Machine-2\n", + " slug: machine-2-9c663adb\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 36c7b92e-0c2d-48bf-b67b-ef1e870085a8\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id1737111469348tops33\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469348shjm7m\n", + " type: Text\n", + " label: Producer\n", + " value: StressStrain GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348awxpwn\n", + " type: Text\n", + " label: Room Number\n", + " value: B500\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348hjsal1\n", + " type: Text\n", + " label: Description\n", + " value: Compression Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.022678'\n", + " updated_at: '2025-01-17T10:57:50.022678'\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:57:50.479332\n", + " updated_at: 2025-01-17 10:57:50.479332\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " rdf_exists: false\n", "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", "fuzziness: False\n", "\n", "\n" @@ -362,8 +412,8 @@ } ], "source": [ - "for result in dsms.search(ktypes=[dsms.ktypes.Organization, dsms.ktypes.DatasetCatalog], limit=1):\n", - " print(result.hit)\n", + "for result in dsms.search(ktypes=[dsms.ktypes.Organization, dsms.ktypes.Testingmachine], limit=1):\n", + " print(result.kitem)\n", " print(\"fuzziness: \", result.fuzzy)\n", " print(\"\\n\")\n", " " @@ -373,18 +423,78 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "... or for all of type `Dataset` with `Specimen-1` in the name:" + "... or for all of type `Specimen` with `Specimen1` in the name:" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "kitem:\n", + " name: Specimen123\n", + " id: 54ff62d5-38f7-474c-856e-fa9c8be96a7c\n", + " ktype_id: specimen\n", + " slug: specimen123-54ff62d5\n", + " annotations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:43:36.912252\n", + " updated_at: 2025-01-17 10:43:36.912252\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " - id: id54decb9641f9a\n", + " type: Number\n", + " label: Radius\n", + " value: 10\n", + " measurement_unit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " namespace: http://qudt.org/vocab/unit\n", + " rdf_exists: true\n", + "fuzzy: false\n", + "\n" + ] + } + ], "source": [ - "for result in dsms.search(query=\"Specimen-1\", ktypes=[dsms.ktypes.Dataset], limit=1):\n", - " print(result.hit)\n", - " print(\"\\n\")" + "for result in dsms.search(query=\"Specimen1\", ktypes=[dsms.ktypes.Specimen], limit=1):\n", + " print(result)" ] }, { @@ -396,223 +506,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 16, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 2335f57a-efc2-47ce-83b3-866cdeb6d30d, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-2335f57a, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-d1524272\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t}, {\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\tupdated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n", - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 379e07a7-acd3-45dd-8bbd-ad5edb549946, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-379e07a7, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-31a7d354\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - "\t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t\tname: Machine-2\n", - "\t\t\tslug: machine-2-8155c264\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:46.777379, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:46.777379, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "for result in dsms.search(\n", " ktypes=[dsms.ktypes.Organization], annotations=[\"www.researchBACiri.org/foo\"], limit=1\n", " ):\n", - " print(result.hit)\n", - " print(\"\\n\")" + " print(result)\n" ] }, { @@ -631,77 +532,111 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[\n", - "\t\t\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-31a7d354\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - "\t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t\tname: Machine-2\n", - "\t\t\tslug: machine-2-8155c264\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\n", - "\t]" + "[linked_kitem:\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " name: Machine-1\n", + " slug: machine-1-7d04a850\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:49.875245'\n", + " updated_at: '2025-01-17T10:57:49.875245',\n", + " linked_kitem:\n", + " id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " name: Machine-2\n", + " slug: machine-2-9c663adb\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 36c7b92e-0c2d-48bf-b67b-ef1e870085a8\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id1737111469348tops33\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469348shjm7m\n", + " type: Text\n", + " label: Producer\n", + " value: StressStrain GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348awxpwn\n", + " type: Text\n", + " label: Room Number\n", + " value: B500\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348hjsal1\n", + " type: Text\n", + " label: Description\n", + " value: Compression Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.022678'\n", + " updated_at: '2025-01-17T10:57:50.022678']" ] }, - "execution_count": 8, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -719,133 +654,141 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 18, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Producer`. Cannot check if value is of correct type.\n", + " warnings.warn(\n", + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Room Number`. Cannot check if value is of correct type.\n", + " warnings.warn(\n", + "/app/dsms/knowledge/webform.py:655: UserWarning: No webform was defined for entry `Description`. Cannot check if value is of correct type.\n", + " warnings.warn(\n" + ] + }, { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Machine-1\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " ktype_id: testingmachine\n", + " slug: machine-1-7d04a850\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " name: Research Institute ABC\n", + " slug: researchinstituteabc-56a1243e\n", + " ktype_id: organization\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: www.researchBACiri.org/foo\n", + " label: foo\n", + " namespace: www.researchBACiri.org\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " - id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments: []\n", + " user_groups: []\n", + " custom_properties: null\n", + " created_at: '2025-01-17T10:57:50.479332'\n", + " updated_at: '2025-01-17T10:57:50.479332'\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " name: Specimen-1\n", + " slug: specimen-1-75b7126b\n", + " ktype_id: specimen\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestPiece\n", + " label: TestPiece\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.171534'\n", + " updated_at: '2025-01-17T10:57:50.171534'\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:57:49.875245\n", + " updated_at: 2025-01-17 10:57:49.875245\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " rdf_exists: true" ] }, - "execution_count": 9, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -863,75 +806,111 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'https://w3id.org/steel/ProcessOntology/TestingMachine': [\n", - " \t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - " \t\t\tname: Machine-1\n", - " \t\t\tslug: machine-1-31a7d354\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - " \t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - " \t\t,\n", - " \n", - " \t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - " \t\t\tname: Machine-2\n", - " \t\t\tslug: machine-2-8155c264\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - " \t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - " \t\t]}" + "{'https://w3id.org/steel/ProcessOntology/TestingMachine': [linked_kitem:\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " name: Machine-1\n", + " slug: machine-1-7d04a850\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:49.875245'\n", + " updated_at: '2025-01-17T10:57:49.875245',\n", + " linked_kitem:\n", + " id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " name: Machine-2\n", + " slug: machine-2-9c663adb\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 36c7b92e-0c2d-48bf-b67b-ef1e870085a8\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id1737111469348tops33\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469348shjm7m\n", + " type: Text\n", + " label: Producer\n", + " value: StressStrain GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348awxpwn\n", + " type: Text\n", + " label: Room Number\n", + " value: B500\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348hjsal1\n", + " type: Text\n", + " label: Description\n", + " value: Compression Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.022678'\n", + " updated_at: '2025-01-17T10:57:50.022678']}" ] }, - "execution_count": 10, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -949,133 +928,129 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Machine-1\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " ktype_id: testingmachine\n", + " slug: machine-1-7d04a850\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " name: Research Institute ABC\n", + " slug: researchinstituteabc-56a1243e\n", + " ktype_id: organization\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: www.researchBACiri.org/foo\n", + " label: foo\n", + " namespace: www.researchBACiri.org\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " - id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments: []\n", + " user_groups: []\n", + " custom_properties: null\n", + " created_at: '2025-01-17T10:57:50.479332'\n", + " updated_at: '2025-01-17T10:57:50.479332'\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " name: Specimen-1\n", + " slug: specimen-1-75b7126b\n", + " ktype_id: specimen\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestPiece\n", + " label: TestPiece\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.171534'\n", + " updated_at: '2025-01-17T10:57:50.171534'\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:57:49.875245\n", + " updated_at: 2025-01-17 10:57:49.875245\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " rdf_exists: true" ] }, - "execution_count": 11, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -1093,75 +1068,184 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{: [\n", - " \t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - " \t\t\tname: Machine-1\n", - " \t\t\tslug: machine-1-31a7d354\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - " \t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - " \t\t,\n", - " \n", - " \t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - " \t\t\tname: Machine-2\n", - " \t\t\tslug: machine-2-8155c264\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - " \t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - " \t\t]}" + "{ktype:\n", + " id: testingmachine\n", + " name: Testing machine\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: id18d888a9c9fa48\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: ida450e96a27a6e8\n", + " label: Machine\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/Machine\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: testingmachine\n", + " range_options: null\n", + " placeholder: null\n", + " - id: idba8e853b2fdbe\n", + " label: Specimen\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/pmd/co/Specimen\n", + " relation_mapping_extra: null\n", + " multiple_selection: true\n", + " knowledge_type: specimen\n", + " range_options: null\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: testingmachine[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: machine\n", + " relation: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: specimen\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-12T17:56:45.095403'\n", + " updated_at: '2025-01-16T15:19:06.989779': [linked_kitem:\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " name: Machine-1\n", + " slug: machine-1-7d04a850\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:49.875245'\n", + " updated_at: '2025-01-17T10:57:49.875245',\n", + " linked_kitem:\n", + " id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " name: Machine-2\n", + " slug: machine-2-9c663adb\n", + " ktype_id: testingmachine\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 36c7b92e-0c2d-48bf-b67b-ef1e870085a8\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id1737111469348tops33\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469348shjm7m\n", + " type: Text\n", + " label: Producer\n", + " value: StressStrain GmBH\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348awxpwn\n", + " type: Text\n", + " label: Room Number\n", + " value: B500\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " - id: id1737111469348hjsal1\n", + " type: Text\n", + " label: Description\n", + " value: Compression Test Machine\n", + " measurementUnit: null\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.022678'\n", + " updated_at: '2025-01-17T10:57:50.022678']}" ] }, - "execution_count": 12, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -1179,139 +1263,135 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" + "kitem:\n", + " name: Machine-1\n", + " id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " ktype_id: testingmachine\n", + " slug: machine-1-7d04a850\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestingMachine\n", + " label: TestingMachine\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems:\n", + " - id: 56a1243e-0e8e-4528-bad0-b683b84b64e7\n", + " name: Research Institute ABC\n", + " slug: researchinstituteabc-56a1243e\n", + " ktype_id: organization\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: www.researchBACiri.org/foo\n", + " label: foo\n", + " namespace: www.researchBACiri.org\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " - id: 9c663adb-6173-4cb5-acc1-9d89d37b7155\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments: []\n", + " user_groups: []\n", + " custom_properties: null\n", + " created_at: '2025-01-17T10:57:50.479332'\n", + " updated_at: '2025-01-17T10:57:50.479332'\n", + " - id: 75b7126b-950d-4473-b86c-f9780dae333f\n", + " name: Specimen-1\n", + " slug: specimen-1-75b7126b\n", + " ktype_id: specimen\n", + " summary: null\n", + " avatar_exists: false\n", + " annotations:\n", + " - iri: https://w3id.org/steel/ProcessOntology/TestPiece\n", + " label: TestPiece\n", + " namespace: https://w3id.org/steel/ProcessOntology\n", + " linked_kitems:\n", + " - id: 7d04a850-f4e5-4682-b043-1414cf4d0fd9\n", + " external_links: []\n", + " contacts: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " linked_affiliations: []\n", + " attachments:\n", + " - name: subgraph.ttl\n", + " content: null\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " entries:\n", + " - id: id175f885f8dda58\n", + " type: Slider\n", + " label: Width\n", + " value: 0.5\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " - id: idef5a37328789f\n", + " type: Slider\n", + " label: Length\n", + " value:\n", + " - 0.1\n", + " - 0.2\n", + " measurementUnit:\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " label: Millimetre\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relationMapping: null\n", + " created_at: '2025-01-17T10:57:50.171534'\n", + " updated_at: '2025-01-17T10:57:50.171534'\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: false\n", + " contacts: []\n", + " created_at: 2025-01-17 10:57:49.875245\n", + " updated_at: 2025-01-17 10:57:49.875245\n", + " external_links: []\n", + " kitem_apps: []\n", + " user_groups: []\n", + " custom_properties:\n", + " sections:\n", + " - id: id17371114692064uv9g3\n", + " name: Misc\n", + " entries:\n", + " - id: id1737111469206ueowwr\n", + " type: Text\n", + " label: Producer\n", + " value: TestingLab GmBH\n", + " - id: id1737111469206dllz5f\n", + " type: Text\n", + " label: Room Number\n", + " value: A404\n", + " - id: id1737111469206wrddrm\n", + " type: Text\n", + " label: Description\n", + " value: Bending Test Machine\n", + " rdf_exists: true" ] }, - "execution_count": 13, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "item5.linked_kitems.by_ktype[dsms.ktypes.TestingMachine][0].fetch()" + "item5.linked_kitems.by_ktype[dsms.ktypes.Testingmachine][0].fetch()" ] }, { @@ -1339,7 +1419,7 @@ ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1353,7 +1433,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/6_apps.ipynb b/docs/dsms_sdk/tutorials/6_apps.ipynb index 8f60c45..f2ebfcf 100644 --- a/docs/dsms_sdk/tutorials/6_apps.ipynb +++ b/docs/dsms_sdk/tutorials/6_apps.ipynb @@ -69,14 +69,30 @@ { "data": { "text/plain": [ - "[AppConfig(name=ckan-fetch, specification={'metadata': {'generateName': 'ckan-resource-request-'}}),\n", - " AppConfig(name=csv_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=csv_tensile_test_f2, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_notched_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_shear_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=ternary-plot, specification={'metadata': {'generateName': 'ckan-tenary-app-'}}),\n", - " AppConfig(name=testapp2, specification={'metadata': {'generateName': 'data2rdf-'}})]" + "[app:\n", + " name: ckan-fetch,\n", + " app:\n", + " name: csv_tensile_test,\n", + " app:\n", + " name: csv_tensile_test_f2,\n", + " app:\n", + " name: csv_tensile_test_three_directions,\n", + " app:\n", + " name: dsms-materialcard,\n", + " app:\n", + " name: dsms-tensile-test-analysis,\n", + " app:\n", + " name: excel_notch_tensile_test,\n", + " app:\n", + " name: excel_notched_tensile_test,\n", + " app:\n", + " name: excel_shear_tensile_test,\n", + " app:\n", + " name: excel_shear_test,\n", + " app:\n", + " name: excel_tensile_test,\n", + " app:\n", + " name: ternary-plot]" ] }, "execution_count": 3, @@ -202,7 +218,6 @@ " {\"name\": \"time_series_header_length\", \"value\": 1},\n", " {\"name\": \"metadata_length\", \"value\": 0},\n", " {\"name\": \"time_series_sep\", \"value\": \",\"},\n", - " {\"name\": \"log_level\", \"value\": \"DEBUG\"},\n", " {\n", " \"name\": \"mapping\",\n", " \"value\": \"\"\"\n", @@ -248,7 +263,7 @@ " \"metadata\": {\"generateName\": \"data2rdf-\"},\n", " \"spec\": {\n", " \"entrypoint\": \"execute_pipeline\",\n", - " \"workflowTemplateRef\": {\"name\": \"dsms-data2rdf\"},\n", + " \"workflowTemplateRef\": {\"name\": \"dsms-data2rdf-1.2.1\"},\n", " \"arguments\": {\"parameters\": parameters},\n", " },\n", "}" @@ -297,6 +312,49 @@ "dsms.commit()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And show the app specification:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'apiVersion': 'argoproj.io/v1alpha1',\n", + " 'kind': 'Workflow',\n", + " 'metadata': {'generateName': 'data2rdf-'},\n", + " 'spec': {'entrypoint': 'execute_pipeline',\n", + " 'workflowTemplateRef': {'name': 'dsms-data2rdf-1.2.1'},\n", + " 'arguments': {'parameters': [{'name': 'parser', 'value': 'csv'},\n", + " {'name': 'time_series_header_length', 'value': 1},\n", + " {'name': 'metadata_length', 'value': 0},\n", + " {'name': 'time_series_sep', 'value': ','},\n", + " {'name': 'mapping',\n", + " 'value': '\\n [\\n {\\n \"key\": \"A\",\\n \"iri\": \"https://w3id.org/steel/ProcessOntology/TestTime\",\\n \"unit\": \"s\"\\n },\\n {\\n \"key\": \"B\",\\n \"iri\": \"https://w3id.org/steel/ProcessOntology/StandardForce\",\\n \"unit\": \"kN\"\\n },\\n {\\n \"key\": \"C\",\\n \"iri\": \"https://w3id.org/steel/ProcessOntology/AbsoluteCrossheadTravel\",\\n \"unit\": \"mm\"\\n }\\n ]\\n '},\n", + " {'name': 'request_timeout', 'value': 120},\n", + " {'name': 'ping', 'value': True},\n", + " {'name': 'host_url', 'value': 'https://bue.materials-data.space/'},\n", + " {'name': 'ssl_verify', 'value': True},\n", + " {'name': 'kitem_repo', 'value': 'knowledge-items'},\n", + " {'name': 'encoding', 'value': 'utf-8'}]}}}" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appspec.specification" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -310,7 +368,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -340,7 +398,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -356,7 +414,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -372,7 +430,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -395,87 +453,53 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "KItem(\n", - "\n", - "\tname = my tensile test experiment, \n", - "\n", - "\tid = 047c3e0e-0c4c-4815-b041-5251c2ef0882, \n", - "\n", - "\tktype_id = dataset, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = mytensiletestexperiment-047c3e0e, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: dummy_data.csv\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = True, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-19 19:27:11.826889, \n", - "\n", - "\tupdated_at = 2024-08-19 19:27:11.826889, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [\n", - "\t\t{\n", - "\t\t\tkitem_app_id: 21,\n", - "\t\t\texecutable: testapp2,\n", - "\t\t\ttitle: data2rdf,\n", - "\t\t\tdescription: None,\n", - "\t\t\ttags: None,\n", - "\t\t\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = [\n", - "\t\t{\n", - "\t\t\tcolumn_id: 0,\n", - "\t\t\tname: TestTime\n", - "\t\t}, \n", - "\t\t{\n", - "\t\t\tcolumn_id: 1,\n", - "\t\t\tname: StandardForce\n", - "\t\t}, \n", - "\t\t{\n", - "\t\t\tcolumn_id: 2,\n", - "\t\t\tname: AbsoluteCrossheadTravel\n", - "\t\t}\n", - "\t], \n", - "\n", - "\trdf_exists = True\n", - ")\n" + "kitem:\n", + " name: my tensile test experiment\n", + " id: 12f0939b-8125-4a4a-9159-84f731e54d5d\n", + " ktype_id: dataset\n", + " in_backend: true\n", + " slug: mytensiletestexperiment-12f0939b\n", + " annotations: []\n", + " attachments:\n", + " - name: dummy_data.csv\n", + " content: null\n", + " - name: subgraph.ttl\n", + " content: null\n", + " linked_kitems: []\n", + " affiliations: []\n", + " authors:\n", + " - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", + " avatar_exists: true\n", + " contacts: []\n", + " created_at: 2025-01-17 12:05:18.315322\n", + " updated_at: 2025-01-17 12:05:18.315322\n", + " external_links: []\n", + " kitem_apps:\n", + " - executable: testapp2\n", + " title: data2rdf\n", + " description: null\n", + " tags: null\n", + " additional_properties:\n", + " triggerUponUpload: true\n", + " triggerUponUploadFileExtensions:\n", + " - .csv\n", + " user_groups: []\n", + " dataframe:\n", + " - column_id: 0\n", + " name: TestTime\n", + " - column_id: 1\n", + " name: StandardForce\n", + " - column_id: 2\n", + " name: AbsoluteCrossheadTravel\n", + " rdf_exists: true\n", + "\n" ] } ], @@ -492,7 +516,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -502,50 +526,50 @@ "@prefix csvw: .\n", "@prefix dcat: .\n", "@prefix dcterms: .\n", - "@prefix ns1: .\n", - "@prefix ns2: .\n", + "@prefix ns1: .\n", + "@prefix ns2: .\n", "@prefix rdfs: .\n", "@prefix xsd: .\n", "\n", - " a dcat:Dataset ;\n", - " dcterms:hasPart ;\n", + " a dcat:Dataset ;\n", + " dcterms:hasPart ;\n", " dcat:distribution [ a dcat:Distribution ;\n", - " dcat:accessURL \"https://bue.materials-data.space/api/knowledge/data_api/047c3e0e-0c4c-4815-b041-5251c2ef0882\"^^xsd:anyURI ;\n", + " dcat:accessURL \"https://bue.materials-data.space/api/knowledge/data_api/12f0939b-8125-4a4a-9159-84f731e54d5d\"^^xsd:anyURI ;\n", " dcat:mediaType \"http://www.iana.org/assignments/media-types/text/csv\"^^xsd:anyURI ] .\n", "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI .\n", + " a ;\n", + " ns2:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI .\n", "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/KiloN\"^^xsd:anyURI .\n", + " a ;\n", + " ns2:hasUnit \"http://qudt.org/vocab/unit/KiloN\"^^xsd:anyURI .\n", "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/SEC\"^^xsd:anyURI .\n", + " a ;\n", + " ns2:hasUnit \"http://qudt.org/vocab/unit/SEC\"^^xsd:anyURI .\n", "\n", - " a csvw:TableGroup ;\n", + " a csvw:TableGroup ;\n", " csvw:table [ a csvw:Table ;\n", " rdfs:label \"Time series data\" ;\n", " csvw:tableSchema [ a csvw:Schema ;\n", " csvw:column [ a csvw:Column ;\n", - " ns1:quantity ;\n", - " csvw:titles \"C\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", - " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", - " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-2\"^^xsd:anyURI ;\n", - " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ],\n", - " [ a csvw:Column ;\n", - " ns1:quantity ;\n", + " ns2:quantity ;\n", " csvw:titles \"A\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", + " ns1:page [ a ns1:Document ;\n", " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-0\"^^xsd:anyURI ;\n", " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ],\n", " [ a csvw:Column ;\n", - " ns1:quantity ;\n", + " ns2:quantity ;\n", " csvw:titles \"B\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", + " ns1:page [ a ns1:Document ;\n", " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-1\"^^xsd:anyURI ;\n", + " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ],\n", + " [ a csvw:Column ;\n", + " ns2:quantity ;\n", + " csvw:titles \"C\"^^xsd:string ;\n", + " ns1:page [ a ns1:Document ;\n", + " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", + " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-2\"^^xsd:anyURI ;\n", " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ] ] ] .\n", "\n", "\n" @@ -565,7 +589,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -583,7 +607,7 @@ " 6000.0]" ] }, - "execution_count": 16, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -608,7 +632,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -716,7 +740,7 @@ "9 5.8 6.0 6.1" ] }, - "execution_count": 17, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -734,7 +758,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -755,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -785,7 +809,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -813,7 +837,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -832,16 +856,16 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "JobStatus(phase='Succeeded', estimated_duration=None, finished_at='08/19/2024, 19:28:06', started_at='08/19/2024, 19:27:43', message=None, progress='1/1')" + "JobStatus(phase='Succeeded', estimated_duration=None, finished_at='01/17/2025, 12:06:14', started_at='01/17/2025, 12:05:54', message=None, progress='1/1')" ] }, - "execution_count": 22, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -859,19 +883,22 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 31, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\"[2024-08-19 19:27:49,060 - dsms_data2rdf.main - INFO]: Fetch KItem: \\n KItem(\\n\\n\\tname = my tensile test experiment, \\n\\n\\tid = 047c3e0e-0c4c-4815-b041-5251c2ef0882, \\n\\n\\tktype_id = dataset, \\n\\n\\tin_backend = True, \\n\\n\\tslug = mytensiletestexperiment-047c3e0e, \\n\\n\\tannotations = [], \\n\\n\\tattachments = [\\n\\t\\t{\\n\\t\\t\\tname: dummy_data.csv\\n\\t\\t}\\n\\t], \\n\\n\\tlinked_kitems = [], \\n\\n\\taffiliations = [], \\n\\n\\tauthors = [\\n\\t\\t{\\n\\t\\t\\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\n\\t\\t}\\n\\t], \\n\\n\\tavatar_exists = True, \\n\\n\\tcontacts = [], \\n\\n\\tcreated_at = 2024-08-19 19:27:11.826889, \\n\\n\\tupdated_at = 2024-08-19 19:27:11.826889, \\n\\n\\texternal_links = [], \\n\\n\\tkitem_apps = [\\n\\t\\t{\\n\\t\\t\\tkitem_app_id: 21,\\n\\t\\t\\texecutable: testapp2,\\n\\t\\t\\ttitle: data2rdf,\\n\\t\\t\\tdescription: None,\\n\\t\\t\\ttags: None,\\n\\t\\t\\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\\n\\t\\t}\\n\\t], \\n\\n\\tsummary = None, \\n\\n\\tuser_groups = [], \\n\\n\\tcustom_properties = None, \\n\\n\\tdataframe = [\\n\\t\\t{\\n\\t\\t\\tcolumn_id: 0,\\n\\t\\t\\tname: TestTime\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 1,\\n\\t\\t\\tname: StandardForce\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 2,\\n\\t\\t\\tname: AbsoluteCrossheadTravel\\n\\t\\t}\\n\\t], \\n\\n\\trdf_exists = True\\n)\\n[2024-08-19 19:27:49,073 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {'metadata_sep': ',', 'metadata_length': '0', 'time_series_sep': ',', 'time_series_header_length': '1', 'drop_na': 'false', 'fillna': ''}\\n[2024-08-19 19:27:49,073 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\n[2024-08-19 19:27:49,073 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {'base_iri': 'https://bue.materials-data.space/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'data_download_uri': 'https://bue.materials-data.space/api/knowledge/data_api/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'graph_identifier': 'https://bue.materials-data.space/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'separator': '/', 'encoding': 'utf-8'}\\n[2024-08-19 19:27:54,079 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\n[2024-08-19 19:27:54,455 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\n[2024-08-19 19:27:54,455 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\n[2024-08-19 19:27:54,456 - dsms_data2rdf.main - INFO]: Done!\\n\"\n" - ] + "data": { + "text/plain": [ + "'\"[2025-01-17 12:06:24,552 - dsms_data2rdf.main - INFO]: Fetch KItem: \\\\n kitem:\\\\n name: my tensile test experiment\\\\n id: 12f0939b-8125-4a4a-9159-84f731e54d5d\\\\n ktype_id: dataset\\\\n slug: mytensiletestexperiment-12f0939b\\\\n annotations: []\\\\n attachments:\\\\n - name: dummy_data.csv\\\\n content: null\\\\n - name: subgraph.ttl\\\\n content: null\\\\n linked_kitems: []\\\\n affiliations: []\\\\n authors:\\\\n - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\\\n avatar_exists: true\\\\n contacts: []\\\\n created_at: 2025-01-17 12:05:18.315322\\\\n updated_at: 2025-01-17 12:05:18.315322\\\\n external_links: []\\\\n kitem_apps:\\\\n - executable: testapp2\\\\n title: data2rdf\\\\n description: null\\\\n tags: null\\\\n additional_properties:\\\\n triggerUponUpload: true\\\\n triggerUponUploadFileExtensions:\\\\n - .csv\\\\n user_groups: []\\\\n rdf_exists: true\\\\n\\\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {\\'metadata_sep\\': \\',\\', \\'metadata_length\\': 0, \\'time_series_sep\\': \\',\\', \\'time_series_header_length\\': 1, \\'drop_na\\': False, \\'fillna\\': None}\\\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {\\'base_iri\\': \\'https://bue.materials-data.space/12f0939b-8125-4a4a-9159-84f731e54d5d\\', \\'data_download_uri\\': \\'https://bue.materials-data.space/api/knowledge/data_api/12f0939b-8125-4a4a-9159-84f731e54d5d\\', \\'graph_identifier\\': \\'https://bue.materials-data.space/12f0939b-8125-4a4a-9159-84f731e54d5d\\', \\'separator\\': \\'/\\', \\'encoding\\': \\'utf-8\\'}\\\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Pipeline finished.\\\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Extracted Time Series: Index([\\'TestTime\\', \\'StandardForce\\', \\'AbsoluteCrossheadTravel\\'], dtype=\\'object\\')\\\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Done!\\\\n\"'" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "print(job.logs)" + "job.logs" ] }, { @@ -883,7 +910,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -903,7 +930,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -912,100 +939,124 @@ "text": [ "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/19/2024, 19:28:06' message=None progress='0/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", "\"\"\n", "\n", " Current status:\n", - "phase='Succeeded' estimated_duration=None finished_at='08/19/2024, 19:28:26' started_at='08/19/2024, 19:28:06' message=None progress='1/1'\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", "\n", " Current logs:\n", - "\"[2024-08-19 19:28:13,519 - dsms_data2rdf.main - INFO]: Fetch KItem: \\n KItem(\\n\\n\\tname = my tensile test experiment, \\n\\n\\tid = 047c3e0e-0c4c-4815-b041-5251c2ef0882, \\n\\n\\tktype_id = dataset, \\n\\n\\tin_backend = True, \\n\\n\\tslug = mytensiletestexperiment-047c3e0e, \\n\\n\\tannotations = [], \\n\\n\\tattachments = [\\n\\t\\t{\\n\\t\\t\\tname: dummy_data.csv\\n\\t\\t}\\n\\t], \\n\\n\\tlinked_kitems = [], \\n\\n\\taffiliations = [], \\n\\n\\tauthors = [\\n\\t\\t{\\n\\t\\t\\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\n\\t\\t}\\n\\t], \\n\\n\\tavatar_exists = True, \\n\\n\\tcontacts = [], \\n\\n\\tcreated_at = 2024-08-19 19:27:11.826889, \\n\\n\\tupdated_at = 2024-08-19 19:27:11.826889, \\n\\n\\texternal_links = [], \\n\\n\\tkitem_apps = [\\n\\t\\t{\\n\\t\\t\\tkitem_app_id: 21,\\n\\t\\t\\texecutable: testapp2,\\n\\t\\t\\ttitle: data2rdf,\\n\\t\\t\\tdescription: None,\\n\\t\\t\\ttags: None,\\n\\t\\t\\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\\n\\t\\t}\\n\\t], \\n\\n\\tsummary = None, \\n\\n\\tuser_groups = [], \\n\\n\\tcustom_properties = None, \\n\\n\\tdataframe = [\\n\\t\\t{\\n\\t\\t\\tcolumn_id: 0,\\n\\t\\t\\tname: TestTime\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 1,\\n\\t\\t\\tname: StandardForce\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 2,\\n\\t\\t\\tname: AbsoluteCrossheadTravel\\n\\t\\t}\\n\\t], \\n\\n\\trdf_exists = True\\n)\\n[2024-08-19 19:28:13,532 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {'metadata_sep': ',', 'metadata_length': '0', 'time_series_sep': ',', 'time_series_header_length': '1', 'drop_na': 'false', 'fillna': ''}\\n[2024-08-19 19:28:13,532 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\n[2024-08-19 19:28:13,532 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {'base_iri': 'https://bue.materials-data.space/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'data_download_uri': 'https://bue.materials-data.space/api/knowledge/data_api/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'graph_identifier': 'https://bue.materials-data.space/047c3e0e-0c4c-4815-b041-5251c2ef0882', 'separator': '/', 'encoding': 'utf-8'}\\n[2024-08-19 19:28:18,546 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\n[2024-08-19 19:28:18,929 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\n[2024-08-19 19:28:18,929 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\n[2024-08-19 19:28:18,929 - dsms_data2rdf.main - INFO]: Done!\\n\"\n" + "\"\"\n", + "\n", + " Current status:\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", + "\n", + " Current logs:\n", + "\"\"\n", + "\n", + " Current status:\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", + "\n", + " Current logs:\n", + "\"\"\n", + "\n", + " Current status:\n", + "phase='Running' estimated_duration=None finished_at=None started_at='01/17/2025, 12:06:15' message=None progress='0/1'\n", + "\n", + " Current logs:\n", + "\"\"\n", + "\n", + " Current status:\n", + "phase='Succeeded' estimated_duration=None finished_at='01/17/2025, 12:06:41' started_at='01/17/2025, 12:06:15' message=None progress='1/1'\n", + "\n", + " Current logs:\n", + "\"[2025-01-17 12:06:24,552 - dsms_data2rdf.main - INFO]: Fetch KItem: \\n kitem:\\n name: my tensile test experiment\\n id: 12f0939b-8125-4a4a-9159-84f731e54d5d\\n ktype_id: dataset\\n slug: mytensiletestexperiment-12f0939b\\n annotations: []\\n attachments:\\n - name: dummy_data.csv\\n content: null\\n - name: subgraph.ttl\\n content: null\\n linked_kitems: []\\n affiliations: []\\n authors:\\n - user_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\n avatar_exists: true\\n contacts: []\\n created_at: 2025-01-17 12:05:18.315322\\n updated_at: 2025-01-17 12:05:18.315322\\n external_links: []\\n kitem_apps:\\n - executable: testapp2\\n title: data2rdf\\n description: null\\n tags: null\\n additional_properties:\\n triggerUponUpload: true\\n triggerUponUploadFileExtensions:\\n - .csv\\n user_groups: []\\n rdf_exists: true\\n\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {'metadata_sep': ',', 'metadata_length': 0, 'time_series_sep': ',', 'time_series_header_length': 1, 'drop_na': False, 'fillna': None}\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\n[2025-01-17 12:06:24,569 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {'base_iri': 'https://bue.materials-data.space/12f0939b-8125-4a4a-9159-84f731e54d5d', 'data_download_uri': 'https://bue.materials-data.space/api/knowledge/data_api/12f0939b-8125-4a4a-9159-84f731e54d5d', 'graph_identifier': 'https://bue.materials-data.space/12f0939b-8125-4a4a-9159-84f731e54d5d', 'separator': '/', 'encoding': 'utf-8'}\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Pipeline finished.\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\n[2025-01-17 12:06:29,292 - dsms_data2rdf.main - INFO]: Extracted Time Series: Index(['TestTime', 'StandardForce', 'AbsoluteCrossheadTravel'], dtype='object')\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\n[2025-01-17 12:06:29,788 - dsms_data2rdf.main - INFO]: Done!\\n\"\n" ] } ], @@ -1029,7 +1080,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -1045,7 +1096,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -1057,7 +1108,7 @@ ], "metadata": { "kernelspec": { - "display_name": "sdk", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1071,7 +1122,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.15" } }, "nbformat": 4, diff --git a/docs/dsms_sdk/tutorials/7_ktypes.ipynb b/docs/dsms_sdk/tutorials/7_ktypes.ipynb new file mode 100644 index 0000000..07dbfc1 --- /dev/null +++ b/docs/dsms_sdk/tutorials/7_ktypes.ipynb @@ -0,0 +1,724 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 7. Interact with KTypes through the SDK\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7.1. Setting up\n", + "\n", + "Before you run this tutorial: make sure to have access to a DSMS-instance of your interest, alongwith with installation of this package and have establised access to the DSMS through DSMS-SDK (refer to [Connecting to DSMS](../dsms_sdk.md#connecting-to-dsms))\n", + "\n", + "Import the needed classes and functions." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from dsms import DSMS, KType" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now source the environmental variables from an `.env` file and start the DSMS-session." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "dsms = DSMS(env=\".env\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7.2. Create KTypes\n", + "\n", + "New KTypes can be created by a simple class inititation." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ktype:\n", + " id: batch\n", + " name: Batch\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: null\n", + " updated_at: null" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ktype = KType( \n", + " id='batch',\n", + " name='Batch'\n", + ")\n", + "\n", + "ktype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `commit` method should be executed to synchronize the changes with the DSMS SDK." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "dsms.commit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `type` object will automatically get updated with after the commit." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ktype:\n", + " id: batch\n", + " name: Batch\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2025-01-17T11:54:17.493125'\n", + " updated_at: '2025-01-17T11:54:17.493125'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ktype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7.3. Update KTypes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ktype object can be fetched using its id." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ktype:\n", + " id: batch\n", + " name: Batch\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2025-01-17T11:54:17.493125'\n", + " updated_at: '2025-01-17T11:54:17.493125'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ktype = dsms.ktypes.Batch\n", + "ktype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can change e.g. the name of the ktype" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "ktype.name = 'Batches'\n", + "dsms.commit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After the committing, we can see the changes of the ktype" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ktype:\n", + " id: batch\n", + " name: Batches\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2025-01-17T11:54:17.493125'\n", + " updated_at: '2025-01-17T11:54:18.373264'" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ktype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7.5. Fetching KTypes\n", + "\n", + "The existing KTypes can be fetched as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ktype:\n", + " id: organization\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: expert\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: app\n", + " name: null\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: dataset\n", + " name: dataset\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: dataset-catalog\n", + " name: dataset catalog\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2024-12-09T15:48:24.918527'\n", + " updated_at: '2024-12-09T15:48:24.918527'\n", + "\n", + "ktype:\n", + " id: material\n", + " name: Material\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: true\n", + " class_mapping:\n", + " - https://w3id.org/emmo#EMMO_4207e895_8b83_4318_996a_72cfb32acd94\n", + " sections:\n", + " - id: id37bef167f3118\n", + " name: Material spec\n", + " inputs:\n", + " - id: idd4eca7fb62c54\n", + " label: Material type\n", + " widget: Select\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Crystal\n", + " disabled: false\n", + " - key: option2\n", + " label: Liquid\n", + " disabled: false\n", + " - key: option3\n", + " label: Gas\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasMaterialClass_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_39348191_08fd_4bb6_9b1e_012d5b2f1ff6\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " - id: id0ff68b6b11bf4\n", + " label: Supplier\n", + " widget: Multi-select\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Company 1\n", + " disabled: false\n", + " - key: option2\n", + " label: Company 2\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasSupplier_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/Supplier\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " - id: id8cc24aecb9282\n", + " label: Product form\n", + " widget: Radio\n", + " required: false\n", + " value: Sheet\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options:\n", + " - key: option1\n", + " label: Sheet\n", + " disabled: false\n", + " - key: option2\n", + " label: Block\n", + " disabled: false\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/emmo#EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_dd4b7d81_28a9_4801_8831_4cbab217e362\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options: null\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/emmo#EMMO_4207e895_8b83_4318_996a_72cfb32acd94\n", + " suffix: slug\n", + " source: material[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: material-type\n", + " relation: https://w3id.org/steel/ProcessOntology/hasMaterialClass_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_39348191_08fd_4bb6_9b1e_012d5b2f1ff6\n", + " - object_location: supplier\n", + " relation: https://w3id.org/steel/ProcessOntology/hasSupplier_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/steel/ProcessOntology/Supplier\n", + " - object_location: product-form\n", + " relation: https://w3id.org/emmo#EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_dd4b7d81_28a9_4801_8831_4cbab217e362\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-09T23:14:18.843010'\n", + " updated_at: '2025-01-17T09:57:57.584798'\n", + "\n", + "ktype:\n", + " id: testingmachine\n", + " name: Testing machine\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: id18d888a9c9fa48\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: ida450e96a27a6e8\n", + " label: Machine\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/Machine\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: testingmachine\n", + " range_options: null\n", + " placeholder: null\n", + " - id: idba8e853b2fdbe\n", + " label: Specimen\n", + " widget: Knowledge item\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit: null\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/pmd/co/Specimen\n", + " relation_mapping_extra: null\n", + " multiple_selection: true\n", + " knowledge_type: specimen\n", + " range_options: null\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: testingmachine[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: machine\n", + " relation: https://w3id.org/steel/ProcessOntology/hasMachine_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: specimen\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTestPiece_Object\n", + " relation_type: object_property\n", + " object_type: anyURI\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-12T17:56:45.095403'\n", + " updated_at: '2025-01-16T15:19:06.989779'\n", + "\n", + "ktype:\n", + " id: specimen\n", + " name: Specimen\n", + " context: false\n", + " context_schema: []\n", + " webform:\n", + " semantics_enabled: true\n", + " sections_enabled: false\n", + " class_mapping:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " sections:\n", + " - id: ida3c5c42685526\n", + " name: Untitled Section\n", + " inputs:\n", + " - id: id175f885f8dda58\n", + " label: Width\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " - id: idef5a37328789f\n", + " label: Length\n", + " widget: Slider\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " relation_mapping_extra:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: true\n", + " placeholder: null\n", + " - id: id54decb9641f9a\n", + " label: Radius\n", + " widget: Number\n", + " required: false\n", + " value: null\n", + " hint: null\n", + " hidden: false\n", + " ignore: false\n", + " select_options: []\n", + " measurement_unit:\n", + " label: Millimetre\n", + " iri: http://qudt.org/vocab/unit/MilliM\n", + " symbol: null\n", + " namespace: http://qudt.org/vocab/unit\n", + " relation_mapping:\n", + " iri: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " type: object_property\n", + " class_iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " relation_mapping_extra: null\n", + " multiple_selection: false\n", + " knowledge_type: null\n", + " range_options:\n", + " min: 0\n", + " max: 1\n", + " step: 0.1\n", + " range: false\n", + " placeholder: null\n", + " hidden: false\n", + " json_schema:\n", + " iri:\n", + " - https://w3id.org/pmd/co/Specimen\n", + " suffix: slug\n", + " source: specimen[*]\n", + " suffix_from_location: true\n", + " custom_relations:\n", + " - object_location: width\n", + " relation: https://w3id.org/steel/ProcessOntology/hasWidth_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_e4de48b1_dabb_4490_ac2b_040f926c64f0\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: length[0]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " suffix: min\n", + " - object_location: length[1]\n", + " relation: https://w3id.org/steel/ProcessOntology/hasTotalLength_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " suffix: max\n", + " iri: https://w3id.org/steel/ProcessOntology/TotalLength\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: radius\n", + " relation: https://w3id.org/steel/ProcessOntology/hasRadius_Object\n", + " relation_type: object_property\n", + " object_type:\n", + " iri: https://w3id.org/emmo#EMMO_32dcd601_47c7_4028_b7fa_5e972ae57f12\n", + " unit: http://qudt.org/vocab/unit/MilliM\n", + " - object_location: Name\n", + " relation: http://www.w3.org/2000/01/rdf-schema#label\n", + " relation_type: annotation_property\n", + " object_data_type: string\n", + " created_at: '2024-12-17T11:00:34.924035'\n", + " updated_at: '2025-01-16T18:25:33.054442'\n", + "\n", + "ktype:\n", + " id: batch\n", + " name: Batches\n", + " context: false\n", + " context_schema: []\n", + " webform: null\n", + " json_schema: null\n", + " created_at: '2025-01-17T11:54:17.493125'\n", + " updated_at: '2025-01-17T11:54:18.373264'\n", + "\n" + ] + } + ], + "source": [ + "for ktype in dsms.ktypes:\n", + " print(ktype)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7.4. Delete KTypes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The fetched ktype can be deleted by applying the `del`-operator to the `dsms` object with the individual `KType` object." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "del dsms[ktype]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As always, commit the changes." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "dsms.commit()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The available KTypes in the SDK can be fetched from an enum list." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/dsms_sdk/tutorials/testfile.txt b/docs/dsms_sdk/tutorials/testfile.txt index 7976166..c81ca04 100755 --- a/docs/dsms_sdk/tutorials/testfile.txt +++ b/docs/dsms_sdk/tutorials/testfile.txt @@ -1 +1 @@ -This is a calibration protocol! +This is a specimen preparation protocol! diff --git a/dsms/__init__.py b/dsms/__init__.py index 1ab4066..24b3344 100644 --- a/dsms/__init__.py +++ b/dsms/__init__.py @@ -2,9 +2,9 @@ from dsms.apps import AppConfig from dsms.core.configuration import Configuration -from dsms.core.context import Context from dsms.core.dsms import DSMS +from dsms.core.session import Session from dsms.knowledge.kitem import KItem from dsms.knowledge.ktype import KType -__all__ = ["DSMS", "Configuration", "Context", "KItem", "KType", "AppConfig"] +__all__ = ["DSMS", "Configuration", "Session", "KItem", "KType", "AppConfig"] diff --git a/dsms/apps/config.py b/dsms/apps/config.py index 946a178..853430d 100644 --- a/dsms/apps/config.py +++ b/dsms/apps/config.py @@ -18,6 +18,7 @@ _get_app_specification, ) +from dsms.knowledge.utils import print_model # isort:skip from dsms.core.logging import handler # isort:skip @@ -27,7 +28,7 @@ logger.propagate = False if TYPE_CHECKING: - from dsms import DSMS, Context + from dsms import DSMS, Session class AppConfig(BaseModel): @@ -76,15 +77,15 @@ def __init__(self, **kwargs: "Any") -> None: # add app config to buffer if ( not self.in_backend - and self.name not in self.context.buffers.created + and self.name not in self.session.buffers.created ): logger.debug( """Marking AppConfig with name `%s` as created and updated during AppConfig initialization.""", self.name, ) - self.context.buffers.created.update({self.name: self}) - self.context.buffers.updated.update({self.name: self}) + self.session.buffers.created.update({self.name: self}) + self.session.buffers.updated.update({self.name: self}) logger.debug("AppConfig initialization successful.") @@ -94,33 +95,16 @@ def __setattr__(self, name, value) -> None: logger.debug( "Setting property with key `%s` on KItem level: %s.", name, value ) - if self.name not in self.context.buffers.updated: + if self.name not in self.session.buffers.updated: logger.debug( "Setting AppConfig with name `%s` as updated during AppConfig.__setattr__", self.name, ) - self.context.buffers.updated.update({self.name: self}) + self.session.buffers.updated.update({self.name: self}) def __str__(self) -> str: - """Pretty print the app config fields""" - fields = ", ".join( - [ - "{key}={value}".format( # pylint: disable=consider-using-f-string - key=key, - value=( - value - if key != "specification" - else { - "metadata": value.get( # pylint: disable=no-member - "metadata" - ) - } - ), - ) - for key, value in self.__dict__.items() - ] - ) - return f"{self.__class__.__name__}({fields})" + """Pretty print the kitem Fields""" + return print_model(self, "app", exclude_extra={"specification"}) def __repr__(self) -> str: """Pretty print the kitem Fields""" @@ -156,20 +140,20 @@ def validate_specification(cls, self: "AppConfig") -> str: raise RuntimeError( f"Invalid yaml specification path: `{error.args[0]}`" ) from error - self.context.buffers.updated.update({self.name: self}) + self.session.buffers.updated.update({self.name: self}) elif isinstance(self.specification, dict) and self.in_backend: spec = _get_app_specification(self.name) if ( not yaml.safe_load(spec) == self.specification - and self.name not in self.context.buffers.updated + and self.name not in self.session.buffers.updated ): - self.context.buffers.updated.update({self.name: self}) + self.session.buffers.updated.update({self.name: self}) elif ( isinstance(self.specification, dict) and not self.in_backend - and self.name not in self.context.buffers.updated + and self.name not in self.session.buffers.updated ): - self.context.buffers.updated.update({self.name: self}) + self.session.buffers.updated.update({self.name: self}) if self.expose_sdk_config: self.specification["spec"]["arguments"]["parameters"] += [ { @@ -190,20 +174,20 @@ def in_backend(self) -> bool: return _app_spec_exists(self.name) @property - def context(cls) -> "Context": - """Getter for Context""" + def session(self) -> "Session": + """Getter for Session""" from dsms import ( # isort:skip - Context, + Session, ) - return Context + return Session @property def dsms(self) -> "DSMS": - """DSMS context getter""" - return self.context.dsms + """DSMS session getter""" + return self.session.dsms @dsms.setter def dsms(self, value: "DSMS") -> None: - """DSMS context setter""" - self.context.dsms = value + """DSMS session setter""" + self.session.dsms = value diff --git a/dsms/core/__init__.py b/dsms/core/__init__.py index 7705c83..ba8493f 100644 --- a/dsms/core/__init__.py +++ b/dsms/core/__init__.py @@ -1,6 +1,6 @@ """DSMS core module """ from dsms.core.configuration import Configuration -from dsms.core.context import Context +from dsms.core.session import Session -__all__ = ["Context", "Configuration"] +__all__ = ["Session", "Configuration"] diff --git a/dsms/core/configuration.py b/dsms/core/configuration.py index 9237366..e74dfda 100644 --- a/dsms/core/configuration.py +++ b/dsms/core/configuration.py @@ -7,11 +7,21 @@ from typing import Callable, Optional, Set, Union import requests -from pydantic import AnyUrl, ConfigDict, Field, SecretStr, field_validator -from pydantic_core.core_schema import ValidationInfo -from pydantic_settings import BaseSettings, SettingsConfigDict -from .utils import get_callable +from pydantic_core.core_schema import ValidationInfo # isort: skip +from pydantic_settings import BaseSettings, SettingsConfigDict # isort: skip + + +from pydantic import ( # isort: skip + AliasChoices, + AnyUrl, + ConfigDict, + Field, + SecretStr, + field_validator, +) + +from .utils import get_callable # isort: skip MODULE_REGEX = r"^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*:[a-zA-Z_][a-zA-Z0-9_]*$" DEFAULT_UNIT_SPARQL = "dsms.knowledge.semantics.units.sparql:UnitSparqlQuery" @@ -44,6 +54,13 @@ class Configuration(BaseSettings): description="Whether the SSL of the DSMS shall be verified during connection.", ) + strict_validation: bool = Field( + True, + description="""Whether the validation of custom properties shall be strict. + Disabling this might be helpful when e.g. the schema of a KType has been changed + and the custom properties are not compatible anymore and should be updated accordingly.""", + ) + username: Optional[SecretStr] = Field( None, description="User name for connecting to the DSMS instance", @@ -121,7 +138,9 @@ class Configuration(BaseSettings): ) loglevel: Optional[Union[Loglevel, str]] = Field( - None, description="Set level of logging messages" + None, + description="Set level of logging messages", + alias=AliasChoices("loglevel", "log_level"), ) model_config = ConfigDict(use_enum_values=True) @@ -146,10 +165,28 @@ def validate_hide_properties(cls, val: Set) -> "Callable": from dsms import KItem for key in val: - if key not in KItem.model_fields: + if key not in KItem.model_fields: # pylint: disable=E1135 raise KeyError(f"Property `{key}` not in KItem schema") return val + @field_validator("strict_validation") + def validate_strictness(cls, val: bool) -> bool: + """ + Validate the strictness of the custom properties validation. + + If strict validation is disabled, custom properties are not validated + against the schema. Instead, the custom properties are allowed to have + any value. + + :param val: If True, use strict validation for custom properties. + :return: The validated value. + """ + if not val: + warnings.warn( + "Strict validation for custom properties is disabled." + ) + return val + @field_validator("token") def validate_auth(cls, val, info: ValidationInfo): """Validate the provided authentication/authorization secrets.""" diff --git a/dsms/core/dsms.py b/dsms/core/dsms.py index 3845509..a9c8f8e 100644 --- a/dsms/core/dsms.py +++ b/dsms/core/dsms.py @@ -1,13 +1,15 @@ """DSMS connection module""" import os +import warnings +from enum import Enum from typing import TYPE_CHECKING, Any, Dict, List from dotenv import load_dotenv from dsms.apps.utils import _get_available_apps_specs from dsms.core.configuration import Configuration -from dsms.core.context import Context +from dsms.core.session import Session from dsms.core.utils import _ping_dsms from dsms.knowledge.sparql_interface import SparqlInterface from dsms.knowledge.utils import _search @@ -20,14 +22,15 @@ ) if TYPE_CHECKING: - from enum import Enum - from typing import Optional + from typing import Optional, Union from dsms.apps import AppConfig - from dsms.core.context import Buffers + from dsms.core.session import Buffers from dsms.knowledge.kitem import KItem from dsms.knowledge.ktype import KType - from dsms.knowledge.search import SearchResult + from dsms.knowledge.search import KItemListModel, SearchResult + +warnings.simplefilter("always", DeprecationWarning) class DSMS: @@ -49,7 +52,7 @@ class DSMS: """ - _context = Context + _session = Session def __init__( self, @@ -72,7 +75,8 @@ def __init__( """ self._config = None - self._context.dsms = self + self._ktypes = None + self._session.dsms = self if env: if not os.path.exists(env): @@ -94,7 +98,7 @@ def __init__( ) self._sparql_interface = SparqlInterface(self) - self._ktypes = _get_remote_ktypes() + self.ktypes = _get_remote_ktypes() def __getitem__(self, key: str) -> "KItem": """Get KItem from remote DSMS instance.""" @@ -111,8 +115,10 @@ def __delitem__(self, obj) -> None: self.context.buffers.deleted.update({obj.id: obj}) elif isinstance(obj, AppConfig): self.context.buffers.deleted.update({obj.name: obj}) - elif isinstance(obj, KType): - raise NotImplementedError("Deletion of KTypes not available yet.") + elif isinstance(obj, KType) or ( + isinstance(obj, Enum) and isinstance(obj.value, KType) + ): + self.context.buffers.deleted.update({obj.name: obj}) else: raise TypeError( f"Object must be of type {KItem}, {AppConfig} or {KType}, not {type(obj)}. " @@ -128,7 +134,7 @@ def commit(self) -> None: def search( self, query: "Optional[str]" = None, - ktypes: "Optional[List[KType]]" = [], + ktypes: "Optional[List[Union[Enum, KType]]]" = [], annotations: "Optional[List[str]]" = [], limit: int = 10, allow_fuzzy: "Optional[bool]" = True, @@ -142,14 +148,23 @@ def sparql_interface(self) -> SparqlInterface: return self._sparql_interface @property - def ktypes(cls) -> "Enum": - """ "Enum of the KTypes defined in the DSMS instance.""" - return cls._ktypes + def ktypes(self) -> "Enum": + """Getter for the Enum of the KTypes defined in the DSMS instance.""" + return self._ktypes + + @ktypes.setter + def ktypes(self, value: "Enum") -> None: + """Setter for the ktypes property of the DSMS instance. + + Args: + value: the Enum object to be set as the ktypes property. + """ + self._ktypes = value @property - def config(cls) -> Configuration: + def config(self) -> Configuration: """Property returning the DSMS Configuration""" - return cls._config + return self._config @config.setter def config(self, value) -> None: @@ -163,27 +178,48 @@ def config(self, value) -> None: verify_connection(self) @property - def headers(cls) -> Dict[str, Any]: + def headers(self) -> Dict[str, Any]: """Request headers for authorization""" - if cls.config.token: + if self.config.token: header = { - "Authorization": f"{cls.config.token.get_secret_value()}" + "Authorization": f"{self.config.token.get_secret_value()}" } else: header = {} return header @property - def kitems(cls) -> "List[KItem]": - """KItems instantiated and available in the remote backend. - WARNING: This will download _all_ KItems in the backend owned - by the current user and may resolve into long response times. - The default timeout for requests is defined under the - `request_timeout`-attribute in the `Configuration`-class.""" + def kitems(self) -> "KItemListModel": + """ + **DEPRECATED** + + Return the first 10 KItems from the remote backend. + + .. warning:: + This property is deprecated and only returns the 10 first kitems. + Please use the `get_kitems`-method instead. + + Returns: + KItemListModel: The first 10 KItems from the remote backend. + """ + message = """`kitems`-property is deprecated and only returns the 10 first kitems. + Please use the `get_kitems`-method instead.""" + warnings.warn(message, DeprecationWarning) return _get_kitem_list() + def get_kitems(self, limit=10, offset=0) -> "KItemListModel": + """ + Get all available KItems from the remote backend. + + Args: + limit (int): The amount of KItems to be returned. Defaults to 10. + offset (int): The offset in the list of KItems. Defaults to 0. + + """ + return _get_kitem_list(limit=limit, offset=offset) + @property - def app_configs(cls) -> "List[AppConfig]": + def app_configs(self) -> "List[AppConfig]": """Return available app configs in the DSMS""" from dsms.apps import AppConfig @@ -193,14 +229,14 @@ def app_configs(cls) -> "List[AppConfig]": ] @property - def buffers(cls) -> "Buffers": + def buffers(self) -> "Buffers": """Return buffers of the DSMS session""" - return cls._context.buffers + return self._session.buffers @property - def context(cls) -> "Context": - """Return DSMS context""" - return cls._context + def context(self) -> "Session": + """Return DSMS session""" + return self._session @classmethod def __get_pydantic_core_schema__(cls): diff --git a/dsms/core/context.py b/dsms/core/session.py similarity index 89% rename from dsms/core/context.py rename to dsms/core/session.py index d206526..13e5f5f 100644 --- a/dsms/core/context.py +++ b/dsms/core/session.py @@ -20,8 +20,8 @@ class Buffers: deleted: "Dict[UUID, KItem]" = {} -class Context: - """Object giving the current DSMS context.""" +class Session: + """Object giving the current DSMS session.""" dsms: "Optional[DSMS]" = None diff --git a/dsms/core/utils.py b/dsms/core/utils.py index d2382cb..9409d26 100644 --- a/dsms/core/utils.py +++ b/dsms/core/utils.py @@ -14,16 +14,16 @@ def _kitem_id2uri(kitem_id: UUID) -> str: "Convert a kitem id in the DSMS to the full resolvable URI" - from dsms import Context + from dsms import Session - return urljoin(str(Context.dsms.config.host_url), str(kitem_id)) + return urljoin(str(Session.dsms.config.host_url), str(kitem_id)) def _uri2kitem_idi(uri: str) -> str: "Extract the kitem id from an URI of the DSMS" - from dsms import Context + from dsms import Session - return uri.replace(f"{Context.dsms.config.host_url}/", "").split("/")[0] + return uri.replace(f"{Session.dsms.config.host_url}/", "").split("/")[0] def _ping_dsms(): @@ -35,9 +35,9 @@ def _perform_request(route: str, method: str, **kwargs: "Any") -> Response: """Perform a general request for a certain route and with a certain method. Kwargs are general arguments which can be passed to the `requests.request`-function. """ - from dsms import Context + from dsms import Session - dsms = Context.dsms + dsms = Session.dsms response = requests.request( method, url=urljoin(str(dsms.config.host_url), route), @@ -46,7 +46,7 @@ def _perform_request(route: str, method: str, **kwargs: "Any") -> Response: verify=dsms.config.ssl_verify, **kwargs, ) - response.encoding = Context.dsms.config.encoding + response.encoding = Session.dsms.config.encoding return response diff --git a/dsms/knowledge/kitem.py b/dsms/knowledge/kitem.py index 39067a5..abf4193 100644 --- a/dsms/knowledge/kitem.py +++ b/dsms/knowledge/kitem.py @@ -1,7 +1,7 @@ """Knowledge Item implementation of the DSMS""" -import json import logging +import warnings from datetime import datetime from enum import Enum from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union @@ -58,12 +58,16 @@ _inspect_dataframe, _make_annotation_schema, _refresh_kitem, + _transform_custom_properties_schema, + print_model, ) from dsms.knowledge.sparql_interface.utils import _get_subgraph # isort:skip +from dsms.knowledge.webform import KItemCustomPropertiesModel # isort:skip + if TYPE_CHECKING: - from dsms import Context + from dsms import Session from dsms.core.dsms import DSMS logger = logging.getLogger(__name__) @@ -116,18 +120,26 @@ class KItem(BaseModel): """ # public - name: str = Field(..., description="Human readable name of the KItem") + name: str = Field( + ..., description="Human readable name of the KItem", max_length=300 + ) id: Optional[UUID] = Field( default_factory=uuid4, description="ID of the KItem", ) ktype_id: Union[Enum, str] = Field(..., description="Type ID of the KItem") + ktype: Optional[Union[Enum, KType]] = Field( + None, description="KType of the KItem", exclude=True + ) in_backend: bool = Field( False, description="Whether the KItem was already created in the backend.", ) slug: Optional[str] = Field( - None, description="Slug of the KContext.dsms", min_length=4 + None, + description="Slug of the KItem", + min_length=4, + max_length=1000, ) annotations: List[Union[str, Annotation]] = Field( [], description="Annotations of the KItem" @@ -175,9 +187,6 @@ class KItem(BaseModel): custom_properties: Optional[Any] = Field( None, description="Custom properties associated to the KItem" ) - ktype: Optional[KType] = Field( - None, description="KType of the KItem", exclude=True - ) dataframe: Optional[ Union[List[Column], pd.DataFrame, Dict[str, Union[List, Dict]]] @@ -192,7 +201,6 @@ class KItem(BaseModel): ) model_config = ConfigDict( - extra="forbid", validate_assignment=True, validate_default=True, exclude={"ktype", "avatar"}, @@ -213,13 +221,13 @@ def __init__(self, **kwargs: "Any") -> None: super().__init__(**kwargs) # add kitem to buffer - if not self.in_backend and self.id not in self.context.buffers.created: + if not self.in_backend and self.id not in self.session.buffers.created: logger.debug( "Marking KItem with ID `%s` as created and updated during KItem initialization.", self.id, ) - self.context.buffers.created.update({self.id: self}) - self.context.buffers.updated.update({self.id: self}) + self.session.buffers.created.update({self.id: self}) + self.session.buffers.updated.update({self.id: self}) self._set_kitem_for_properties() @@ -234,28 +242,20 @@ def __setattr__(self, name, value) -> None: self._set_kitem_for_properties() if ( - self.id not in self.context.buffers.updated + self.id not in self.session.buffers.updated and not name.startswith("_") ): logger.debug( "Setting KItem with ID `%s` as updated during KItem.__setattr__", self.id, ) - self.context.buffers.updated.update({self.id: self}) + self.session.buffers.updated.update({self.id: self}) def __str__(self) -> str: """Pretty print the kitem fields""" - fields = ", \n".join( - [ - f"\n\t{key} = {value}" - for key, value in self.__dict__.items() - if ( - key not in self.model_config["exclude"] - and key not in self.dsms.config.hide_properties - ) - ] + return print_model( + self, "kitem", exclude_extra=self.dsms.config.hide_properties ) - return f"{self.__class__.__name__}(\n{fields}\n)" def __repr__(self) -> str: """Pretty print the kitem Fields""" @@ -411,11 +411,11 @@ def validate_user_groups( @classmethod def validate_created(cls, value: str) -> Any: """Convert the str for `created_at` in to a `datetime`-object""" - from dsms import Context + from dsms import Session if isinstance(value, str): value = datetime.strptime( - value, Context.dsms.config.datetime_format + value, Session.dsms.config.datetime_format ) return value @@ -423,31 +423,61 @@ def validate_created(cls, value: str) -> Any: @classmethod def validate_updated(cls, value: str) -> Any: """Convert the str for `created_at` in to a `datetime`-object""" - from dsms import Context + from dsms import Session if isinstance(value, str): value = datetime.strptime( - value, Context.dsms.config.datetime_format + value, Session.dsms.config.datetime_format ) return value + @field_validator("ktype_id") + @classmethod + def validate_ktype_id(cls, value: Union[str, Enum]) -> KType: + """Validate the ktype id of the KItem""" + from dsms import Session + + if isinstance(value, str): + ktype = Session.ktypes.get(value) + if not ktype: + raise TypeError( + f"KType for `ktype_id={value}` does not exist." + ) + value = ktype + if not hasattr(value, "id"): + raise TypeError( + "Not a valid KType. Provided Enum does not have an `id`." + ) + + return value.id + @field_validator("ktype") @classmethod - def validate_ktype(cls, value: KType, info: ValidationInfo) -> KType: - """Validate the data attribute of the KItem""" - from dsms import Context + def validate_ktype( + cls, value: Optional[Union[KType, Enum]], info: ValidationInfo + ) -> KType: + """Validate the ktype of the KItem""" + from dsms import Session - if not value: - ktype_id = info.data.get("ktype_id") - if not isinstance(ktype_id, str): - value = Context.ktypes.get(ktype_id.value) - else: - value = Context.ktypes.get(ktype_id) + ktype_id = info.data.get("ktype_id") + if not value: + value = Session.ktypes.get(ktype_id) if not value: raise TypeError( f"KType for `ktype_id={ktype_id}` does not exist." ) + if not hasattr(value, "id"): + raise TypeError( + "Not a valid KType. Provided Enum does not have an `id`." + ) + + if value.id != ktype_id: + raise TypeError( + f"KType for `ktype_id={ktype_id}` does not match " + f"the provided `ktype`." + ) + return value @field_validator("in_backend") @@ -463,29 +493,24 @@ def validate_in_backend(cls, value: bool, info: ValidationInfo) -> bool: @classmethod def validate_slug(cls, value: str, info: ValidationInfo) -> str: """Validate slug""" - from dsms import Context + from dsms import Session ktype_id = info.data["ktype_id"] - kitem_id = info.data.get("id") + kitem_id = info.data["id"] + name = info.data["name"] kitem_exists = info.data.get("in_backend") if not isinstance(kitem_exists, bool): kitem_exists = cls.in_backend - if not isinstance(ktype_id, str): - ktype = ktype_id.value - else: - ktype = ktype_id - name = info.data.get("name") - if not value: value = _slugify(name) if len(value) < 4: raise ValueError( "Slug length must have a minimum length of 4." ) - if Context.dsms.config.individual_slugs: + if Session.dsms.config.individual_slugs: value += f"-{str(kitem_id).split('-', maxsplit=1)[0]}" - if not kitem_exists and not _slug_is_available(ktype, value): + if not kitem_exists and not _slug_is_available(ktype_id, value): raise ValueError(f"Slug for `{value}` is already taken.") return value @@ -533,45 +558,53 @@ def validate_dataframe( @model_validator(mode="after") @classmethod - def validate_custom_properties(cls, self) -> "KItem": - """Validate the custom properties with respect to the KType of the KItem""" - if not isinstance( - self.custom_properties, (BaseModel, dict, type(None)) - ): - raise TypeError( - f"""Custom properties must be one of the following types: - {(BaseModel, dict, type(None))}. Not {type(self.custom_properties)}""" - ) - # validate content with webform model - if self.ktype.webform and isinstance(self.custom_properties, dict): - content = ( + def validate_custom_properties(cls, self: "KItem") -> "KItem": + """Validate custom properties""" + + if isinstance(self.custom_properties, dict): + value = ( self.custom_properties.get("content") or self.custom_properties ) - if isinstance(content, str): - try: - content = json.loads(content) - except Exception as error: - raise TypeError( - f"Invalid type: {type(content)}" - ) from error - was_in_buffer = self.id in self.context.buffers.updated - self.custom_properties = self.ktype.webform(**content) - # fix: find a better way to prehebit that properties are - # set in the buffer + + if not value.get("sections"): + value = _transform_custom_properties_schema( + value, self.ktype.webform + ) + warnings.warn( + """A flat dictionary was provided for custom properties. + Will be transformed into `KItemCustomPropertiesModel`.""" + ) + was_in_buffer = self.id in self.session.buffers.updated + self.custom_properties = KItemCustomPropertiesModel( + **value, kitem=self + ) if not was_in_buffer: - self.context.buffers.updated.pop(self.id) - # set kitem id for custom properties - if isinstance(self.custom_properties, BaseModel): - self.custom_properties.kitem = self + self.session.buffers.updated.pop(self.id) + elif not isinstance( + self.custom_properties, (KItemCustomPropertiesModel, type(None)) + ): + raise TypeError( + "Custom properties must be either a dictionary or a " + "KItemCustomPropertiesModel. Not a " + f"{type(self.custom_properties)}: {self.custom_properties}" + ) return self def _set_kitem_for_properties(self) -> None: """Set kitem for CustomProperties and KProperties in order to - remain the context for the buffer if any of these properties is changed. + remain the session for the buffer if any of these properties is changed. """ for prop in self.__dict__.values(): if ( - isinstance(prop, (KItemPropertyList, Summary, Avatar)) + isinstance( + prop, + ( + KItemPropertyList, + Summary, + Avatar, + KItemCustomPropertiesModel, + ), + ) and not prop.kitem ): logger.debug( @@ -582,54 +615,43 @@ def _set_kitem_for_properties(self) -> None: prop.kitem = self @property - def dsms(cls) -> "DSMS": - """DSMS context getter""" - return cls.context.dsms + def dsms(self) -> "DSMS": + """DSMS session getter""" + return self.session.dsms @dsms.setter - def dsms(cls, value: "DSMS") -> None: - """DSMS context setter""" - cls.context.dsms = value + def dsms(self, value: "DSMS") -> None: + """DSMS session setter""" + self.session.dsms = value @property - def subgraph(cls) -> Optional[Graph]: + def subgraph(self) -> Optional[Graph]: """Getter for Subgraph""" return _get_subgraph( - cls.id, cls.dsms.config.kitem_repo, is_kitem_id=True + self.id, self.dsms.config.kitem_repo, is_kitem_id=True ) @property - def context(cls) -> "Context": - """Getter for Context""" + def session(self) -> "Session": + """Getter for Session""" from dsms import ( # isort:skip - Context, + Session, ) - return Context + return Session @property - def url(cls) -> str: + def url(self) -> str: """URL of the KItem""" return urljoin( - str(cls.context.dsms.config.host_url), - f"knowledge/{cls._get_ktype_as_str()}/{cls.slug}", + str(self.session.dsms.config.host_url), + f"knowledge/{self.ktype_id}/{self.slug}", ) def is_a(self, to_be_compared: KType) -> bool: """Check the KType of the KItem""" - return ( - self.ktype_id == to_be_compared.value # pylint: disable=no-member - ) + return self.ktype.id == to_be_compared.id # pylint: disable=no-member def refresh(self) -> None: """Refresh the KItem""" _refresh_kitem(self) - - def _get_ktype_as_str(self) -> str: - if isinstance(self.ktype_id, str): - ktype = self.ktype_id - elif isinstance(self.ktype_id, Enum): - ktype = self.ktype_id.value # pylint: disable=no-member - else: - raise TypeError(f"Datatype for KType is unknown: {type(ktype)}") - return ktype diff --git a/dsms/knowledge/ktype.py b/dsms/knowledge/ktype.py index c1a396e..c4e2f3c 100644 --- a/dsms/knowledge/ktype.py +++ b/dsms/knowledge/ktype.py @@ -1,42 +1,139 @@ """KItem types""" -from typing import Any, Dict, Optional, Union +import logging +from datetime import datetime +from typing import TYPE_CHECKING, Any, Optional, Union from uuid import UUID -from pydantic import BaseModel, Field, field_validator, model_serializer +from pydantic import BaseModel, Field, model_serializer -from dsms.knowledge.utils import _create_custom_properties_model +from dsms.core.logging import handler +from dsms.knowledge.utils import _ktype_exists, _refresh_ktype, print_ktype +from dsms.knowledge.webform import Webform + +if TYPE_CHECKING: + from dsms import Session + from dsms.core.dsms import DSMS + +logger = logging.getLogger(__name__) +logger.addHandler(handler) +logger.propagate = False class KType(BaseModel): """Knowledge type of the knowledge item.""" - id: Union[UUID, str] = Field(..., description="ID of the KType.") + id: Union[UUID, str] = Field( + ..., description="ID of the KType.", max_length=50 + ) name: Optional[str] = Field( - None, description="Human readable name of the KType." + None, description="Human readable name of the KType.", max_length=50 + ) + webform: Optional[Webform] = Field( + None, description="Form data of the KType." ) - webform: Optional[Any] = Field(None, description="Form data of the KItem.") json_schema: Optional[Any] = Field( - None, description="OpenAPI schema of the KItem." + None, description="OpenAPI schema of the KType." + ) + created_at: Optional[Union[str, datetime]] = Field( + None, description="Time and date when the KType was created." + ) + updated_at: Optional[Union[str, datetime]] = Field( + None, description="Time and date when the KType was updated." ) def __hash__(self) -> int: return hash(str(self)) - @field_validator("webform") - @classmethod - def create_model(cls, value: Optional[Dict[str, Any]]) -> Any: - """Create the datamodel for the ktype""" - return _create_custom_properties_model(value) + def __init__(self, **kwargs: "Any") -> None: + """Initialize the KType""" + from dsms import DSMS + + logger.debug("Initialize KType with model data: %s", kwargs) + + # set dsms instance if not already done + if not self.dsms: + self.dsms = DSMS() + + super().__init__(**kwargs) + + # add ktype to buffer + if not self.in_backend and self.id not in self.session.buffers.created: + logger.debug( + "Marking KType with ID `%s` as created and updated during KItem initialization.", + self.id, + ) + self.session.buffers.created.update({self.id: self}) + self.session.buffers.updated.update({self.id: self}) + + logger.debug("KType initialization successful.") + + def __setattr__(self, name, value) -> None: + """Add ktype to updated-buffer if an attribute is set""" + super().__setattr__(name, value) + + if name != "custom_properties": + logger.debug( + "Setting property with key `%s` on KType level: %s.", + name, + value, + ) + + if self.id not in self.session.buffers.updated: + logger.debug( + "Setting KType with ID `%s` as updated during KType.__setattr__", + self.id, + ) + self.session.buffers.updated.update({self.id: self}) + + def __repr__(self) -> str: + """Print the KType""" + return str(self) + + def __str__(self) -> str: + """Print the KType""" + return print_ktype(self) + + @property + def in_backend(self) -> bool: + """Checks whether the KType already exists""" + return _ktype_exists(self) + + @property + def dsms(self) -> "DSMS": + """DSMS session getter""" + return self.session.dsms + + @dsms.setter + def dsms(self, value: "DSMS") -> None: + """DSMS session setter""" + self.session.dsms = value + + @property + def session(self) -> "Session": + """Getter for Session""" + from dsms import ( # isort:skip + Session, + ) + + return Session + + def refresh(self) -> None: + """Refresh the KType""" + _refresh_ktype(self) @model_serializer def serialize(self): """Serialize ktype.""" return { key: ( - value - if not isinstance(value, BaseModel) - else value.model_dump_json() + value.model_dump( # pylint: disable=no-member + exclude_none=False, by_alias=False + ) + if key == "webform" + and value is not None + and not isinstance(value, dict) + else value ) - for key, value in self.items() + for key, value in self.__dict__.items() } diff --git a/dsms/knowledge/properties/__init__.py b/dsms/knowledge/properties/__init__.py index 13b8547..3df0c2a 100644 --- a/dsms/knowledge/properties/__init__.py +++ b/dsms/knowledge/properties/__init__.py @@ -12,7 +12,6 @@ from dsms.knowledge.properties.authors import Author, AuthorsProperty from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList from dsms.knowledge.properties.contacts import ContactInfo, ContactsProperty -from dsms.knowledge.properties.custom_datatype import NumericalDataType from dsms.knowledge.properties.dataframe import Column, DataFrameContainer from dsms.knowledge.properties.summary import Summary from dsms.knowledge.properties.user_groups import UserGroup, UserGroupsProperty @@ -60,5 +59,4 @@ "KItemProperty", "DataFrameContainer", "Column", - "NumericalDataType", ] diff --git a/dsms/knowledge/properties/affiliations.py b/dsms/knowledge/properties/affiliations.py index bb0297c..531bd1b 100644 --- a/dsms/knowledge/properties/affiliations.py +++ b/dsms/knowledge/properties/affiliations.py @@ -6,6 +6,7 @@ from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList from dsms.knowledge.properties.utils import _str_to_dict +from dsms.knowledge.utils import print_model if TYPE_CHECKING: from typing import Callable @@ -14,7 +15,13 @@ class Affiliation(KItemProperty): """Affiliation of a KItem.""" - name: str = Field(..., description="Name of the affiliation") + name: str = Field( + ..., description="Name of the affiliation", max_length=100 + ) + + # OVERRIDE + def __str__(self) -> str: + return print_model(self, "affiliation") class AffiliationsProperty(KItemPropertyList): @@ -22,10 +29,10 @@ class AffiliationsProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return Affiliation @property - def k_property_helper(cls) -> "Callable": + def k_property_helper(self) -> "Callable": """Affiliation property helper""" return _str_to_dict diff --git a/dsms/knowledge/properties/annotations.py b/dsms/knowledge/properties/annotations.py index b3be8f2..90d36fc 100644 --- a/dsms/knowledge/properties/annotations.py +++ b/dsms/knowledge/properties/annotations.py @@ -1,11 +1,11 @@ """Annotation property of a KItem""" -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from pydantic import Field from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList -from dsms.knowledge.utils import _make_annotation_schema +from dsms.knowledge.utils import _make_annotation_schema, print_model if TYPE_CHECKING: from typing import Any, Callable, Dict @@ -14,12 +14,17 @@ class Annotation(KItemProperty): """KItem annotation model""" - iri: str = Field(..., description="IRI of the annotation") - name: str = Field(..., description="Name of the annotation") - namespace: str = Field(..., description="Namespace of the annotation") - description: Optional[str] = Field( - None, description="Description of the annotation" + iri: str = Field(..., description="IRI of the annotation", max_length=200) + label: str = Field( + ..., description="Label of the annotation", max_length=100 ) + namespace: str = Field( + ..., description="Namespace of the annotation", max_length=100 + ) + + # OVERRIDE + def __str__(self) -> str: + return print_model(self, "annotation") class AnnotationsProperty(KItemPropertyList): @@ -27,16 +32,16 @@ class AnnotationsProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": """Annotation data model""" return Annotation @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for Affiliations""" return _make_annotation_schema @property - def by_iri(cls) -> "Dict[str, Any]": + def by_iri(self) -> "Dict[str, Any]": """Return dict of annotations per IRI""" - return {annotation.iri: annotation for annotation in cls} + return {annotation.iri: annotation for annotation in self} diff --git a/dsms/knowledge/properties/apps.py b/dsms/knowledge/properties/apps.py index d0253e1..5a905cb 100644 --- a/dsms/knowledge/properties/apps.py +++ b/dsms/knowledge/properties/apps.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, Field, model_serializer from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList -from dsms.knowledge.utils import _perform_request +from dsms.knowledge.utils import _perform_request, print_model if TYPE_CHECKING: from typing import Callable @@ -24,17 +24,6 @@ class AdditionalProperties(BaseModel): description="File extensions for which the upload shall be triggered.", ) - def __str__(self) -> str: - """Pretty print the KItemPropertyList""" - values = ", ".join( - [f"{key}: {value}" for key, value in self.__dict__.items()] - ) - return f"{{{values}}}" - - def __repr__(self) -> str: - """Pretty print the Apps""" - return str(self) - class JobStatus(BaseModel): """Status of a job""" @@ -64,11 +53,17 @@ class App(KItemProperty): None, description="ID of the KItem App" ) executable: str = Field( - ..., description="Name of the executable related to the app" + ..., + description="Name of the executable related to the app", + max_length=400, + ) + title: str = Field( + ..., description="Title of the appilcation", max_length=50 ) - title: str = Field(..., description="Title of the appilcation") description: Optional[str] = Field( - None, description="Description of the appilcation" + None, + description="Description of the appilcation", + max_length=1000, ) tags: Optional[dict] = Field( None, description="Tags related to the appilcation" @@ -145,6 +140,10 @@ def inputs(self) -> Dict[str, Any]: ) return response.json() + # OVERRIDE + def __str__(self): + return print_model(self, "app") + class Job(BaseModel): """Job running an app""" @@ -193,20 +192,20 @@ class AppsProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": """App data model""" return App @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for Apps""" @property - def by_title(cls) -> Dict[str, App]: + def by_title(self) -> Dict[str, App]: """Get apps by title""" - return {app.title: app for app in cls} + return {app.title: app for app in self} @property - def by_exe(cls) -> Dict[str, App]: + def by_exe(self) -> Dict[str, App]: """Get apps by executable""" - return {app.executable: app for app in cls} + return {app.executable: app for app in self} diff --git a/dsms/knowledge/properties/attachments.py b/dsms/knowledge/properties/attachments.py index 10df1e7..184fae8 100644 --- a/dsms/knowledge/properties/attachments.py +++ b/dsms/knowledge/properties/attachments.py @@ -7,7 +7,7 @@ from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList from dsms.knowledge.properties.utils import _str_to_dict -from dsms.knowledge.utils import _get_attachment +from dsms.knowledge.utils import _get_attachment, print_model if TYPE_CHECKING: from typing import Any, Callable, Dict, Iterable, List @@ -16,10 +16,12 @@ class Attachment(KItemProperty): """Attachment uploaded by a certain user.""" - name: str = Field(..., description="File name of the attachment") + name: str = Field( + ..., description="File name of the attachment", max_length=100 + ) content: Optional[Union[str, bytes]] = Field( - None, description="Content of the file" + None, description="Content of the file", exclude=True ) # OVERRIDE @@ -31,20 +33,7 @@ class Attachment(KItemProperty): # OVERRIDE def __str__(self) -> str: - """Pretty print the Attachment""" - values = ",\n\t\t\t".join( - [ - f"{key}: {value}" - for key, value in self.__dict__.items() - if key not in self.exclude - ] - ) - return f"{{\n\t\t\t{values}\n\t\t}}" - - # OVERRIDE - def __repr__(self) -> str: - """Pretty print the Attachment""" - return str(self) + return print_model(self, "attachment") def download(self, as_bytes: bool = False) -> "Union[str, bytes]": """Download attachment file""" @@ -60,12 +49,12 @@ class AttachmentsProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return Attachment # OVERRIDE @property - def k_property_helper(cls) -> "Callable": + def k_property_helper(self) -> "Callable": """Helper for constructing attachment property""" return _str_to_dict @@ -109,10 +98,10 @@ def insert(self, index: int, item: "Union[Dict, Any]") -> None: super().insert(index, item) @property - def by_name(cls) -> "List[str]": + def by_name(self) -> "List[str]": "Return list of names of attachments" return { Path(attachment.name).stem + Path(attachment.name).suffix: attachment - for attachment in cls + for attachment in self } diff --git a/dsms/knowledge/properties/authors.py b/dsms/knowledge/properties/authors.py index 66738f3..2a8fbf8 100644 --- a/dsms/knowledge/properties/authors.py +++ b/dsms/knowledge/properties/authors.py @@ -6,6 +6,7 @@ from pydantic import Field, model_serializer from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList +from dsms.knowledge.utils import print_model if TYPE_CHECKING: from typing import Callable @@ -14,7 +15,10 @@ class Author(KItemProperty): """Author of a KItem.""" - user_id: UUID = Field(..., description="ID of the DSMS User") + user_id: UUID = Field( + ..., + description="ID of the DSMS User", + ) # OVERRIDE @model_serializer @@ -26,17 +30,21 @@ def serialize_author(self) -> Dict[str, Any]: if key != "id" } + # OVERRIDE + def __str__(self): + return print_model(self, "author") + class AuthorsProperty(KItemPropertyList): """KItemPropertyList for authors""" # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": """Author data model""" return Author # OVERRIDE @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for Authors""" diff --git a/dsms/knowledge/properties/avatar.py b/dsms/knowledge/properties/avatar.py index f2fe1e9..05c40d2 100644 --- a/dsms/knowledge/properties/avatar.py +++ b/dsms/knowledge/properties/avatar.py @@ -6,7 +6,7 @@ from pydantic import ConfigDict, Field from dsms.knowledge.properties.base import KItemProperty -from dsms.knowledge.utils import _get_avatar, _make_avatar +from dsms.knowledge.utils import _get_avatar, _make_avatar, print_model class Avatar(KItemProperty): @@ -31,3 +31,7 @@ def download(self) -> "Image": def generate(self) -> "Image": """Generate avatar as PIL Image""" return _make_avatar(self.kitem, self.file, self.include_qr) + + # OVERRIDE + def __str__(self): + return print_model(self, "avatar") diff --git a/dsms/knowledge/properties/base.py b/dsms/knowledge/properties/base.py index f764ae5..d1e557f 100644 --- a/dsms/knowledge/properties/base.py +++ b/dsms/knowledge/properties/base.py @@ -24,7 +24,7 @@ if TYPE_CHECKING: from typing import Any, Callable, Dict, Iterable, List, Set, Union - from dsms import Context, KItem + from dsms import KItem, Session class KItemProperty(BaseModel): @@ -43,16 +43,9 @@ class KItemProperty(BaseModel): _kitem = PrivateAttr(default=None) + @abstractmethod def __str__(self) -> str: """Pretty print the KItemProperty""" - values = ",\n\t\t\t".join( - [ - f"{key}: {value}" - for key, value in self.__dict__.items() - if key not in self.exclude - ] - ) - return f"{{\n\t\t\t{values}\n\t\t}}" def __repr__(self) -> str: """Pretty print the KItemProperty""" @@ -78,29 +71,34 @@ def __hash__(self) -> int: return hash(str(self)) @property - def kitem(cls) -> "KItem": + def kitem(self) -> "KItem": """KItem related to the KItemProperty""" - return cls._kitem + return self._kitem + + @property + def dsms(self) -> "KItem": + """DSMS instance related to the KItemProperty""" + return self.kitem.dsms @kitem.setter - def kitem(cls, item: "KItem") -> None: + def kitem(self, item: "KItem") -> None: """Set KItem related to the KItemProperty""" - cls._kitem = item - cls.id = item.id + self._kitem = item + self.id = item.id @property - def exclude(cls) -> "Optional[Set[str]]": + def exclude(self) -> "Optional[Set[str]]": """Fields to be excluded from the JSON-schema""" - return cls.model_config.get("exclude") + return self.model_config.get("exclude") @property - def context(cls) -> "Context": - """Getter for Context""" + def context(self) -> "Session": + """Getter for Session""" from dsms import ( # isort:skip - Context, + Session, ) - return Context + return Session @model_serializer def serialize(self): @@ -120,26 +118,15 @@ def __init__(self, *args) -> None: @property @abstractmethod - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": """Return the KItemProperty-class""" @property @abstractmethod - def k_property_helper(cls) -> "Optional[Callable]": + def k_property_helper(self) -> "Optional[Callable]": """Optional helper for transforming a given input into the k property item""" - def __str__(self) -> str: - """Pretty print the KItemPropertyList""" - values = ", \n".join(["\t\t" + repr(value) for value in self]) - if values: - values = f"\n{values}\n\t" - return f"[{values}]" - - def __repr__(self) -> str: - """Pretty print the KItemPropertyList""" - return str(self) - def __hash__(self) -> int: return hash(str(self)) @@ -270,27 +257,27 @@ def _mark_as_updated(self) -> None: self.context.buffers.updated.update({self._kitem.id: self._kitem}) @property - def context(cls) -> "Context": - """Getter for Context""" + def context(self) -> "Session": + """Getter for Session""" from dsms import ( # isort:skip - Context, + Session, ) - return Context + return Session @property - def kitem(cls) -> "KItem": + def kitem(self) -> "KItem": """KItem context of the field""" - return cls._kitem + return self._kitem @kitem.setter - def kitem(cls, value: "KItem") -> None: + def kitem(self, value: "KItem") -> None: """KItem setter""" - cls._kitem = value - for item in cls: - item.kitem = cls.kitem + self._kitem = value + for item in self: + item.kitem = self.kitem @property - def values(cls) -> "List[Dict[str, Any]]": + def values(self) -> "List[Dict[str, Any]]": """Values of the KItemPropertyList""" - return list(cls) + return list(self) diff --git a/dsms/knowledge/properties/contacts.py b/dsms/knowledge/properties/contacts.py index 70353cb..4c96c8e 100644 --- a/dsms/knowledge/properties/contacts.py +++ b/dsms/knowledge/properties/contacts.py @@ -7,6 +7,7 @@ from pydantic import Field from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList +from dsms.knowledge.utils import print_model if TYPE_CHECKING: from typing import Callable @@ -21,16 +22,20 @@ class ContactInfo(KItemProperty): None, description="User ID of the contact person" ) + # OVERRIDE + def __str__(self) -> str: + return print_model(self, "contact") + class ContactsProperty(KItemPropertyList): """KItemPropertyList for contacts""" # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return ContactInfo # OVERRIDE @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for Contacts""" diff --git a/dsms/knowledge/properties/custom_datatype/__init__.py b/dsms/knowledge/properties/custom_datatype/__init__.py deleted file mode 100644 index f53b7d1..0000000 --- a/dsms/knowledge/properties/custom_datatype/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Custom data type module""" - -from .numerical import NumericalDataType - -__all__ = ["NumericalDataType"] diff --git a/dsms/knowledge/properties/custom_datatype/numerical.py b/dsms/knowledge/properties/custom_datatype/numerical.py deleted file mode 100644 index 65c6736..0000000 --- a/dsms/knowledge/properties/custom_datatype/numerical.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Module for custom numerical data type""" - -import logging -from typing import TYPE_CHECKING - -from dsms.knowledge.semantics.units.utils import ( - get_conversion_factor, - get_property_unit, -) - -if TYPE_CHECKING: - from typing import Any, Dict, Optional - - from dsms import KItem - - -logger = logging.Logger(__name__) - - -class NumericalDataType(float): - """Custom Base data type for custom properties""" - - def __init__(self, value) -> None: # pylint: disable=unused-argument - self._kitem: "Optional[KItem]" = None - self._name: "Optional[str]" = None - - def __str__(self) -> str: - """Pretty print the numerical datatype""" - if self.kitem.dsms.config.display_units: - try: - string = f"{self.__float__()} {self.get_unit().get('symbol')}" - except Exception as error: - logger.debug( - "Could not fetch unit from `%i`: %i", self.name, error.args - ) - string = str(self.__float__()) - else: - string = str(self.__float__()) - return string - - def __repr__(self) -> str: - return str(self) - - @property - def kitem(cls) -> "Optional[KItem]": - """Context of the current kitem for this property""" - return cls._kitem - - @kitem.setter - def kitem(cls, value: "Optional[KItem]") -> None: - """Setter for current KItem context""" - cls._kitem = value - - @property - def name(cls) -> str: - """Context of the name for this property""" - return cls._name - - @name.setter - def name(cls, value: str) -> None: - """Setter for the name of the property""" - cls._name = value - - def get_unit(self) -> "Dict[str, Any]": - """Get unit for the property""" - return get_property_unit( - self.kitem.id, - self.name, - is_dataframe_column=True, - autocomplete_symbol=self.kitem.dsms.config.autocomplete_units, - ) - - def convert_to( - self, - unit_symbol_or_iri: str, - decimals: "Optional[int]" = None, - use_input_iri: bool = True, - ) -> float: - """ - Convert the data of property to a different unit. - - Args: - unit_symbol_or_iri (str): Symbol or IRI of the unit to convert to. - decimals (Optional[int]): Number of decimals to round the result to. Defaults to None. - use_input_iri (bool): If True, use IRI for unit comparison. Defaults to False. - - Returns: - float: converted value of the property - """ - unit = self.get_unit() - if use_input_iri: - input_str = unit.get("iri") - else: - input_str = unit.get("symbol") - return self * get_conversion_factor( - input_str, unit_symbol_or_iri, decimals=decimals - ) diff --git a/dsms/knowledge/properties/dataframe.py b/dsms/knowledge/properties/dataframe.py index b994b4a..182eae7 100644 --- a/dsms/knowledge/properties/dataframe.py +++ b/dsms/knowledge/properties/dataframe.py @@ -6,7 +6,7 @@ from pydantic import Field from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList -from dsms.knowledge.utils import _get_dataframe_column, _is_number +from dsms.knowledge.utils import _get_dataframe_column, _is_number, print_model from dsms.knowledge.semantics.units import ( # isort:skip get_conversion_factor, @@ -34,21 +34,8 @@ class Column(KItemProperty): ..., description="Name of the column in the data series." ) - def __repr__(self) -> str: - """Pretty print the numerical datatype""" - if self.kitem and self.kitem.dsms.config.display_units: - try: - unit = f"\tunit={self.get_unit().get('symbol')}\n\t\t" - string = str(self) - string = string[:-1] + unit + string[-1:] - except Exception as error: - logger.debug( - "Could not fetch unit from `%i`: %i", self.name, error.args - ) - string = str(self) - else: - string = str(self) - return string + def __str__(self) -> str: + return print_model(self, "column") def get(self) -> "List[Any]": """ @@ -110,12 +97,12 @@ class DataFrameContainer(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return Column # OVERRIDE @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for DataFrame""" def to_df(self) -> pd.DataFrame: diff --git a/dsms/knowledge/properties/external_links.py b/dsms/knowledge/properties/external_links.py index 937d6a7..64532c3 100644 --- a/dsms/knowledge/properties/external_links.py +++ b/dsms/knowledge/properties/external_links.py @@ -1,10 +1,11 @@ """ExternalLink property of a KItem""" -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Union -from pydantic import AnyUrl, Field +from pydantic import AnyUrl, Field, field_validator from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList +from dsms.knowledge.utils import print_model if TYPE_CHECKING: from typing import Callable @@ -13,8 +14,36 @@ class ExternalLink(KItemProperty): """External link of a KItem.""" - label: str = Field(..., description="Label of the external link") - url: AnyUrl = Field(..., description="URL of the external link") + label: str = Field( + ..., description="Label of the external link", max_length=50 + ) + url: Union[str, AnyUrl] = Field( + ..., description="URL of the external link" + ) + + # OVERRIDE + def __str__(self): + return print_model(self, "external_link") + + @field_validator("url") + @classmethod + def validate_url(cls, value: Union[str, AnyUrl]) -> AnyUrl: + """ + Validate and convert the URL to a string. + + This method is a model validator that runs after the model is initialized. + It ensures that the `url` field of the `ExternalLink` is a string. + If it is not, it attempts to convert it to a string. + + Args: + value (Union[str, AnyUrl]): The value to be validated and converted. + + Returns: + AnyUrl: The validated and potentially modified URL. + """ + if isinstance(value, AnyUrl): + value = str(value) + return value class ExternalLinksProperty(KItemPropertyList): @@ -22,10 +51,10 @@ class ExternalLinksProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return ExternalLink # OVERRIDE @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for External links""" diff --git a/dsms/knowledge/properties/linked_kitems.py b/dsms/knowledge/properties/linked_kitems.py index a64b23c..073e18b 100644 --- a/dsms/knowledge/properties/linked_kitems.py +++ b/dsms/knowledge/properties/linked_kitems.py @@ -26,7 +26,7 @@ from dsms.knowledge.properties.contacts import ContactInfo # isort:skip from dsms.knowledge.properties.external_links import ExternalLink # isort:skip from dsms.knowledge.properties.user_groups import UserGroup # isort:skip -from dsms.knowledge.utils import _get_kitem # isort:skip +from dsms.knowledge.utils import _get_kitem, print_model # isort:skip if TYPE_CHECKING: @@ -50,10 +50,7 @@ class LinkedLinkedKItem(BaseModel): def __str__(self) -> str: """Pretty print the linked KItems of the linked KItem""" - values = ",\n\t\t\t".join( - [f"{key}: {value}" for key, value in self.__dict__.items()] - ) - return f"{{\n\t\t\t{values}\n\t\t}}" + return print_model(self, "linked_kitem") def __repr__(self) -> str: """Pretty print the linked KItems of the linked KItem""" @@ -139,7 +136,7 @@ class LinkedKItem(KItemProperty): _kitem = PrivateAttr(default=None) # OVERRIDE - model_config = ConfigDict(exclude={}, arbitrary_types_allowed=True) + model_config = ConfigDict(arbitrary_types_allowed=True) def fetch(self) -> "KItem": """Fetch the linked KItem""" @@ -147,22 +144,12 @@ def fetch(self) -> "KItem": def is_a(self, to_be_compared: KType) -> bool: """Check the KType of the KItem""" - return ( - self.ktype_id.value # pylint: disable=no-member - == to_be_compared.value - ) + return self.ktype_id == to_be_compared.id # pylint: disable=no-member # OVERRIDE def __str__(self) -> str: """Pretty print the linked KItem""" - values = "\n\t\t\t".join( - [ - f"{key}: {value}" - for key, value in self.__dict__.items() - if key not in self.exclude - ] - ) - return f"\n\t\t\t{values}\n\t\t" + return print_model(self, "linked_kitem") # OVERRIDE def __repr__(self) -> str: @@ -171,15 +158,15 @@ def __repr__(self) -> str: # OVERRIDE @property - def kitem(cls) -> "KItem": + def kitem(self) -> "KItem": """KItem related to the linked KItem""" - return cls._kitem + return self._kitem # OVERRIDE @kitem.setter - def kitem(cls, value: "KItem") -> None: + def kitem(self, value: "KItem") -> None: """Set KItem related to the linked KItem""" - cls._kitem = value + self._kitem = value @field_validator("attachments", mode="before") @classmethod @@ -233,12 +220,12 @@ class LinkedKItemsProperty(KItemPropertyList): # OVERRIDE @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": return LinkedKItem # OVERRIDE @property - def k_property_helper(cls) -> "Callable": + def k_property_helper(self) -> "Callable": """Linked KItem helper function""" return _linked_kitem_helper @@ -263,11 +250,11 @@ def by_annotation(self) -> "Dict[str, List[KItem]]": @property def by_ktype(self) -> "Dict[KType, List[KItem]]": """Get the kitems grouped by ktype""" - from dsms import Context + from dsms import Session grouped = {} for linked in self: - ktype = Context.dsms.ktypes[_name_to_camel(linked.ktype_id)] + ktype = Session.dsms.ktypes[_name_to_camel(linked.ktype_id)] if not ktype in grouped: grouped[ktype] = [] if not linked in grouped[ktype]: diff --git a/dsms/knowledge/properties/summary.py b/dsms/knowledge/properties/summary.py index ae694a0..2c8291c 100644 --- a/dsms/knowledge/properties/summary.py +++ b/dsms/knowledge/properties/summary.py @@ -6,16 +6,21 @@ from pydantic import BaseModel, ConfigDict, Field, model_serializer +from dsms.knowledge.utils import print_model + if TYPE_CHECKING: from typing import Set - from dsms import Context + from dsms import Session class Summary(BaseModel): """Model for the custom properties of the KItem""" - id: Optional[UUID] = Field(None, description="ID of the KItem") + id: Optional[UUID] = Field( + None, + description="ID of the KItem", + ) text: str = Field(..., description="Summary text of the KItem") kitem: Optional[Any] = Field( None, description="KItem related to the summary", exclude=True @@ -30,16 +35,9 @@ def __setattr__(self, name, value) -> None: super().__setattr__(name, value) self._mark_as_updated() - def __str__(self) -> str: - """Pretty print the custom properties""" - fields = ", ".join( - [ - f"{key}={value}" - for key, value in self.__dict__.items() - if key not in self.exclude - ] - ) - return f"{self.__class__.__name__}({fields})" + # OVERIDE + def __str__(self): + return print_model(self, "summary") def __repr__(self) -> str: """Pretty print the custom properties""" @@ -53,25 +51,25 @@ def _mark_as_updated(self) -> None: self.context.buffers.updated.update({self.id: self.kitem}) @property - def id(cls) -> Optional[UUID]: + def id(self) -> Optional[UUID]: """Identifier of the KItem related to the CustomProperies""" - if not cls.kitem: + if not self.kitem: raise ValueError("KItem not defined yet.") - return cls.kitem.id # pylint: disable=E1101 + return self.kitem.id # pylint: disable=E1101 @property - def context(cls) -> "Context": - """Getter for Context""" + def context(self) -> "Session": + """Getter for Session""" from dsms import ( # isort:skip - Context, + Session, ) - return Context + return Session @property - def exclude(cls) -> "Optional[Set[str]]": + def exclude(self) -> "Optional[Set[str]]": """Fields to be excluded from the JSON-schema""" - return cls.model_config.get("exclude") + return self.model_config.get("exclude") @model_serializer def serialize(self) -> str: diff --git a/dsms/knowledge/properties/user_groups.py b/dsms/knowledge/properties/user_groups.py index 4c5fe7a..6a1c154 100644 --- a/dsms/knowledge/properties/user_groups.py +++ b/dsms/knowledge/properties/user_groups.py @@ -5,6 +5,7 @@ from pydantic import Field from dsms.knowledge.properties.base import KItemProperty, KItemPropertyList +from dsms.knowledge.utils import print_model if TYPE_CHECKING: from typing import Callable @@ -13,18 +14,26 @@ class UserGroup(KItemProperty): """Users groups related to a KItem.""" - name: str = Field(..., description="Name of the user group") - group_id: str = Field(..., description="ID of the user group") + name: str = Field( + ..., description="Name of the user group", max_length=100 + ) + group_id: str = Field( + ..., description="ID of the user group", max_length=100 + ) + + # OVERWRITE + def __str__(self): + return print_model(self, "user_group") class UserGroupsProperty(KItemPropertyList): """KItemPropertyList for user_groups""" @property - def k_property_item(cls) -> "Callable": + def k_property_item(self) -> "Callable": """UserGroup data model""" return UserGroup @property - def k_property_helper(cls) -> None: + def k_property_helper(self) -> None: """Not defined for User groups""" diff --git a/dsms/knowledge/search.py b/dsms/knowledge/search.py index 42b1e8d..bbb04c1 100644 --- a/dsms/knowledge/search.py +++ b/dsms/knowledge/search.py @@ -1,19 +1,136 @@ """DSMS search model""" -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Generator, List, Union +import oyaml as yaml from pydantic import BaseModel, Field +from dsms.core.session import Session + if TYPE_CHECKING: from dsms import KItem -class SearchResult(BaseModel): +class KItemSearchResult(BaseModel): """DSMS search result""" - hit: "KItem" = Field(..., description="KItem returned by the search") + kitem: "KItem" = Field(..., description="KItem returned by the search") fuzzy: Union[bool, float] = Field( ..., description="""Whether the KItem was found through a similarity hit. If not a bool, a float indicates the distance from search term""", ) + + def __str__(self): + """Pretty print the KItemSearchResult""" + from dsms.knowledge.utils import dump_model + + return yaml.dump( + { + "kitem": dump_model( + self.kitem, + exclude_extra=Session.dsms.config.hide_properties, + ), + "fuzzy": self.fuzzy, + } + ) + + def __repr__(self): + """Pretty print the KItemSearchResult""" + return str(self) + + +class SearchResult(BaseModel): + """DSMS search result""" + + hits: List[KItemSearchResult] = Field( + ..., description="KItem hits returned by the search" + ) + total_count: int = Field(..., description="Total number of hits") + + def __getitem__(self, key: str) -> "KItemSearchResult": + """Retrieve a KItemSearchResult from the search result by its index. + + Args: + key (str): The index of the KItemSearchResult to retrieve. + + Returns: + KItemSearchResult: The KItemSearchResult at the given index. + """ + return self.hits[key] + + def __iter__(self) -> "Generator[KItemSearchResult]": + """Iterate over the hits in the search result.""" + yield from self.hits + + def __str__(self): + """Pretty print the KItemSearchResult""" + from dsms.knowledge.utils import dump_model + + return yaml.dump( + { + "hits": [ + { + "kitem": dump_model( + hit.kitem, + exclude_extra=Session.dsms.config.hide_properties, + ), + "fuzzy": hit.fuzzy, + } + for hit in self.hits + ], + "total_count": self.total_count, + } + ) + + def __repr__(self): + """Pretty print the KItemSearchResult""" + return str(self) + + +class KItemListModel(BaseModel): + """KItem list model returned by used id""" + + kitems: List["KItem"] = Field( + ..., description="KItems returned when listed by user id" + ) + total_count: int = Field(..., description="Total number of hits") + + def __getitem__(self, key: str) -> "KItem": + """Retrieve a KItem from the list by its index. + + Args: + key (str): The index of the KItem to retrieve. + + Returns: + KItem: The KItem at the given index. + + Raises: + IndexError: If the index is out of range. + """ + return self.kitems[key] + + def __iter__(self) -> "Generator[KItem]": + """Iterate over the KItems in the list.""" + yield from self.kitems + + def __str__(self): + """Pretty print the KItemList""" + from dsms.knowledge.utils import dump_model + + return yaml.dump( + { + "kitems": [ + dump_model( + kitem, + exclude_extra=Session.dsms.config.hide_properties, + ) + for kitem in self.kitems + ], + "total_count": self.total_count, + } + ) + + def __repr__(self): + """Pretty print the KItemList""" + return str(self) diff --git a/dsms/knowledge/semantics/queries/base.py b/dsms/knowledge/semantics/queries/base.py index 37f1b58..735f19b 100644 --- a/dsms/knowledge/semantics/queries/base.py +++ b/dsms/knowledge/semantics/queries/base.py @@ -15,32 +15,32 @@ class BaseSparqlQuery(ABC): """Abstract class for DSMS Sparql Query""" def __init__(self, **kwargs: "Dict[str, Any]") -> None: - from dsms import Context + from dsms import Session self._kwargs = kwargs self._results: "Optional[Dict[str, Any]]" = None - self._dsms: "DSMS" = Context.dsms + self._dsms: "DSMS" = Session.dsms self.execute() @property - def kwargs(cls) -> "Dict[str, Any]": + def kwargs(self) -> "Dict[str, Any]": """Return kwargs passed during initialization""" - return cls._kwargs + return self._kwargs @property - def dsms(cls) -> "Dict[str, Any]": + def dsms(self) -> "Dict[str, Any]": """Return dsms context""" - return cls._dsms + return self._dsms @property - def results(cls) -> "Optional[Dict[str, Any]]": + def results(self) -> "Optional[Dict[str, Any]]": """Return query results""" - return cls._results + return self._results @property @abstractmethod - def result_mappings(cls) -> "Dict[str, Any]": + def result_mappings(self) -> "Dict[str, Any]": """ Define a mapping between the output keys and the output datatype. E.g. {'foo': int, 'bar': str, 'foobar': MyCustomClass} @@ -48,13 +48,13 @@ def result_mappings(cls) -> "Dict[str, Any]": @property @abstractmethod - def query(cls) -> str: + def query(self) -> str: """ Define sparql query by using the kwargs defined during initialization. """ @abstractmethod - def postprocess_result(cls, row: "Dict[str, Any]") -> "Dict[str, Any]": + def postprocess_result(self, row: "Dict[str, Any]") -> "Dict[str, Any]": """ Define a function that postprocesses the result of the indivudal row in the sparql result. This might e.g. be some string operations etc. diff --git a/dsms/knowledge/semantics/units/base.py b/dsms/knowledge/semantics/units/base.py index cbc76c2..349d1be 100644 --- a/dsms/knowledge/semantics/units/base.py +++ b/dsms/knowledge/semantics/units/base.py @@ -32,6 +32,6 @@ def __init__( # OVERRIDE @property - def result_mappings(cls) -> "Dict[str, Any]": + def result_mappings(self) -> "Dict[str, Any]": """Define mappings for the results of the units sparql queries""" return {"symbol": str, "iri": str} diff --git a/dsms/knowledge/semantics/units/conversion.py b/dsms/knowledge/semantics/units/conversion.py index f6f0e98..9373699 100644 --- a/dsms/knowledge/semantics/units/conversion.py +++ b/dsms/knowledge/semantics/units/conversion.py @@ -119,13 +119,13 @@ def _get_factor_from_uri(uri: str) -> int: @lru_cache def _get_qudt_graph(ontology_ref: str) -> Graph: - from dsms import Context + from dsms import Session - url = getattr(Context.dsms.config, ontology_ref) - encoding = Context.dsms.config.encoding + url = getattr(Session.dsms.config, ontology_ref) + encoding = Session.dsms.config.encoding graph = Graph() - response = requests.get(url, timeout=Context.dsms.config.request_timeout) + response = requests.get(url, timeout=Session.dsms.config.request_timeout) if response.status_code != 200: raise RuntimeError( f"Could not download QUDT ontology. Please check URI: {url}" diff --git a/dsms/knowledge/semantics/units/sparql.py b/dsms/knowledge/semantics/units/sparql.py index a35056a..2f1fabe 100644 --- a/dsms/knowledge/semantics/units/sparql.py +++ b/dsms/knowledge/semantics/units/sparql.py @@ -18,15 +18,15 @@ class UnitSparqlQuery(BaseUnitSparqlQuery): # OVERRIDE @property - def query(cls) -> str: + def query(self) -> str: """Construct sparql query for getting unit for dataframe column""" - kitem_id = cls.kwargs.get("kitem_id") - property_name = cls.kwargs.get("property_name") + kitem_id = self.kwargs.get("kitem_id") + property_name = self.kwargs.get("property_name") if not kitem_id: raise ValueError("KItem ID must be defined.") if not property_name: raise ValueError("Property name must be defined.") - url = urljoin(str(cls.dsms.config.host_url), str(kitem_id)) + url = urljoin(str(self.dsms.config.host_url), str(kitem_id)) return f"""prefix csvw: prefix dcat: @@ -46,13 +46,13 @@ def query(cls) -> str: }}""" # OVERRIDE - def postprocess_result(cls, row: "Dict[str, Any]") -> "Dict[str, Any]": + def postprocess_result(self, row: "Dict[str, Any]") -> "Dict[str, Any]": """ Define a function that postprocesses the result of the indivudal row in the sparql result. This might e.g. be some string operations etc. """ if row.get("symbol") == "None": row["symbol"] = None - if cls.kwargs.get("autocomplete_symbol") and not row.get("symbol"): + if self.kwargs.get("autocomplete_symbol") and not row.get("symbol"): row["symbol"] = _get_symbol_from_uri(row.get("iri")) return row diff --git a/dsms/knowledge/semantics/units/utils.py b/dsms/knowledge/semantics/units/utils.py index 6870cca..fdef380 100644 --- a/dsms/knowledge/semantics/units/utils.py +++ b/dsms/knowledge/semantics/units/utils.py @@ -68,56 +68,63 @@ def get_conversion_factor( def get_property_unit( kitem_id: "Union[str, UUID]", property_name: str, + measurement_unit: "Optional[Any]" = None, is_dataframe_column: bool = False, autocomplete_symbol: bool = True, ) -> "Dict[str, Any]": """ - Retrieve the unit associated with a given property of a KIitem. + Get unit for a given property name. + + This function queries the unit for a given property name with respect to the + semantics applied. If `measurement_unit` is not `None`, it will be returned + as is. If `measurement_unit` is `None`, the function will try to get the unit + from the QUDT-based semantics. If no unit is found, a `ValueError` is raised. Args: - kitem (KItem): The identifier of the KItem. - property_name (str): The name of the property of the KItem for which - the unit is to be retrieved. - is_dataframe_column (bool, optional): Indicates whether the property is an DataFrame - column or a custom property. Defaults to False. - autocomplete_symbol (bool, optional): Whether the symbol of a unit shall be - fetched automatically from the ontology when it is not given next to the - URI. + kitem_id (Union[str, UUID]): ID of the KItem. + property_name (str): Name of the property. + measurement_unit (Optional[Any], optional): Measurement unit. Defaults to None. + is_dataframe_column (bool, optional): Whether the property is a dataframe column. + Defaults to False. + autocomplete_symbol (bool, optional): Whether to autocomplete the unit symbol. + Defaults to True. Returns: - Dict[str, Any]: A dictionary with the symbol and iri of the unit associated - with the specified property. + Dict[str, Any]: The unit as a dictionary. Raises: - ValueError: If unable to retrieve the unit for the property due to any errors or if - the property does not have a unit or has more than one unit associated with it. + ValueError: If no unit is found. """ - from dsms import Context - - units_sparql_object = Context.dsms.config.units_sparql_object - if not issubclass(units_sparql_object, BaseUnitSparqlQuery): - raise TypeError( - f"´{units_sparql_object}´ must be a subclass of `{BaseUnitSparqlQuery}`" - ) - try: - query = units_sparql_object( - kitem_id=kitem_id, - property_name=property_name, - is_dataframe_column=is_dataframe_column, - autocomplete_symbol=autocomplete_symbol, - ) - except Exception as error: - raise ValueError( - f"Something went wrong catching the unit for property `{property_name}`." - ) from error - if len(query.results) == 0: - raise ValueError( - f"""Property `{property_name}` does not own any - unit with respect to the semantics applied.""" - ) - if len(query.results) > 1: - raise ValueError( - f"""Property `{property_name}` owns more than one - unit with respect to the semantics applied.""" - ) - return query.results.pop() + from dsms import Session + + if not measurement_unit: + units_sparql_object = Session.dsms.config.units_sparql_object + if not issubclass(units_sparql_object, BaseUnitSparqlQuery): + raise TypeError( + f"´{units_sparql_object}´ must be a subclass of `{BaseUnitSparqlQuery}`" + ) + try: + query = units_sparql_object( + kitem_id=kitem_id, + property_name=property_name, + is_dataframe_column=is_dataframe_column, + autocomplete_symbol=autocomplete_symbol, + ) + except Exception as error: + raise ValueError( + f"Something went wrong catching the unit for property `{property_name}`." + ) from error + if len(query.results) == 0: + raise ValueError( + f"""Property `{property_name}` does not own any + unit with respect to the semantics applied.""" + ) + if len(query.results) > 1: + raise ValueError( + f"""Property `{property_name}` owns more than one + unit with respect to the semantics applied.""" + ) + unit = query.results.pop() + else: + unit = measurement_unit.model_dump() + return unit diff --git a/dsms/knowledge/sparql_interface/sparql_interface.py b/dsms/knowledge/sparql_interface/sparql_interface.py index 118c31d..6651596 100644 --- a/dsms/knowledge/sparql_interface/sparql_interface.py +++ b/dsms/knowledge/sparql_interface/sparql_interface.py @@ -50,6 +50,6 @@ def insert( _add_rdf(file_or_pathlike, self._dsms.config.encoding, repository) @property - def subgraph(cls) -> Subgraph: + def subgraph(self) -> Subgraph: """Subgraph interface for DSMS""" - return cls._subgraph + return self._subgraph diff --git a/dsms/knowledge/utils.py b/dsms/knowledge/utils.py index 277528e..5fbdf3d 100644 --- a/dsms/knowledge/utils.py +++ b/dsms/knowledge/utils.py @@ -2,40 +2,30 @@ import base64 import io import logging +import random import re -import warnings +import string +import time from enum import Enum from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union from uuid import UUID +import oyaml as yaml import pandas as pd import segno -import yaml from PIL import Image from requests import Response -from pydantic import ( # isort: skip - BaseModel, - ConfigDict, - Field, - create_model, - model_validator, -) - from dsms.core.logging import handler # isort:skip from dsms.core.utils import _name_to_camel, _perform_request # isort:skip -from dsms.knowledge.properties.custom_datatype import ( # isort:skip - NumericalDataType, -) - -from dsms.knowledge.search import SearchResult # isort:skip +from dsms.knowledge.search import SearchResult, KItemListModel # isort:skip if TYPE_CHECKING: from dsms.apps import AppConfig - from dsms.core.context import Buffers + from dsms.core.session import Buffers from dsms.knowledge import KItem, KType from dsms.knowledge.properties import Attachment @@ -52,129 +42,47 @@ def _is_number(value): return False -def _create_custom_properties_model( - value: Optional[Dict[str, Any]] -) -> BaseModel: - """Convert the dict with the model schema into a pydantic model.""" - from dsms import KItem +def print_model(self, key, exclude_extra: set = set()) -> str: + """Pretty print the ktype fields""" + dumped = dump_model(self, exclude_extra) + return yaml.dump({key: dumped}) - fields = {} - if isinstance(value, dict): - for item in value.get("sections"): - for form_input in item.get("inputs"): - label = form_input.get("label") - dtype = form_input.get("widget") - default = form_input.get("defaultValue") - slug = _slugify(label) - if dtype in ("Text", "File", "Textarea", "Vocabulary term"): - dtype = Optional[str] - elif dtype in ("Number", "Slider"): - dtype = Optional[NumericalDataType] - elif dtype == "Checkbox": - dtype = Optional[bool] - elif dtype in ("Select", "Radio"): - choices = Enum( - _name_to_camel(label) + "Choices", - { - _name_to_camel(choice["value"]): choice["value"] - for choice in form_input.get("choices") - }, - ) - dtype = Optional[choices] - elif dtype == "Knowledge item": - warnings.warn( - "knowledge item not fully supported for KTypes yet." - ) - dtype = Optional[str] - - fields[slug] = (dtype, default or None) - fields["kitem"] = ( - Optional[KItem], - Field(None, exclude=True), - ) - config = ConfigDict( - extra="allow", arbitrary_types_allowed=True, exclude={"kitem"} +def dump_model(self, exclude_extra: set = set()) -> Dict[str, Any]: + """ + Dump the model fields into a dictionary format with optional exclusions. + + This method converts the model's fields into a dictionary while allowing + specific fields to be excluded. UUID fields are converted to string + representation. + + Args: + exclude_extra (set): Additional fields to exclude from the dump. + + Returns: + Dict[str, Any]: A dictionary of the model fields with specified exclusions. + """ + exclude = self.model_config.get("exclude", set()) | exclude_extra + dumped = self.model_dump( + exclude_none=True, + exclude_unset=True, + exclude=exclude, ) - validators = { - "validate_model": model_validator(mode="before")(_validate_model) + return { + key: (str(value) if isinstance(value, UUID) else value) + for key, value in dumped.items() } - model = create_model( - "CustomPropertiesModel", - __config__=config, - __validators__=validators, - **fields, - ) - setattr(model, "__str__", _print_properties) - setattr(model, "__repr__", _print_properties) - setattr(model, "__setattr__", __setattr_property__) - logger.debug("Create custom properties model with fields: %s", fields) - return model - - -def _print_properties(self: Any) -> str: - fields = ", \n".join( - [ - f"\t\t{key}: {value}" - for key, value in self.model_dump().items() - if key not in self.model_config["exclude"] - ] - ) - return f"{{\n{fields}\n\t}}" -def __setattr_property__(self, key, value) -> None: - logger.debug( - "Setting property for custom property with key `%s` with value `%s`.", - key, - value, - ) - if _is_number(value): - # convert to convertable numeric object - value = _create_numerical_dtype(key, value, self.kitem) - # mark as updated - if key != "kitem" and self.kitem: - logger.debug( - "Setting related kitem for custom properties with id `%s` as updated", - self.kitem.id, - ) - self.kitem.context.buffers.updated.update({self.kitem.id: self.kitem}) - elif key == "kitem": - # set kitem for convertable numeric datatype - for prop in self.model_dump().values(): - if isinstance(prop, NumericalDataType) and not prop.kitem: - prop.kitem = value - # reassignment of extra fields does not work, seems to be a bug? - # have this workaround: - if key in self.__pydantic_extra__: - self.__pydantic_extra__[key] = value - super(BaseModel, self).__setattr__(key, value) - - -def _create_numerical_dtype( - key: str, value: Union[int, float], kitem: "KItem" -) -> NumericalDataType: - value = NumericalDataType(value) - value.name = key - value.kitem = kitem - return value - - -def _validate_model( - cls, values: Dict[str, Any] # pylint: disable=unused-argument -) -> Dict[str, Any]: - for key, value in values.items(): - if _is_number(value): - values[key] = _create_numerical_dtype( - key, value, values.get("kitem") - ) - return values +def print_ktype(self) -> str: + """Pretty print the ktype fields""" + return print_model(self, "ktype") def _get_remote_ktypes() -> Enum: """Get the KTypes from the remote backend""" from dsms import ( # isort:skip - Context, + Session, KType, ) @@ -184,27 +92,160 @@ def _get_remote_ktypes() -> Enum: f"Something went wrong fetching the remote ktypes: {response.text}" ) - Context.ktypes = {ktype["id"]: KType(**ktype) for ktype in response.json()} + Session.ktypes = {ktype["id"]: KType(**ktype) for ktype in response.json()} ktypes = Enum( - "KTypes", {_name_to_camel(key): key for key in Context.ktypes} + "KTypes", + {_name_to_camel(key): value for key, value in Session.ktypes.items()}, ) + + def custom_getattr(self, name) -> None: + """ + Custom getattr method for the Enum of KTypes. + + When a KType field is accessed, first check if the field is an attribute of the + underlying KType object (self.value). If it is, return that. + Otherwise, call the super method to access the Enum field. + + This is needed because the Enum object is not a KType object, but has all the same + fields. This allows us to access the fields of the KType object as if it were an + Enum. + """ + if hasattr(self.value, name): + return getattr(self.value, name) + return super(ktypes, self).__getattr__(name) + + def custom_setattr(self, name, value) -> None: + """ + Custom setattr method for the Enum of KTypes. + + When a KType field is set, first check if the field is an attribute of the + underlying KType object (self.value). If it is, set that. + Otherwise, call the super method to set the Enum field. + + This is needed because the Enum object is not a KType object, but has all the same + fields. This allows us to set the fields of the KType object as if it were an + Enum. + """ + + if hasattr(self.value, name): + setattr(self.value, name, value) + else: + super(ktypes, self).__setattr__(name, value) + + # Attach methods to the dynamically created Enum class + setattr(ktypes, "__getattr__", custom_getattr) + setattr(ktypes, "__setattr__", custom_setattr) + setattr(ktypes, "__str__", print_ktype) + setattr(ktypes, "__repr__", print_ktype) + logger.debug("Got the following ktypes from backend: `%s`.", list(ktypes)) return ktypes -def _get_kitem_list() -> "List[KItem]": - """Get all available KItems from the remote backend.""" - from dsms.knowledge.kitem import ( # isort:skip - KItem, +def _ktype_exists(ktype: Union[Any, str, UUID]) -> bool: + """Check whether the KType exists in the remote backend""" + from dsms.knowledge.ktype import ( # isort:skip + KType, + ) + + if isinstance(ktype, KType): + route = f"api/knowledge-type/{ktype.id}" + else: + route = f"api/knowledge-type/{ktype}" + response = _perform_request(route, "get") + return response.ok + + +def _create_new_ktype(ktype: "KType") -> None: + """Create a new KType in the remote backend""" + body = { + "name": ktype.name, + "id": str(ktype.id), + } + logger.debug("Create new KType with body: %s", body) + response = _perform_request("api/knowledge-type/", "post", json=body) + if not response.ok: + raise ValueError( + f"KType with id `{ktype.id}` could not be created in DSMS: {response.text}`" + ) + + +def _get_ktype(ktype_id: str, as_json=False) -> "Union[KType, Dict[str, Any]]": + """Get the KType for an instance with a certain ID from remote backend""" + from dsms import KType, Session + + response = _perform_request(f"api/knowledge-type/{ktype_id}", "get") + if response.status_code == 404: + raise ValueError( + f"""KType with the id `{ktype_id}` does not exist in + DSMS-instance `{Session.dsms.config.host_url}`""" + ) + if not response.ok: + raise ValueError( + f"""An error occured fetching the KType with id `{ktype_id}`: + `{response.text}`""" + ) + body = response.json() + if as_json: + response = body + else: + response = KType(**body) + return response + + +def _update_ktype(ktype: "KType") -> Response: + """Update a KType in the remote backend.""" + payload = ktype.model_dump( + exclude_none=True, + by_alias=True, ) + logger.debug("Update KType for `%s` with body: %s", ktype.id, payload) + response = _perform_request( + f"api/knowledge-type/{ktype.id}", "put", json=payload + ) + if not response.ok: + raise ValueError( + f"KType with uuid `{ktype.id}` could not be updated in DSMS: {response.text}`" + ) + return response + - response = _perform_request("api/knowledge/kitems", "get") +def _delete_ktype(ktype: "KType") -> None: + """Delete a KType in the remote backend""" + from dsms import Session + + logger.debug("Delete KType with id: %s", ktype.id) + response = _perform_request(f"api/knowledge-type/{ktype.id}", "delete") + if not response.ok: + raise ValueError( + f"KItem with uuid `{ktype.id}` could not be deleted from DSMS: `{response.text}`" + ) + Session.dsms.ktypes = _get_remote_ktypes() + + +def _get_kitem_list(limit=10, offset=0) -> "KItemListModel": + """Get all available KItems from the remote backend.""" + from dsms.knowledge.kitem import KItem # isort:skip + + response = _perform_request( + "api/knowledge/kitems", + "get", + params={ + "limit": limit, + "offset": offset, + }, + ) if not response.ok: raise ValueError( f"Something went wrong fetching the available kitems: {response.text}" ) - return [KItem(**kitem) for kitem in response.json()] + payload = response.json() + kitems = { + "kitems": [KItem(**kitem) for kitem in payload["kitems"]], + "total_count": payload["total_count"], + } + return KItemListModel(**kitems) def _kitem_exists(kitem: Union[Any, str, UUID]) -> bool: @@ -225,13 +266,13 @@ def _get_kitem( uuid: Union[str, UUID], as_json=False ) -> "Union[KItem, Dict[str, Any]]": """Get the KItem for a instance with a certain ID from remote backend""" - from dsms import Context, KItem + from dsms import KItem, Session response = _perform_request(f"api/knowledge/kitems/{uuid}", "get") if response.status_code == 404: raise ValueError( f"""KItem with uuid `{uuid}` does not exist in - DSMS-instance `{Context.dsms.config.host_url}`""" + DSMS-instance `{Session.dsms.config.host_url}`""" ) if not response.ok: raise ValueError( @@ -284,6 +325,7 @@ def _update_kitem(new_kitem: "KItem", old_kitem: "Dict[str, Any]") -> Response: "created_at", "external_links", "dataframe", + "access_url", }, exclude_none=True, ) @@ -294,15 +336,9 @@ def _update_kitem(new_kitem: "KItem", old_kitem: "Dict[str, Any]") -> Response: **differences, ) if new_kitem.custom_properties: - custom_properties = new_kitem.custom_properties.model_dump() - # # a smarted detection whether the custom properties were updated is needed - # old_properties = old_kitem.get("custom_properties") - # if isinstance(old_properties, dict): - # old_custom_properties = old_properties.get("content") - # else: - # old_custom_properties = None - # if custom_properties != old_custom_properties: - # payload.update(custom_properties={"content": custom_properties}) + custom_properties = new_kitem.custom_properties.model_dump( + by_alias=True + ) payload.update(custom_properties={"content": custom_properties}) logger.debug( "Update KItem for `%s` with payload: %s", new_kitem.id, payload @@ -533,9 +569,7 @@ def _commit_created( elif isinstance(obj, AppConfig): _create_or_update_app_spec(obj) elif isinstance(obj, KType): - raise NotImplementedError( - "Committing of KTypes not implemented yet." - ) + _create_new_ktype(obj) else: raise TypeError( f"Object `{obj}` of type {type(obj)} cannot be committed." @@ -554,9 +588,7 @@ def _commit_updated( elif isinstance(obj, AppConfig): _create_or_update_app_spec(obj, overwrite=True) elif isinstance(obj, KType): - raise NotImplementedError( - "Committing of KTypes not implemented yet." - ) + _commit_updated_ktype(obj) else: raise TypeError( f"Object `{obj}` of type {type(obj)} cannot be committed." @@ -593,6 +625,25 @@ def _commit_updated_kitem(new_kitem: "KItem") -> None: new_kitem.refresh() +def _commit_updated_ktype(new_ktype: "KType") -> None: + """Commit the updated KTypes""" + from dsms import Session + + old_ktype = _get_ktype(new_ktype.id, as_json=True) + logger.debug( + "Fetched data from old KType with id `%s`: %s", + new_ktype.id, + old_ktype, + ) + if old_ktype: + _update_ktype(new_ktype) + logger.debug( + "Fetching updated KType from remote backend: %s", new_ktype.id + ) + new_ktype.refresh() + Session.dsms.ktypes = _get_remote_ktypes() + + def _commit_deleted( buffer: "Dict[str, Union[KItem, KType, AppConfig]]", ) -> None: @@ -605,10 +656,10 @@ def _commit_deleted( _delete_kitem(obj) elif isinstance(obj, AppConfig): _delete_app_spec(obj.name) - elif isinstance(obj, KType): - raise NotImplementedError( - "Deletion of KTypes not implemented yet." - ) + elif isinstance(obj, KType) or ( + isinstance(obj, Enum) and isinstance(obj.value, KType) + ): + _delete_ktype(obj) else: raise TypeError( f"Object `{obj}` of type {type(obj)} cannot be committed or deleted." @@ -628,6 +679,18 @@ def _refresh_kitem(kitem: "KItem") -> None: kitem.dataframe = _inspect_dataframe(kitem.id) +def _refresh_ktype(ktype: "KType") -> None: + """Refresh the KItem""" + for key, value in _get_ktype(ktype.id, as_json=True).items(): + logger.debug( + "Set updated property `%s` for KType with id `%s` after commiting: %s", + key, + ktype.id, + value, + ) + setattr(ktype, key, value) + + def _split_iri(iri: str) -> List[str]: if "#" in iri: namspace, name = iri.rsplit("#", 1) @@ -637,15 +700,16 @@ def _split_iri(iri: str) -> List[str]: def _make_annotation_schema(iri: str) -> Dict[str, Any]: - namespace, name = _split_iri(iri) - return {"namespace": namespace, "name": name, "iri": iri} + namespace, label = _split_iri(iri) + return {"namespace": namespace, "label": label, "iri": iri} def _search( query: Optional[str] = None, - ktypes: "Optional[List[KType]]" = [], + ktypes: "Optional[List[Union[Enum, KType]]]" = [], annotations: "Optional[List[str]]" = [], limit: "Optional[int]" = 10, + offset: "Optional[int]" = 0, allow_fuzzy: "Optional[bool]" = True, ) -> "List[SearchResult]": """Search for KItems in the remote backend""" @@ -653,9 +717,10 @@ def _search( payload = { "search_term": query or "", - "ktypes": [ktype.value for ktype in ktypes], + "ktypes": [ktype.value.id for ktype in ktypes], "annotations": [_make_annotation_schema(iri) for iri in annotations], "limit": limit, + "offset": offset, } response = _perform_request( "api/knowledge/kitems/search", @@ -673,10 +738,13 @@ def _search( raise RuntimeError( f"""Something went wrong while searching for KItems: {response.text}""" ) from excep - return [ - SearchResult(hit=KItem(**item.get("hit")), fuzzy=item.get("fuzzy")) - for item in dumped - ] + return SearchResult( + hits=[ + {"kitem": KItem(**item.get("kitem")), "fuzzy": item.get("fuzzy")} + for item in dumped.get("hits") + ], + total_count=dumped.get("total_count"), + ) def _slugify(input_string: str, replacement: str = ""): @@ -689,7 +757,7 @@ def _slugify(input_string: str, replacement: str = ""): return slug -def _slug_is_available(ktype_id: Union[str, UUID], value: str) -> bool: +def _slug_is_available(ktype_id: str, value: str) -> bool: """Check whether the id of a KItem is available in the DSMS or not""" response = _perform_request( f"api/knowledge/kitems/{ktype_id}/{value}", "head" @@ -703,7 +771,7 @@ def _get_dataframe_column(kitem_id: str, column_id: int) -> List[Any]: """Download the column of a dataframe container of a certain kitem""" response = _perform_request( - f"api/knowledge/data_api/{kitem_id}/column-{column_id}", "get" + f"api/knowledge/data/{kitem_id}/column-{column_id}", "get" ) if not response.ok: message = f"""Something went wrong fetch column id `{column_id}` @@ -714,7 +782,7 @@ def _get_dataframe_column(kitem_id: str, column_id: int) -> List[Any]: def _inspect_dataframe(kitem_id: str) -> Optional[List[Dict[str, Any]]]: """Get column info for the dataframe container of a certain kitem""" - response = _perform_request(f"api/knowledge/data_api/{kitem_id}", "get") + response = _perform_request(f"api/knowledge/data/{kitem_id}", "get") if not response.ok and response.status_code == 404: dataframe = None elif not response.ok and response.status_code != 404: @@ -734,7 +802,7 @@ def _update_dataframe(kitem_id: str, data: pd.DataFrame): data.to_json(buffer, indent=2) buffer.seek(0) response = _perform_request( - f"api/knowledge/data_api/{kitem_id}", "put", files={"data": buffer} + f"api/knowledge/data/{kitem_id}", "put", files={"data": buffer} ) if not response.ok: raise RuntimeError( @@ -744,7 +812,7 @@ def _update_dataframe(kitem_id: str, data: pd.DataFrame): def _delete_dataframe(kitem_id: str) -> Response: logger.debug("Delete DataFrame for kitem with id `%s`.", kitem_id) - return _perform_request(f"api/knowledge/data_api/{kitem_id}", "delete") + return _perform_request(f"api/knowledge/data/{kitem_id}", "delete") def _commit_avatar(kitem) -> None: @@ -843,3 +911,170 @@ def _delete_app_spec(name: str) -> None: message = f"Something went wrong deleting app spec with name `{name}`: {response.text}" raise RuntimeError(message) return response.text + + +def _transform_custom_properties_schema(custom_properties: Any, webform: Any): + if webform: + copy_properties = custom_properties.copy() + transformed_sections = {} + for section_def in webform.sections: + for input_def in section_def.inputs: + if input_def.label in copy_properties: + if input_def.measurement_unit: + measurement_unit = ( + input_def.measurement_unit.model_dump() + ) + else: + measurement_unit = None + entry = { + "id": input_def.id, + "label": input_def.label, + "value": copy_properties.pop(input_def.label), + "measurement_unit": measurement_unit, + "type": input_def.widget, + } + section_name = section_def.name + if section_name not in transformed_sections: + section = { + "id": section_def.id, + "name": section_name, + "entries": [], + } + transformed_sections[section_name] = section + transformed_sections[section_name]["entries"].append(entry) + if copy_properties: + logger.info( + "Some custom properties were not found in the webform: %s", + copy_properties, + ) + transformed_sections["General"] = _make_misc_section( + copy_properties + ) + response = {"sections": list(transformed_sections.values())} + else: + response = _transform_from_flat_schema(custom_properties) + return response + + +def _transform_from_flat_schema( + custom_properties: Dict[str, Any] +) -> Dict[str, Any]: + return {"sections": [_make_misc_section(custom_properties)]} + + +def _make_misc_section(custom_properties: dict): + """ + If the ktype_id is not found, return the custom_properties dictionary + as is, wrapped in a section named "Misc". + """ + section = {"id": generate_id(), "name": "Misc", "entries": []} + for key, value in custom_properties.items(): + section["entries"].append( + { + "id": generate_id(), + "label": key, + "value": value, + } + ) + return section + + +def _map_data_type_to_widget(value): + from dsms import KItem + from dsms.knowledge.webform import KnowledgeItemReference, Widget + + widget = None + is_list = isinstance(value, list) + if isinstance(value, list): + is_list = True + types = [] + for val in value: + dtype = type(val) + if isinstance(val, str): + types.append(Widget.MULTI_SELECT.value) + if isinstance(val, (KItem, KnowledgeItemReference, dict)): + types.append(Widget.KNOWLEDGE_ITEM.value) + if isinstance(val, (int, float)): + types.append(Widget.SLIDER.value) + types = set(types) + if len(types) > 1: + raise ValueError( + f"More than one widget type detected from data ({value}): {types} " + ) + if len(types) == 0: + raise ValueError(f"No widget type detected from data ({value}).") + widget = types.pop() + else: + dtype = type(value) + if isinstance(value, str): + widget = Widget.TEXT.value + dtype = type(value) + elif isinstance(value, (int, float)): + widget = Widget.NUMBER.value + elif isinstance(value, bool): + widget = Widget.CHECKBOX.value + + elif isinstance(value, (KItem, KnowledgeItemReference, dict)): + raise ValueError( + "KItems in the custom properties should be wrapped into a list." + ) + else: + raise ValueError( + f"Unsupported data type: {type(value)}. Value: {value}" + ) + return widget, is_list, dtype + + +def make_custom_properties_schema(metadata: List[Dict[str, Any]]) -> dict: + """ + Convert a list of dictionaries representing metadata + entries into a DSMS schema dict. + + The input should be a list of dictionaries, + where each dictionary represents a metadata entry. + The output is a dictionary in the DSMS schema, + with a single section named "General", + containing the given metadata entries. + + If the input is empty, the function will + return an empty dictionary. + + :param metadata: The metadata list to convert. + :return: A dictionary in the DSMS schema. + """ + if metadata: + for metadatum in metadata: + metadatum["id"] = generate_id() + metadata = { + "sections": [ + { + "id": generate_id(), + "name": "General", + "entries": metadata, + } + ] + } + else: + metadata = {} + + return metadata + + +def generate_id(prefix: str = "id") -> str: + # Generate a unique part using time and random characters + """ + Generates a unique id using a combination of the current time and 6 random characters. + + Args: + prefix (str): The prefix to use for the generated id. Defaults to "id". + + Returns: + str: The generated id. + """ + unique_part = f"{int(time.time() * 1000)}" # Milliseconds since epoch + random_part = "".join( + random.choices(string.ascii_lowercase + string.digits, k=6) # nosec + ) + # Combine prefix, unique part, and random part + generated_id = f"{prefix}{unique_part}{random_part}" + return generated_id diff --git a/dsms/knowledge/webform.py b/dsms/knowledge/webform.py new file mode 100644 index 0000000..85f4df0 --- /dev/null +++ b/dsms/knowledge/webform.py @@ -0,0 +1,1039 @@ +"""Webform model""" + +import logging +import warnings +from enum import Enum +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from uuid import UUID + +from pydantic.alias_generators import to_camel + +from pydantic import ( # isort:skip + AnyUrl, + BaseModel, + ConfigDict, + Field, + model_validator, + field_validator, + AliasGenerator, + AliasChoices, +) + +from dsms.knowledge.utils import ( # isort:skip + _map_data_type_to_widget, + generate_id, + print_model, +) + +from dsms.knowledge.semantics.units.utils import ( # isort:skip + get_conversion_factor, + get_property_unit, +) + +from dsms.core.logging import handler # isort:skip + +if TYPE_CHECKING: + from dsms.knowledge.ktype import KType + + +logger = logging.getLogger(__name__) +logger.addHandler(handler) +logger.propagate = False + + +class Widget(Enum): + """Enum for widgets""" + + TEXT = "Text" + FILE = "File" + TEXTAREA = "Textarea" + NUMBER = "Number" + SLIDER = "Slider" + CHECKBOX = "Checkbox" + SELECT = "Select" + RADIO = "Radio" + KNOWLEDGE_ITEM = "Knowledge item" + MULTI_SELECT = "Multi-select" + + +class WebformSelectOption(BaseModel): + """Choices in webform""" + + key: Optional[str] = Field(None, description="Label of the option") + label: Optional[Any] = Field(None, description="Value of the option") + disabled: Optional[bool] = Field(False, description="Disabled option") + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "select option") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class WebformMeasurementUnit(BaseModel): + """Measurement unit""" + + label: Optional[str] = Field( + None, description="Label of the measurement unit" + ) + iri: Optional[Union[str, AnyUrl]] = Field( + None, description="IRI of the measurement unit" + ) + symbol: Optional[str] = Field( + None, description="Symbol of the measurement unit" + ) + namespace: Optional[Union[str, AnyUrl]] = Field( + None, description="Namespace of the measurement unit" + ) + + @model_validator(mode="after") + def check_measurement_unit(cls, self) -> "MeasurementUnit": + """ + Validate and convert IRI and namespace fields to AnyUrl type. + + This method is a model validator that runs after the model is initialized. + It ensures that the `iri` and `namespace` fields of the `MeasurementUnit` + are of type `AnyUrl`. If they are not, it attempts to convert them to + `AnyUrl`. + + Returns: + MeasurementUnit: The validated and potentially modified instance. + """ + + if not isinstance(self.iri, AnyUrl): + self.iri = str(self.iri) + if not isinstance(self.namespace, AnyUrl): + self.namespace = str(self.namespace) + return self + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "webform measurement unit") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class WebformRangeOptions(BaseModel): + """Range options""" + + min: Optional[Union[int, float]] = Field(0, description="Minimum value") + max: Optional[Union[int, float]] = Field(0, description="Maximum value") + step: Optional[Union[int, float]] = Field(0, description="Step value") + range: Optional[bool] = Field(False, description="Range value") + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "range options") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class RelationMappingType(Enum): + """ + Relation mapping type + """ + + OBJECT_PROPERY = "object_property" + DATA_PROPERTY = "data_property" + ANNOTATION_PROPERTY = "annotation_property" + PROPERTY = "property" + + +class BaseWebformModel(BaseModel): + """Base webform model""" + + model_config = ConfigDict( + alias_generator=AliasGenerator( + validation_alias=lambda field_name: AliasChoices( + to_camel(field_name), field_name # pylint: disable=W0108 + ), + serialization_alias=lambda field_name: to_camel( # pylint: disable=W0108 + field_name + ), + ), + exclude={"kitem"}, + use_enum_values=True, + ) + + kitem: Optional[Any] = Field( + None, description="Associated KItem instance", exclude=True, hide=True + ) + + @property + def ktype(self) -> "KType": + """ + KType instance the entry is related to + + Returns: + KType: KType instance + """ + return self.kitem.ktype + + @property + def webform(self) -> "Webform": + """ + Retrieve the webform associated with the KType of this entry. + + Returns: + Webform: The webform instance related to the KType. + """ + return self.ktype.webform + + @property + def dsms(self): + """ + Get the DSMS instance associated with the kitem. + + This property retrieves the DSMS instance related to the kitem + of the custom properties section. + + Returns: + DSMS: The DSMS instance associated with the kitem. + """ + return self.kitem.dsms + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "webform") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + def __setattr__(self, key, value) -> None: + """ + Set an attribute of the model. + + This method sets an attribute of the model and logs the operation. + If the attribute being set is `kitem`, it directly assigns the value. + For other attributes, it marks the associated `kitem` as updated in the + session buffers if it exists. + + Args: + key (str): The name of the attribute to set. + value (Any): The value to set for the attribute. + """ + logger.debug( + "Setting property for model attribute with key `%s` with value `%s`.", + key, + value, + ) + + # Set kitem as updated + if key != "kitem" and self.kitem: + logger.debug( + "Setting related kitem with id `%s` as updated", + self.kitem.id, + ) + self.kitem.session.buffers.updated.update( + {self.kitem.id: self.kitem} + ) + + elif key == "kitem": + self.kitem = value + + super().__setattr__(key, value) + + +class RelationMapping(BaseWebformModel): + """Relation mapping""" + + iri: Optional[str] = Field(None, description="IRI of the annotation") + type: Optional[RelationMappingType] = Field( + None, description="Type of the annotation" + ) + class_iri: Optional[str] = Field( + None, + description="Target class IRI if the type of relation is an object property", + ) + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "relation mapping") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class Input(BaseWebformModel): + """Input fields in the sections in webform""" + + id: Optional[str] = Field( + default_factory=generate_id, description="ID of the input" + ) + label: Optional[str] = Field(None, description="Label of the input") + widget: Optional[Widget] = Field(None, description="Widget of the input") + required: Optional[bool] = Field(False, description="Required input") + value: Optional[Any] = Field(None, description="Value of the input") + hint: Optional[str] = Field(None, description="Hint of the input") + hidden: Optional[bool] = Field(False, description="Hidden input") + ignore: Optional[bool] = Field(False, description="Ignore input") + select_options: List[WebformSelectOption] = Field( + [], description="List of select options" + ) + measurement_unit: Optional[WebformMeasurementUnit] = Field( + None, description="Measurement unit" + ) + relation_mapping: Optional[RelationMapping] = Field( + None, description="Relation mapping" + ) + relation_mapping_extra: Optional[RelationMapping] = Field( + None, description="Relation mapping extra" + ) + multiple_selection: Optional[bool] = Field( + False, description="Multiple selection" + ) + knowledge_type: Optional[str] = Field(None, description="Knowledge type") + range_options: Optional[WebformRangeOptions] = Field( + None, description="Range options" + ) + placeholder: Optional[str] = Field( + None, description="Placeholder for the input" + ) + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "input") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class Section(BaseWebformModel): + """Section in webform""" + + id: Optional[str] = Field( + default_factory=generate_id, description="ID of the section" + ) + name: Optional[str] = Field(None, description="Name of the section") + inputs: List[Input] = Field( + [], description="List of inputs in the section" + ) + hidden: Optional[bool] = Field(False, description="Hidden section") + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "section") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class Webform(BaseWebformModel): + """User defined webform for ktype""" + + semantics_enabled: Optional[bool] = Field( + False, description="Semantics enabled" + ) + sections_enabled: Optional[bool] = Field( + False, description="Sections enabled" + ) + class_mapping: Optional[Union[List[str], str]] = Field( + [], description="Class mapping" + ) + sections: List[Section] = Field([], description="List of sections") + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "webform") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class MeasurementUnit(BaseWebformModel): + """Measurement unit""" + + iri: Optional[Union[str, AnyUrl]] = Field( + None, + description="IRI of the annotation", + ) + label: Optional[str] = Field( + None, + description="Label of the measurement unit", + ) + symbol: Optional[str] = Field( + None, + description="Symbol of the measurement unit", + ) + namespace: Optional[Union[str, AnyUrl]] = Field( + None, description="Namespace of the measurement unit" + ) + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "measurement_unit") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + @model_validator(mode="after") + def check_measurement_unit(cls, self) -> "MeasurementUnit": + """ + Validate and convert IRI and namespace fields to AnyUrl type. + + This method is a model validator that runs after the model is initialized. + It ensures that the `iri` and `namespace` fields of the `MeasurementUnit` + are of type `AnyUrl`. If they are not, it attempts to convert them to + `AnyUrl`. + + Returns: + MeasurementUnit: The validated and potentially modified instance. + """ + + if not isinstance(self.iri, AnyUrl): + self.iri = str(self.iri) + if not isinstance(self.namespace, AnyUrl): + self.namespace = str(self.namespace) + return self + + +class KnowledgeItemReference(BaseModel): + """Reference to a knowledge item if linked in the custom properties""" + + id: Union[str, UUID] = Field(..., description="ID of the knowledge item") + name: str = Field(..., description="Name of the knowledge item") + ktype_id: str = Field(..., description="ID of the knowledge type") + slug: str = Field(..., description="Slug of the knowledge item") + + model_config = ConfigDict(validate_assignment=True) + + @field_validator("id") + @classmethod + def _validate_uuid(cls, value: Union[str, UUID]) -> str: + return str(value) + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "knowledge item reference") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class Entry(BaseWebformModel): + """ + Entry in a custom properties section + """ + + id: str = Field(default_factory=generate_id) + type: Optional[Widget] = Field(None, description="Type of the entry") + label: str = Field(..., description="Label of the entry") + value: Optional[Any] = Field(None, description="Value of the entry") + measurement_unit: Optional[MeasurementUnit] = Field( + None, + description="Measurement unit of the entry", + ) + relation_mapping: Optional[RelationMapping] = Field( + None, + description="Relation mapping of the entry", + ) + required: Optional[bool] = Field(False, description="Required input") + + def __setattr__(self, key, value) -> None: + """ + Set an attribute of the Entry instance. + + This method overrides the default behavior of setting an attribute. + It sets the KItem instance of the measurement unit and relation mapping + if the key is 'kitem'. + + Args: + key (str): The name of the attribute to set. + value (Any): The value to set for the attribute. + """ + if key == "kitem": + if self.measurement_unit: + self.measurement_unit.kitem = ( # pylint: disable=assigning-non-slot + value + ) + if self.relation_mapping: + self.relation_mapping.kitem = ( # pylint: disable=assigning-non-slot + value + ) + + super().__setattr__(key, value) + + if key == "value": + self.model_validate(self) + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "entry") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + def get_unit(self) -> "Dict[str, Any]": + """Get unit for the property""" + return get_property_unit( + self.kitem.id, # pylint: disable=no-member + self.label, + self.measurement_unit, + is_dataframe_column=True, + autocomplete_symbol=self.kitem.dsms.config.autocomplete_units, # pylint: disable=no-member + ) + + def convert_to( + self, + unit_symbol_or_iri: str, + decimals: "Optional[int]" = None, + use_input_iri: bool = True, + val: "Optional[Union[int, float]]" = None, + ) -> float: + """ + Convert the data of property to a different unit. + + Args: + unit_symbol_or_iri (str): Symbol or IRI of the unit to convert to. + decimals (Optional[int]): Number of decimals to round the result to. Defaults to None. + use_input_iri (bool): If True, use IRI for unit comparison. Defaults to False. + + Returns: + float: converted value of the property + """ + value = val or self.value + if isinstance(value, list): + converted = [] + for iterval in value: + converted.append( + self.convert_to( + unit_symbol_or_iri, decimals, use_input_iri, iterval + ) + ) + else: + if not isinstance(value, (float, int)): + raise ValueError("Value must be a number") + unit = self.get_unit() + if use_input_iri: + input_str = unit.get("iri") + else: + input_str = unit.get("symbol") + converted = value * get_conversion_factor( + input_str, unit_symbol_or_iri, decimals=decimals + ) + return converted + + @model_validator(mode="after") + @classmethod + def _validate_inputs(cls, self: "Entry") -> "Entry": + spec = cls._get_input_spec(self) + + logger.debug("Entry label: %s", self.label) + logger.debug("Entry value: %s", self.value) + + # in this case we assume that a webform was defined for + # the knowledge type for this specific entry + if spec: + logger.debug("Found input spec for entry: %s", self.label) + if len(spec) == 0: + raise ValueError( + f"Could not find input spec for entry {self.label}" + ) + if len(spec) > 1: + raise ValueError( + f"Found multiple input specs for entry {self.label}" + ) + spec = spec.pop() + self.type = spec.widget + default_value = spec.value + select_options = spec.select_options + range_options = spec.range_options + if range_options: + is_list = range_options.range + else: + is_list = False + dtype = None + logger.debug("Widget type from spec: %s", self.type) + # in this case we assume that a webform was not defined + # but the user explicitly set the widget type + # this might be e.g. the case when a kitem without a webform + # is pulled from the remote backend + elif self.type and not spec: + logger.debug("Did not find input spec for entry: %s", self.label) + logger.debug("Using user-provided widget type: %s", self.type) + default_value = None + select_options = [] + is_list = None + dtype = None + # in this case we assume that a webform was not defined + # and the user did not explicitly set the widget type + # this might be e.g. the case when a new kitem is instanciated + # in the session by a flat dict (e.g. {"foo": "bar"}) + else: + logger.debug("Did not find input spec for entry: %s", self.label) + self.type, is_list, dtype = _map_data_type_to_widget(self.value) + logger.debug("Guessed widget type: %s", self.type) + default_value = None + select_options = [] + + logger.debug("Entry is_list: %s", is_list) + if dtype: + logger.debug("Guessed data type: %s", dtype) + + choices = [choice.label for choice in select_options] or None + logger.debug("Entry choices: %s", choices) + + # if the widget not is guessed from the data type, + # check if widget is mapped to the correct data type + if not dtype: + logger.debug("Guessing data type from widget type") + if self.type in ( + Widget.TEXT.value, + Widget.FILE.value, + Widget.TEXTAREA.value, + ): + dtype = str + elif self.type in (Widget.NUMBER.value, Widget.SLIDER.value): + dtype = (int, float) + elif self.type == Widget.CHECKBOX.value: + dtype = bool + elif self.type in ( + Widget.SELECT.value, + Widget.RADIO.value, + Widget.MULTI_SELECT.value, + ): + if self.type == Widget.MULTI_SELECT.value: + is_list = True + dtype = str + elif self.type == Widget.KNOWLEDGE_ITEM.value: + dtype = (type(self.kitem), KnowledgeItemReference, dict) + is_list = True + else: + raise ValueError( + f"Widget type is not mapped to a data type: {self.type}" + ) + + logger.debug("Guessed data type: %s", dtype) + + # check if value is set + if self.value is None and default_value is not None: + logger.debug( + "Value is not set, setting default value: %s", default_value + ) + self.value = default_value + + # check whether strict validation is enabled + if self.kitem.dsms.config.strict_validation: + # check if value is of correct type + error_message = "Value of type {} is not of type {}." + if is_list is True: + error_message += f""" Widget of type ´{self.type}` + is requiring a value of type `List[{dtype}]`.""" + if not isinstance(self.value, list): + raise ValueError( + error_message.format(type(self.value), dtype) + ) + for val in self.value: + if not isinstance(val, dtype): + raise ValueError( + error_message.format(type(val), dtype) + ) + elif is_list is False: + error_message += f""" Widget of type ´{self.type}` + is requiring a value of type `{dtype}`.""" + if self.value is not None and not isinstance( + self.value, dtype + ): + raise ValueError( + error_message.format(type(self.value), dtype) + ) + else: + warnings.warn( + f"No webform was defined for entry `{self.label}`. " + "Cannot check if value is of correct type." + ) + + # check if value is a valid choice (if choices are set) + if self.value is not None and choices is not None: + logger.debug("Checking if value is a valid choice") + error_message = f"""Value {self.value} is not a valid choice for entry {self.label}. + Valid choices are: {choices}""" + # in case of multi-select + if is_list is True: + for value in self.value: + if value not in choices: + raise ValueError(error_message) + # in case of single-select + elif is_list is False: + if self.value not in choices: + raise ValueError(error_message) + else: + warnings.warn( + f"No webform was defined for entry `{self.label}`. " + "Cannot check if value is a valid choice." + ) + + # check if value is required + logger.debug("Checking if value is required") + if ( + self.value is None + and default_value is None + and self.required + ): + raise ValueError( + f"Value for entry {self.label} is required" + ) + + # special case for knowledge item + if ( + self.value is not None + and self.type == Widget.KNOWLEDGE_ITEM.value + ): + logger.debug("Checking if value is a valid knowledge item") + kitems = [] + is_updated = False + if not isinstance(self.value, list): + raise ValueError( + f"""Value for entry `{self.label}` for widget of type `knowledge item` + is not a list. Got {type(self.value)}.""" + ) + for val in self.value: + if isinstance(val, dict): + val = KnowledgeItemReference(**val) + is_updated = True + if not isinstance(val, KnowledgeItemReference): + val = KnowledgeItemReference( + id=val.id, + name=val.name, + ktype_id=val.ktype_id, + slug=val.slug, + ) + is_updated = True + kitems.append(val) + if is_updated: + self.value = kitems + else: + warnings.warn( + """ + Strict validation is disabled. + Will not strictly type check the custom properties. + This also will take place when values are re-assigned. + """ + ) + + return self + + @classmethod + def _get_input_spec(cls, self: "Entry"): + spec = [] + if self.webform: + for section in self.webform.sections: + for inp in section.inputs: + if inp.id == self.id: + spec.append(inp) + return spec + + +class CustomPropertiesSection(BaseWebformModel): + """ + Section for custom properties + """ + + id: Optional[str] = Field(default_factory=generate_id) + name: str = Field(..., description="Name of the section") + entries: List[Entry] = Field([], description="Entries of the section") + + def __setattr__(self, key, value) -> None: + """ + Set an attribute of the section. + + This method is overridden to intercept setting of properties. If the key is + not a valid attribute of the section, it is interpreted as a label of an + entry of the section. The value is then set for the entry. + + Args: + key: The key of the attribute to be set. + value: The value of the attribute to be set. + """ + if key == "kitem": + for entry in self.entries: # pylint: disable=not-an-iterable + entry.kitem = value # pylint: disable=assigning-non-slot + + # Set value + if key not in self.model_dump() and key != "kitem": + to_be_updated = [] + for entry in self.entries: # pylint: disable=not-an-iterable + if entry.label == key: + to_be_updated.append(entry) + if len(to_be_updated) == 0: + raise AttributeError( + f"Section with name '{self.name}' has no attribute '{key}'" + ) + if len(to_be_updated) > 1: + raise AttributeError( + f"""Section with name '{self.name}' + has multiple attributes '{key}'. Please specify section!""" + ) + + to_be_updated = to_be_updated.pop() + to_be_updated.value = value + else: + super().__setattr__(key, value) + + def __getattr__(self, key) -> Any: + """ + Retrieve an entry from the section by its label. + + This method searches through the entries of the section to find an entry whose + label matches the given key. If the entry is found and is unique, it returns the entry. + If the entry is not found, or if multiple entries with the same label are found, it raises + an AttributeError. If the attribute exists on the BaseModel, it is retrieved using the + superclass's __getattr__ method. + + Args: + key (str): The label of the entry to retrieve. + + Returns: + Entry: The entry matching the given label. + + Raises: + AttributeError: If no entry or multiple entries with the given label are found. + """ + target = [] + if not key in self.model_dump() and key != "kitem": + for entry in self.entries: # pylint: disable=not-an-iterable + if entry.label == key: + target.append(entry) + if len(target) == 0: + raise AttributeError( + f"Section with name `{self.name}` has no attribute '{key}'" + ) + if len(target) > 1: + raise AttributeError( + f"""Section with name `{self.name}` + has multiple attributes '{key}'. + Please specify the concrete entry via indexing !""" + ) + + target = target.pop() + else: + target = super().__getattr__(key) + return target + + def __getitem__(self, key): + """ + Retrieve an entry from the section by its index. + + Args: + key (int): The index of the entry to retrieve. + + Returns: + Entry: The entry at the given index. + + Raises: + IndexError: If the index is out of range. + """ + return self.entries[key] # pylint: disable=unsubscriptable-object + + def __iter__(self): + """ + Iterate over the entries of the section. + + Yields: + Entry: The entries in the section. + """ + yield from self.entries # pylint: disable=not-an-iterable + + def __len__(self): + """ + Return the number of entries in the section. + + Returns: + int: The number of entries in the section. + """ + return len(self.entries) + + @model_validator(mode="before") + @classmethod + def set_kitem(cls, self: Dict[str, Any]) -> Dict[str, Any]: + """ + Set kitem for all entries of the section. + + This validator is called before the model is validated. It sets the kitem + for all entries of the section if the kitem is set. + + Args: + self (CustomPropertiesSection): The section to set the kitem for. + """ + kitem = self.get("kitem") + if kitem: + for entry in self.get("entries"): + if not "kitem" in entry: + entry["kitem"] = kitem + return self + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "section") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) + + +class KItemCustomPropertiesModel(BaseWebformModel): + """ + A custom properties model for a KItem. + """ + + sections: List[CustomPropertiesSection] = Field( + [], description="Sections of custom properties" + ) + + def __getattr__(self, key): + """ + Retrieve an entry from the custom properties sections by its label. + + This method searches through the entries of each section within the custom properties + model to find an entry whose label matches the given key. If the entry is found and + is unique, it returns the entry. If the entry is not found, or if multiple entries + with the same label are found, it raises an AttributeError. If the attribute exists + on the BaseModel, it is retrieved using the superclass's __getattr__ method. + + Args: + key (str): The label of the entry to retrieve. + + Returns: + Entry: The entry matching the given label. + + Raises: + AttributeError: If no entry or multiple entries with the given label are found. + """ + target = [] + + if not key in self.model_dump() and key != "kitem": + for section in self.sections: # pylint: disable=not-an-iterable + if section.name == key: + target.append(section) + for entry in section.entries: + if entry.label == key: + target.append(entry) + if len(target) == 0: + raise AttributeError( + f"Custom properties model has no entry or section '{key}'" + ) + if len(target) > 1: + raise AttributeError( + f"""Custom properties model has multiple entries or sections for + '{key}'. Please specify section via list indexing!""" + ) + target = target.pop() + else: + target = super().__getattr__(key) + return target + + def __setattr__(self, key, value) -> None: + """ + Set a custom property's value by its label. + + This method searches through the entries of each section within the custom properties + model to find an entry whose label matches the given key. If the entry is found and is + unique, it sets the value of that entry. If the entry is not found, or if multiple + entries with the same label are found, it raises an AttributeError. If the attribute + exists on the BaseModel, it is set using the superclass's __setattr__ method. + + Args: + key (str): The label of the entry to set. + value (Any): The new value of the entry. + + Raises: + AttributeError: If no entry or multiple entries with the given label are found. + """ + + if key == "kitem": + self.sections.kitem = value # pylint: disable=assigning-non-slot + + # Set value in model + if key not in self.model_dump().keys(): + to_be_updated = [] + for section in self.sections: # pylint: disable=not-an-iterable + for entry in section.entries: + if entry.label == key: + to_be_updated.append(entry) + if len(to_be_updated) == 0: + raise AttributeError( + f"Custom properties model has no attribute '{key}'" + ) + if len(to_be_updated) > 1: + raise AttributeError( + f"""Custom properties model has multiple attributes + '{key}'. Please specify section!""" + ) + to_be_updated = to_be_updated.pop() + to_be_updated.value = value + else: + super().__setattr__(key, value) + + def __iter__(self): + """ + Iterate over the sections in the custom properties. + + This method yields each section within the custom properties model, + allowing for iteration over all sections. + + Yields: + CustomPropertiesSection: The next section in the custom properties. + """ + yield from self.sections # pylint: disable=not-an-iterable + + def __len__(self): + """ + Return the number of sections in the custom properties. + + Returns: + int: The number of sections in the custom properties. + """ + return len(self.sections) + + def __getitem__(self, key): + """ + Retrieve a section from the custom properties by its index. + + Args: + key (int): The index of the section to retrieve. + + Returns: + CustomPropertiesSection: The section at the specified index. + """ + return self.sections[key] # pylint: disable=unsubscriptable-object + + @model_validator(mode="before") + @classmethod + def set_kitem(cls, self: Dict[str, Any]) -> Dict[str, Any]: + """ + Set kitem for all sections of the custom properties model. + + This validator is called before the model is validated. It sets the kitem + for all sections of the custom properties model if the kitem is set. + + Args: + self (KItemCustomPropertiesModel): The custom properties model to set the kitem for. + """ + kitem = self.get("kitem") + if kitem: + for section in self.get("sections"): + if not "kitem" in section: + section["kitem"] = kitem + return self + + def __str__(self) -> str: + """Pretty print the model fields""" + return print_model(self, "custom_properties") + + def __repr__(self) -> str: + """Pretty print the model fields""" + return str(self) diff --git a/examples/basic_usage.ipynb b/examples/basic_usage.ipynb deleted file mode 100644 index d66b53c..0000000 --- a/examples/basic_usage.ipynb +++ /dev/null @@ -1,1588 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Basic useage of the DSMS-Python-SDK\n", - "\n", - "Before you run this tutorial: make sure to have access to an DSMS-instance of your interest, that you have installed this package and that you have copied the needed variables such as the `DSMS_HOST_URL` and `DSMS_TOKEN` into an `.env`-file." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First of all, make let us import the needed classes and functions for this tutortial." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS, KItem" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\"../.env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1: Introduction" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see which kind of DSMS-object we own as a user:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can investigate what a KItem needs in order to be created. KItems are entirely based on [`Pydantic`](https://docs.pydantic.dev/latest/)-Models (v2), hence the properties (in `Pydantic` called `Fields`) are automatically validated once we set them. \n", - "\n", - "The schema of the KItem itself is a JSON schema which is machine-readable and can be directly incorporated into [Swagger](https://swagger.io/tools/swagger-ui/)-supported APIs like e.g. [`FastAPI`](https://fastapi.tiangolo.com/)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can investigate the KTypes defined in the remote instance:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KTypes.Organization\n", - "KTypes.App\n", - "KTypes.Dataset\n", - "KTypes.DatasetCatalog\n", - "KTypes.Expert\n", - "KTypes.Test\n", - "KTypes.Specimen\n", - "KTypes.Batch\n", - "KTypes.Resource\n", - "KTypes.TestingMachine\n" - ] - } - ], - "source": [ - "for ktype in dsms.ktypes:\n", - " print(ktype)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2: Create KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can make new KItems by simple class-initiation:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = foo123, \n", - "\n", - "\tid = 617cd64f-1a4d-48d5-aed6-ff9d9e3ddb20, \n", - "\n", - "\tktype_id = KTypes.Dataset, \n", - "\n", - "\tin_backend = False, \n", - "\n", - "\tslug = foo123-617cd64f, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = None, \n", - "\n", - "\tupdated_at = None, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tfoo: bar\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item = KItem(\n", - " name=\"foo123\",\n", - " ktype_id=dsms.ktypes.Dataset,\n", - " custom_properties={\"foo\": \"bar\"},\n", - ")\n", - "\n", - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Remember: changes are only syncronized with the DSMS when you call the `commit`-method:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'https://bue.materials-data.space/knowledge/dataset/foo123-617cd64f'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.commit()\n", - "item.url" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see, the object we created before running the `commit`-method has automatically been updated, e.g. with the creation- and update-timestamp:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = foo123, \n", - "\n", - "\tid = 617cd64f-1a4d-48d5-aed6-ff9d9e3ddb20, \n", - "\n", - "\tktype_id = dataset, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = foo123-617cd64f, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-20 08:01:50.536406, \n", - "\n", - "\tupdated_at = 2024-08-20 08:01:50.536406, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tfoo: bar\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. Update KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we would like to update the properties of our KItem we created previously.\n", - "\n", - "Depending on the schema of each property (see `KItem.model_schema_json()` in the **Introduction** of this tutorial), we can simply use the standard `list`-method as we know them from basic Python (e.g. for the `annotations`, `attachments`, `external_link`, etc). \n", - "\n", - "\n", - "Other properties which are not `list`-like can be simply set by attribute-assignment (e.g. `name`, `slug`, `ktype_id`, etc)." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "item.name = \"foobar\"\n", - "item.custom_properties.foobar = \"foobar\"\n", - "item.attachments.append(\"../README.md\")\n", - "item.annotations.append(\"www.example.org/foo\")\n", - "item.external_links.append(\n", - " {\"url\": \"http://example.org\", \"label\": \"example link\"}\n", - ")\n", - "item.contacts.append({\"name\": \"foo\", \"email\": \"foo@bar.mail\"})\n", - "item.affiliations.append(\"foobar team\")\n", - "item.user_groups.append({\"name\": \"foogroup\", \"group_id\": \"123\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Changes are sent to the DSMS through the `commit`-method again." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = foobar, \n", - "\n", - "\tid = 617cd64f-1a4d-48d5-aed6-ff9d9e3ddb20, \n", - "\n", - "\tktype_id = dataset, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = foo123-617cd64f, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.example.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.example.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: README.md\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: foobar team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: foo,\n", - "\t\t\temail: foo@bar.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-20 08:01:50.536406, \n", - "\n", - "\tupdated_at = 2024-08-20 08:01:54.745601, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: example link,\n", - "\t\t\turl: http://example.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [\n", - "\t\t{\n", - "\t\t\tname: foogroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tfoo: bar\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see now that e.g. the local system path of the attachment is changed to a simply file name, which means that the upload was successful. If not so, an error would have beem thrown during the `commit`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Furthermore we can also download the file we uploaded again:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\t\t\t Downloaded file: {\n", - "\t\t\tname: README.md\n", - "\t\t}\n", - "|------------------------------------Beginning of file------------------------------------|\n", - "# DSMS-SDK\n", - "Python SDK core-package for interacting with the Dataspace Management System (DSMS)\n", - "\n", - "\n", - "## Authors\n", - "\n", - "[Matthias Büschelberger](mailto:matthias.bueschelberger@iwm.fraunhofer.de) (Fraunhofer Institute for Mechanics of Materials IWM)\n", - "\n", - "[Yoav Nahshon](mailto:yoav.nahshon@iwm.fraunhofer.de) (Fraunhofer Institute for Mechanics of Materials IWM)\n", - "\n", - "[Pablo De Andres](mailto:pablo.de.andres@iwm.fraunhofer.de) (Fraunhofer Institute for Mechanics of Materials IWM)\n", - "\n", - "## License\n", - "\n", - "This project is licensed under the BSD 3-Clause. See the LICENSE file for more information.\n", - "\n", - "## Usage\n", - "\n", - "The SDK provides a general Python interface to a remote DSMS deployment, allowing users to access, store and link data in a DSMS instance easily and safely. The package provides the following main capabilities:\n", - "\n", - "- Managing Knowledge-Items (KItems), which are data instances of an explicitly defined semantic class type (KType)\n", - " - Creating, updating and deleting meta data and properties, e.g. date, operator, material response data for a conducted tensile test\n", - " - Administrating authorship, contact information and supplementary information upon making changes or adding KItems\n", - " - Semantic annotation of KItems\n", - "- Conduct simple free-text searches within the DSMS instance including filters (e.g. limiting the search for certain materials) as well as a more experts-aware SPARQL interface\n", - "- Linking KItems to other KItems\n", - "- Linking Apps to KItems, triggererd, for example, during a file upload\n", - "- Performing simple file upload and download using attachments to KItems\n", - "- Export of a knowledge (sub) graph as common serializations (.ttl, .json)\n", - "\n", - "For the basic usage, please have a look on the Jupyter Notebook under `examples/basic_usage.ipynb`. This tutorial provides a basic overview of using the dsms package to interact with Knowledge Items.\n", - "\n", - "## Disclaimer\n", - "\n", - "Copyright (c) 2014-2024, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. acting on behalf of its Fraunhofer IWM.\n", - "\n", - "Contact: [Matthias Büschelberger](mailto:matthias.bueschelberger@iwm.fraunhofer.de)\n", - "\n", - "|---------------------------------------End of file---------------------------------------|\n" - ] - } - ], - "source": [ - "for file in item.attachments:\n", - " download = file.download()\n", - "\n", - " print(\"\\t\\t\\t Downloaded file:\", file)\n", - " print(\"|------------------------------------Beginning of file------------------------------------|\")\n", - " print(download)\n", - " print(\"|---------------------------------------End of file---------------------------------------|\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4: Delete KItems and their properties" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also remove properties from the KItem without deleting the KItem itself.\n", - "\n", - "For the `list`-like properties, we can use the standard `list`-methods from basic Python again (e.g. `pop`, `remove`, etc. or the `del`-operator).\n", - "\n", - "For the other, non-`list`-like properties, we can simply use the attribute-assignment again.\n", - "\n", - "When we only want single parts of the properties in the KItem, we can do it like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{\n", - "\t\t\tiri: www.example.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.example.org,\n", - "\t\t\tdescription: None\n", - "\t\t}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.attachments.pop(0)\n", - "item.annotations.pop(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, we can also reset the entire property by setting it to e.g. an empty list again:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "item.user_groups = []" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "See the changes:" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Send the changes to the DSMS with the `commit`-method:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = foobar, \n", - "\n", - "\tid = 617cd64f-1a4d-48d5-aed6-ff9d9e3ddb20, \n", - "\n", - "\tktype_id = dataset, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = foo123-617cd64f, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: foobar team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: foo,\n", - "\t\t\temail: foo@bar.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-20 08:01:50.536406, \n", - "\n", - "\tupdated_at = 2024-08-20 08:01:54.745601, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: example link,\n", - "\t\t\turl: http://example.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tfoo: bar\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, we can also delete the whole KItem from the DSMS by applying the `del`-operator to the `dsms`-object with the individual `KItem`-object:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Commit the changes:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5: Search for KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the last unit of this tutorial, we would like to search for specfic KItems we created in the DSMS.\n", - "\n", - "For this purpose, we will firstly create some KItems and apply the `search`-method on the `DSMS`-object later on in order to find them again in the DSMS.\n", - "\n", - "We also wnat to demonstrate here, that we can link KItems to each other in order to find e.g. a related item of type `DatasetCatalog`. For this strategy, we are using the `linked_kitems`-attribute and the `id` of the item which we would like to link.\n", - "\n", - "The procedure looks like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "item = KItem(\n", - " name=\"foo 1\",\n", - " ktype_id=dsms.ktypes.DatasetCatalog\n", - ")\n", - "\n", - "item2 = KItem(\n", - " name=\"foo 2\",\n", - " ktype_id=dsms.ktypes.Organization,\n", - " linked_kitems=[item],\n", - " annotations=[\"www.example.org/foo\"]\n", - ")\n", - "item3 = KItem(\n", - " name=\"foo 3\", \n", - " ktype_id=dsms.ktypes.Organization\n", - ")\n", - "item4 = KItem(\n", - " name=\"foo 4\",\n", - " ktype_id=dsms.ktypes.Organization,\n", - " annotations=[\"www.example.org/bar\"],\n", - ")\n", - "\n", - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we are apply to search for e.g. kitems of type `DatasetCatalog`:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 1, \n", - " \n", - " \tid = 966beb55-6eb5-422e-b8c1-84d65b8cf50d, \n", - " \n", - " \tktype_id = dataset-catalog, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo1-966beb55, \n", - " \n", - " \tannotations = [], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [\n", - " \t\t\n", - " \t\t\tid: 3ca3c293-8845-4f0e-afcb-6c680c07239f\n", - " \t\t\tname: foo 2\n", - " \t\t\tslug: foo2-3ca3c293\n", - " \t\t\tktype_id: organization\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: www.example.org/foo,\n", - " \t\t\tname: foo,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: 966beb55-6eb5-422e-b8c1-84d65b8cf50d\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: None\n", - " \t\t\tcreated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\tupdated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\n", - " \t], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False)]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.search(ktypes=[dsms.ktypes.DatasetCatalog])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and for all of type `Organization` and `DatasetCatalog`:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 1, \n", - " \n", - " \tid = 966beb55-6eb5-422e-b8c1-84d65b8cf50d, \n", - " \n", - " \tktype_id = dataset-catalog, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo1-966beb55, \n", - " \n", - " \tannotations = [], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [\n", - " \t\t\n", - " \t\t\tid: 3ca3c293-8845-4f0e-afcb-6c680c07239f\n", - " \t\t\tname: foo 2\n", - " \t\t\tslug: foo2-3ca3c293\n", - " \t\t\tktype_id: organization\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: www.example.org/foo,\n", - " \t\t\tname: foo,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: 966beb55-6eb5-422e-b8c1-84d65b8cf50d\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: None\n", - " \t\t\tcreated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\tupdated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\n", - " \t], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False),\n", - " SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 2, \n", - " \n", - " \tid = 3ca3c293-8845-4f0e-afcb-6c680c07239f, \n", - " \n", - " \tktype_id = organization, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo2-3ca3c293, \n", - " \n", - " \tannotations = [\n", - " \t\t{\n", - " \t\t\tiri: www.example.org/foo,\n", - " \t\t\tname: foo,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [\n", - " \t\t\n", - " \t\t\tid: 966beb55-6eb5-422e-b8c1-84d65b8cf50d\n", - " \t\t\tname: foo 1\n", - " \t\t\tslug: foo1-966beb55\n", - " \t\t\tktype_id: dataset-catalog\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: []\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: 3ca3c293-8845-4f0e-afcb-6c680c07239f\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: None\n", - " \t\t\tcreated_at: 2024-08-20T08:02:08.491699\n", - " \t\t\tupdated_at: 2024-08-20T08:02:08.491699\n", - " \t\t\n", - " \t], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:09.024038, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:09.024038, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False),\n", - " SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 3, \n", - " \n", - " \tid = 31a58a53-8f50-4f18-93ee-90ff5a806e14, \n", - " \n", - " \tktype_id = organization, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo3-31a58a53, \n", - " \n", - " \tannotations = [], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:09.532080, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:09.532080, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False),\n", - " SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 4, \n", - " \n", - " \tid = 552ab1b9-64df-4343-9e4e-e5c292c3999f, \n", - " \n", - " \tktype_id = organization, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo4-552ab1b9, \n", - " \n", - " \tannotations = [\n", - " \t\t{\n", - " \t\t\tiri: www.example.org/bar,\n", - " \t\t\tname: bar,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:10.062595, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:10.062595, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False),\n", - " SearchResult(hit=KItem(\n", - " \n", - " \tname = Research Institute ABC, \n", - " \n", - " \tid = 21aa50c3-5ec2-4ac3-aba8-69071a4287e2, \n", - " \n", - " \tktype_id = organization, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = researchinstituteabc-21aa50c3, \n", - " \n", - " \tannotations = [], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-19 18:26:00.740761, \n", - " \n", - " \tupdated_at = 2024-08-19 18:26:00.740761, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False)]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.search(ktypes=[dsms.ktypes.Organization, dsms.ktypes.DatasetCatalog])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... or for all of type `DatasetCatalog` with `foo` in the name:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 1, \n", - " \n", - " \tid = 966beb55-6eb5-422e-b8c1-84d65b8cf50d, \n", - " \n", - " \tktype_id = dataset-catalog, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo1-966beb55, \n", - " \n", - " \tannotations = [], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [\n", - " \t\t\n", - " \t\t\tid: 3ca3c293-8845-4f0e-afcb-6c680c07239f\n", - " \t\t\tname: foo 2\n", - " \t\t\tslug: foo2-3ca3c293\n", - " \t\t\tktype_id: organization\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: www.example.org/foo,\n", - " \t\t\tname: foo,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: 966beb55-6eb5-422e-b8c1-84d65b8cf50d\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: None\n", - " \t\t\tcreated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\tupdated_at: 2024-08-20T08:02:09.024038\n", - " \t\t\n", - " \t], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:08.491699, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False)]" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.search(query=\"foo\", ktypes=[dsms.ktypes.DatasetCatalog])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and for all of type `Organization` with the annotation `www.example.org/foo`:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[SearchResult(hit=KItem(\n", - " \n", - " \tname = foo 2, \n", - " \n", - " \tid = 3ca3c293-8845-4f0e-afcb-6c680c07239f, \n", - " \n", - " \tktype_id = organization, \n", - " \n", - " \tin_backend = True, \n", - " \n", - " \tslug = foo2-3ca3c293, \n", - " \n", - " \tannotations = [\n", - " \t\t{\n", - " \t\t\tiri: www.example.org/foo,\n", - " \t\t\tname: foo,\n", - " \t\t\tnamespace: www.example.org,\n", - " \t\t\tdescription: None\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tattachments = [], \n", - " \n", - " \tlinked_kitems = [\n", - " \t\t\n", - " \t\t\tid: 966beb55-6eb5-422e-b8c1-84d65b8cf50d\n", - " \t\t\tname: foo 1\n", - " \t\t\tslug: foo1-966beb55\n", - " \t\t\tktype_id: dataset-catalog\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: []\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: 3ca3c293-8845-4f0e-afcb-6c680c07239f\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: None\n", - " \t\t\tcreated_at: 2024-08-20T08:02:08.491699\n", - " \t\t\tupdated_at: 2024-08-20T08:02:08.491699\n", - " \t\t\n", - " \t], \n", - " \n", - " \taffiliations = [], \n", - " \n", - " \tauthors = [\n", - " \t\t{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}\n", - " \t], \n", - " \n", - " \tavatar_exists = False, \n", - " \n", - " \tcontacts = [], \n", - " \n", - " \tcreated_at = 2024-08-20 08:02:09.024038, \n", - " \n", - " \tupdated_at = 2024-08-20 08:02:09.024038, \n", - " \n", - " \texternal_links = [], \n", - " \n", - " \tkitem_apps = [], \n", - " \n", - " \tsummary = None, \n", - " \n", - " \tuser_groups = [], \n", - " \n", - " \tcustom_properties = None, \n", - " \n", - " \tdataframe = None, \n", - " \n", - " \trdf_exists = False\n", - " ), fuzzy=False)]" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.search(\n", - " ktypes=[dsms.ktypes.Organization], annotations=[\"www.example.org/foo\"]\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Clean up the DSMS from the tutortial:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item]\n", - "del dsms[item2]\n", - "del dsms[item3]\n", - "del dsms[item4]\n", - "\n", - "dsms.commit()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6. Apps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can investigate which apps are available through JupyterLab:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[AppConfig(name=ckan-fetch, specification={'metadata': {'generateName': 'ckan-resource-request-'}}),\n", - " AppConfig(name=csv_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=csv_tensile_test_f2, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_notched_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_shear_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=ternary-plot, specification={'metadata': {'generateName': 'ckan-tenary-app-'}})]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.app_configs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "7. HDF5 " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are also able to upload dataframes or time series data and investigate them:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Column-wise:\n", - "column: a ,\n", - " data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n", - "column: b ,\n", - " data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]\n", - "\n", - "As data frame:\n", - " a b\n", - "0 0 1\n", - "1 1 2\n", - "2 2 3\n", - "3 3 4\n", - "4 4 5\n", - ".. .. ...\n", - "95 95 96\n", - "96 96 97\n", - "97 97 98\n", - "98 98 99\n", - "99 99 100\n", - "\n", - "[100 rows x 2 columns]\n" - ] - } - ], - "source": [ - "data = {\"a\": list(range(100)), \"b\": list(range(1,101))}\n", - "\n", - "\n", - "item = KItem(name=\"testdata1234\", ktype_id=dsms.ktypes.DatasetCatalog, dataframe=data)\n", - "dsms.commit()\n", - "\n", - "print(\"Column-wise:\")\n", - "for column in item.dataframe:\n", - " print(\"column:\", column.name, \",\\n\", \"data:\", column.get())\n", - "\n", - "df = item.dataframe.to_df()\n", - "print(\"\\nAs data frame:\")\n", - "print(df)\n", - "\n", - "new_df = df.drop(['a'], axis=1)\n", - "item.dataframe = new_df\n", - "\n", - "dsms.commit()" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item]" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/1_introduction.ipynb b/examples/tutorials/1_introduction.ipynb deleted file mode 100644 index a727932..0000000 --- a/examples/tutorials/1_introduction.ipynb +++ /dev/null @@ -1,138 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 1. Connecting with the SDK to DSMS\n", - "\n", - "In this tutorial we see the overview on how to setup and basic use DSMS-SDK\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.1. Setting up" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\"../../.env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 1.2. Introduction to KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see which kind of DSMS-object we own as a user (in the beginning, we own none):" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.kitems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can investigate what a KItem needs in order to be created. KItems are entirely based on Pydantic-Models (v2), hence the properties (in Pydantic called Fields) are automatically validated once we set them.\n", - "\n", - "The schema of the KItem itself is a JSON schema which is machine-readable and can be directly incorporated into Swagger-supported APIs like e.g. FastAPI.\n", - "\n", - "We can investigate the KTypes defined in the remote instance:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KTypes.Organization\n", - "KTypes.App\n", - "KTypes.Dataset\n", - "KTypes.DatasetCatalog\n", - "KTypes.Expert\n", - "KTypes.Test\n", - "KTypes.Specimen\n", - "KTypes.Batch\n", - "KTypes.Resource\n", - "KTypes.TestingMachine\n" - ] - } - ], - "source": [ - "for ktype in dsms.ktypes:\n", - " print(ktype)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/2_creation.ipynb b/examples/tutorials/2_creation.ipynb deleted file mode 100644 index 2f37561..0000000 --- a/examples/tutorials/2_creation.ipynb +++ /dev/null @@ -1,386 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2. Create KItems with the SDK\n", - "\n", - "In this tutorial we see how to create new Kitems." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2.1. Setting up\n", - "\n", - "Now let us import the needed classes and functions for this tutorial." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS, KItem" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\".env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### 2.2: Create KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can make new KItems by simple class-initiation: (Make sure existing KItems are not given as input). \n", - "#" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 6a5fd4a4-4dc0-4643-84eb-1e35513974ba, \n", - "\n", - "\tktype_id = KTypes.TestingMachine, \n", - "\n", - "\tin_backend = False, \n", - "\n", - "\tslug = machine-1-6a5fd4a4, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = None, \n", - "\n", - "\tupdated_at = None, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item = KItem(\n", - " name=\"Machine-1\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", - " custom_properties={\"Producer\": \"TestingLab GmBH\",\n", - " \"Location\": \"A404\",\n", - " \"Model Number\" : \"Bending Test Machine No 777\"\n", - " },\n", - ")\n", - "\n", - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Remember: changes are only syncronized with the DSMS when you call the `commit`-method:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'https://stahldigital.materials-data.space/knowledge/testing-machine/machine-1-6a5fd4a4'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.commit()\n", - "item.url" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see, the object we created before running the `commit`-method has automatically been updated, e.g. with the creation- and update-timestamp. We can check this with the below command:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 6a5fd4a4-4dc0-4643-84eb-1e35513974ba, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-6a5fd4a4, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: aa97bc4c-939e-4142-8f22-c6be8c0df228\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:24.190604, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:24.190604, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To just get the name of the item, we can do it as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'Machine-1'" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.name" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As well as the id of the kitem we can do it as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "UUID('6a5fd4a4-4dc0-4643-84eb-1e35513974ba')" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To check the KType of the item newly created we can use the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KType(id='testing-machine', name='Testing Machine', webform=, json_schema=None)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.ktype" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and also check the KType:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.is_a(dsms.ktypes.TestingMachine)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Now you can check if the particular kitem is in the list of KItems. This can be done either by using the command:\n", - " `\n", - " dsms.kitems\n", - " `\n", - " or by logging into the frontend dsms instance." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/3_updation.ipynb b/examples/tutorials/3_updation.ipynb deleted file mode 100644 index 3bf4d84..0000000 --- a/examples/tutorials/3_updation.ipynb +++ /dev/null @@ -1,287 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3. Updating KItems with the SDK\n", - "\n", - "In this tutorial we see how to update existing Kitems." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.1. Setting up\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\"../../.env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now lets get the kitem we created in the [2nd tutorial : Creation of Kitems](2_creation.ipynb)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Machine-1\n" - ] - } - ], - "source": [ - "item = dsms.kitems[-1]\n", - "print(item.name)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3.2. Updating Kitems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we would like to update the properties of our KItem we created previously.\n", - "\n", - "Depending on the schema of each property (see [DSMS KItem Schema](../dsms_kitem_schema.md)), we can simply use the standard `list`-method as we know them from basic Python (e.g. for the `annotations`, `attachments`, `external_link`, etc). \n", - "\n", - "Other properties which are not `list`-like can be simply set by attribute-assignment (e.g. `name`, `slug`, `ktype_id`, etc)." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "item.name = \"Machine-1\"\n", - "item.custom_properties.Producer = \"Machinery GmBH\"\n", - "item.attachments.append(\"testfile.txt\")\n", - "item.annotations.append(\"www.machinery.org/\")\n", - "item.external_links.append(\n", - " {\"url\": \"http://machine.org\", \"label\": \"machine-link\"}\n", - ")\n", - "item.contacts.append({\"name\": \"machinesupport\", \"email\": \"machinesupport@group.mail\"})\n", - "item.affiliations.append(\"machine-team\")\n", - "item.user_groups.append({\"name\": \"machinegroup\", \"group_id\": \"123\"})" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see now that the local system path of the attachment is changed to a simply file name, which means that the upload was successful. If not so, an error would have been thrown during the `commit`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see the updates when we print the item:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.machinery.org/,\n", - "\t\t\tname: ,\n", - "\t\t\tnamespace: www.machinery.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [\n", - "\t\t{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: Machinery GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Furthermore we can also download the file we uploaded again:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\t\t\t Downloaded file: {\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", - "|------------------------------------Beginning of file------------------------------------|\n", - "This is a calibration protocol!\n", - "|---------------------------------------End of file---------------------------------------|\n" - ] - } - ], - "source": [ - "for file in item.attachments:\n", - " download = file.download()\n", - "\n", - " print(\"\\t\\t\\t Downloaded file:\", file)\n", - " print(\"|------------------------------------Beginning of file------------------------------------|\")\n", - " print(download)\n", - " print(\"|---------------------------------------End of file---------------------------------------|\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/4_deletion.ipynb b/examples/tutorials/4_deletion.ipynb deleted file mode 100644 index 210df6b..0000000 --- a/examples/tutorials/4_deletion.ipynb +++ /dev/null @@ -1,404 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4. Deleting KItems with the SDK\n", - "\n", - "In this tutorial we see how to delete new Kitems and their properties." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.1. Setting up\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\"../../.env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then lets see the Kitem we are interested in to remove." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.machinery.org/,\n", - "\t\t\tname: ,\n", - "\t\t\tnamespace: www.machinery.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: testfile.txt\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [\n", - "\t\t{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: Machinery GmBH, \n", - "\t\tLocation: A404, \n", - "\t\tModel Number: Bending Test Machine No 777\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n" - ] - } - ], - "source": [ - "item = dsms.kitems[-1]\n", - "print(item)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4.2. Deletion of KItems and their properties" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also remove properties from the KItem without deleting the KItem itself.\n", - "\n", - "For the `list`-like properties, we can use the standard `list`-methods from basic Python again (e.g. `pop`, `remove`, etc. or the `del`-operator).\n", - "\n", - "For the other, non-`list`-like properties, we can simply use the attribute-assignment again.\n", - "\n", - "When we only want single parts of the properties in the KItem, we can do it like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{\n", - "\t\t\tname: machinegroup,\n", - "\t\t\tgroup_id: 123\n", - "\t\t}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.attachments.pop(0)\n", - "item.annotations.pop(0)\n", - "item.external_links.pop(0)\n", - "item.contacts.pop(0)\n", - "item.user_groups.pop(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, we can also reset the entire property by setting it to e.g. an empty list again:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "item.affiliations = []" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can delete the custom properties by setting the property to an empty dict:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "item.custom_properties = {}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Send the changes to the DSMS with the `commit`-method:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "See the changes:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-dd091666, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [\n", - "\t\t{\n", - "\t\t\tname: machine-team\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [\n", - "\t\t{\n", - "\t\t\tname: machinesupport,\n", - "\t\t\temail: machinesupport@group.mail,\n", - "\t\t\tuser_id: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tcreated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\tupdated_at = 2024-08-19 18:12:11.338394, \n", - "\n", - "\texternal_links = [\n", - "\t\t{\n", - "\t\t\tlabel: machine-link,\n", - "\t\t\turl: http://machine.org/\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tid: dd091666-a7c9-4b3b-8832-910bdec5c63c, \n", - "\t\tcontent: {}\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, we can also delete the whole KItem from the DSMS by applying the `del`-operator to the `dsms`-object with the individual `KItem`-object:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Commit the changes:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now to check if the particular kitem was removed, we can do this by using the command:\n", - " `\n", - " dsms.kitems\n", - " `\n", - " or by logging into the frontend dsms instance." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.12" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/5_search.ipynb b/examples/tutorials/5_search.ipynb deleted file mode 100644 index d6f8aec..0000000 --- a/examples/tutorials/5_search.ipynb +++ /dev/null @@ -1,1357 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 5. Searching KItems with the SDK\n", - "\n", - "In this tutorial we see how to search existing Kitems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.1. Setting up\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS, KItem" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\".env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 5.2. Searching for KItems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this section, we would like to search for specfic KItems we created in the DSMS.\n", - "\n", - "For this purpose, we will firstly create some KItems and apply the `search`-method on the `DSMS`-object later on in order to find them again in the DSMS.\n", - "\n", - "We also want to demonstrate here, that we can link KItems to each other in order to find e.g. a related item of type `DatasetCatalog`. For this strategy, we are using the `linked_kitems`- attribute and the `id` of the item which we would like to link.\n", - "\n", - "The procedure looks like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "item1 = KItem(\n", - " name=\"Machine-1\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", - " annotations=[\"https://w3id.org/steel/ProcessOntology/TestingMachine\"],\n", - " custom_properties={\"Producer\": \"TestingLab GmBH\",\n", - " \"Room Number\": \"A404\",\n", - " \"Description\": \"Bending Test Machine\"\n", - " }\n", - ")\n", - "\n", - "item2 = KItem(\n", - " name=\"Machine-2\",\n", - " ktype_id=dsms.ktypes.TestingMachine,\n", - " annotations=[\"https://w3id.org/steel/ProcessOntology/TestingMachine\"],\n", - " custom_properties={\"Producer\": \"StressStrain GmBH\",\n", - " \"Room Number\": \"B500\",\n", - " \"Description\": \"Compression Test Machine\"\n", - " }\n", - ")\n", - "\n", - "item3 = KItem(\n", - " name=\"Specimen-1\", \n", - " ktype_id=dsms.ktypes.Specimen,\n", - " linked_kitems=[item1],\n", - " annotations=[\"https://w3id.org/steel/ProcessOntology/TestPiece\"],\n", - " custom_properties={\"Geometry\": \"Cylindrical 150mm x 20mm x 40mm\",\n", - " \"Material\": \"Concrete\",\n", - " \"Project ID\": \"ConstructionProject2024\"\n", - " }\n", - "\n", - ")\n", - "item4 = KItem(\n", - " name=\"Specimen-2\",\n", - " ktype_id=dsms.ktypes.Specimen,\n", - " linked_kitems=[item2],\n", - " annotations=[\"https://w3id.org/steel/ProcessOntology/TestPiece\"],\n", - " custom_properties={\"Geometry\": \"Rectangular 200mm x 30mm x 20mm\",\n", - " \"Material\": \"Metal\",\n", - " \"Project ID\": \"MetalBlenders2024\"\n", - " }\n", - ")\n", - "\n", - "item5 = KItem(\n", - " name=\"Research Institute ABC\",\n", - " ktype_id=dsms.ktypes.Organization,\n", - " linked_kitems=[item1,item2],\n", - " annotations=[\"www.researchBACiri.org/foo\"],\n", - ")\n", - "\n", - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "

Note : Here in this tutorial, we use dsms.search with `limit=1` to maintain readability but the user can adjust the variable `limit` as per requirement.

\n", - "\n", - "\n", - "Now, we are apply to search for e.g. kitems of type `TestingMachine`:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = d1524272-5f34-454b-bb61-7b0ab3a825a7, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-d1524272, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-ba1a7871\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:46.876917\n", - "\t\t\tupdated_at: 2024-08-23T17:15:46.876917\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-2335f57a\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T17:15:47.998202\n", - "\t\t\tupdated_at: 2024-08-23T17:15:47.998202\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:45.431622, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:45.431622, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for result in dsms.search(ktypes=[dsms.ktypes.TestingMachine], limit=1):\n", - " print(result.hit)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and for all of type `Organization` and `DatasetCatalog`:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 2335f57a-efc2-47ce-83b3-866cdeb6d30d, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-2335f57a, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-d1524272\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t}, {\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\tupdated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "fuzziness: False\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for result in dsms.search(ktypes=[dsms.ktypes.Organization, dsms.ktypes.DatasetCatalog], limit=1):\n", - " print(result.hit)\n", - " print(\"fuzziness: \", result.fuzzy)\n", - " print(\"\\n\")\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... or for all of type `Dataset` with `Specimen-1` in the name:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "for result in dsms.search(query=\"Specimen-1\", ktypes=[dsms.ktypes.Dataset], limit=1):\n", - " print(result.hit)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and for all of type `Organization` with the annotation `www.researchBACiri.org/foo`:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 2335f57a-efc2-47ce-83b3-866cdeb6d30d, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-2335f57a, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: research ABC Institute,\n", - "\t\t\tnamespace: research,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: d1524272-5f34-454b-bb61-7b0ab3a825a7\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-d1524272\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: []\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ba1a7871-ff75-465f-8625-a7a0202edca4\n", - "\t\t}, {\n", - "\t\t\tid: 2335f57a-efc2-47ce-83b3-866cdeb6d30d\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\tupdated_at: 2024-08-23T17:15:45.431622\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\tupdated_at = 2024-08-23 17:15:47.998202, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n", - "KItem(\n", - "\n", - "\tname = Research Institute ABC, \n", - "\n", - "\tid = 379e07a7-acd3-45dd-8bbd-ad5edb549946, \n", - "\n", - "\tktype_id = organization, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = researchinstituteabc-379e07a7, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-31a7d354\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - "\t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t\tname: Machine-2\n", - "\t\t\tslug: machine-2-8155c264\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:46.777379, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:46.777379, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for result in dsms.search(\n", - " ktypes=[dsms.ktypes.Organization], annotations=[\"www.researchBACiri.org/foo\"], limit=1\n", - " ):\n", - " print(result.hit)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5.3. Fetching linked KItems from a KItem" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the beginning under **5.1** we created some kitems and linked each other. Now we want to fetch the linked kitems and display them to the user. For this we use the `linked_kitems` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[\n", - "\t\t\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t\tname: Machine-1\n", - "\t\t\tslug: machine-1-31a7d354\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - "\t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t\tname: Machine-2\n", - "\t\t\tslug: machine-2-8155c264\n", - "\t\t\tktype_id: testing-machine\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - "\t\t}, {\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - "\t\t\n", - "\t]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, this linked KItem is not a \"real\" KItem. Due to performance reasons, we only display a slim representation of the linked KItem. Imagine if the linked KItem also has a linked KItem... this might lead to an infinite recursion. We can fetch the \"real\" KItem by using the `fetch` method of the linked KItem:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems[0].fetch()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also get the linked KItems grouped by annotation:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'https://w3id.org/steel/ProcessOntology/TestingMachine': [\n", - " \t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - " \t\t\tname: Machine-1\n", - " \t\t\tslug: machine-1-31a7d354\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - " \t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - " \t\t,\n", - " \n", - " \t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - " \t\t\tname: Machine-2\n", - " \t\t\tslug: machine-2-8155c264\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - " \t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - " \t\t]}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems.by_annotation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Again, we are able to fetch the \"real\" KItem by using the `fetch` method of the linked KItem:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems.by_annotation[\"https://w3id.org/steel/ProcessOntology/TestingMachine\"][0].fetch()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Additionally, we can retrieve the linked KItems grouped by ktype:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{: [\n", - " \t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - " \t\t\tname: Machine-1\n", - " \t\t\tslug: machine-1-31a7d354\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'TestingLab GmBH', 'Room Number': 'A404', 'Description': 'Bending Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:40.453930\n", - " \t\t\tupdated_at: 2024-08-23T18:16:40.453930\n", - " \t\t,\n", - " \n", - " \t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - " \t\t\tname: Machine-2\n", - " \t\t\tslug: machine-2-8155c264\n", - " \t\t\tktype_id: testing-machine\n", - " \t\t\tsummary: None\n", - " \t\t\tavatar_exists: False\n", - " \t\t\tannotations: [{\n", - " \t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - " \t\t\tname: TestingMachine,\n", - " \t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - " \t\t\tdescription: None\n", - " \t\t}]\n", - " \t\t\tlinked_kitems: [{\n", - " \t\t\tid: ce4309d3-cb6b-4fe0-85e6-d74e0b282b5d\n", - " \t\t}, {\n", - " \t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - " \t\t}]\n", - " \t\t\texternal_links: []\n", - " \t\t\tcontacts: []\n", - " \t\t\tauthors: [{\n", - " \t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - " \t\t}]\n", - " \t\t\tlinked_affiliations: []\n", - " \t\t\tattachments: []\n", - " \t\t\tuser_groups: []\n", - " \t\t\tcustom_properties: {'Producer': 'StressStrain GmBH', 'Room Number': 'B500', 'Description': 'Compression Test Machine'}\n", - " \t\t\tcreated_at: 2024-08-23T18:16:42.132533\n", - " \t\t\tupdated_at: 2024-08-23T18:16:42.132533\n", - " \t\t]}" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems.by_ktype" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and retrieve them by type:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "KItem(\n", - "\n", - "\tname = Machine-1, \n", - "\n", - "\tid = 31a7d354-6dfc-4aa5-832c-a1e581757193, \n", - "\n", - "\tktype_id = testing-machine, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = machine-1-31a7d354, \n", - "\n", - "\tannotations = [\n", - "\t\t{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestingMachine,\n", - "\t\t\tname: TestingMachine,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tattachments = [], \n", - "\n", - "\tlinked_kitems = [\n", - "\t\t\n", - "\t\t\tid: af4e0334-6325-4ae7-91fd-cc1b21864cf1\n", - "\t\t\tname: Specimen-1\n", - "\t\t\tslug: specimen-1-af4e0334\n", - "\t\t\tktype_id: specimen\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: https://w3id.org/steel/ProcessOntology/TestPiece,\n", - "\t\t\tname: TestPiece,\n", - "\t\t\tnamespace: https://w3id.org/steel/ProcessOntology,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: {'sampletype': None, 'sampleinformation': None, 'sampleproductionprocess': None, 'Geometry': 'Cylindrical 150mm x 20mm x 40mm', 'Material': 'Concrete', 'Project ID': 'ConstructionProject2024'}\n", - "\t\t\tcreated_at: 2024-08-23T18:16:43.773825\n", - "\t\t\tupdated_at: 2024-08-23T18:16:43.773825\n", - "\t\t, \n", - "\t\t\n", - "\t\t\tid: 379e07a7-acd3-45dd-8bbd-ad5edb549946\n", - "\t\t\tname: Research Institute ABC\n", - "\t\t\tslug: researchinstituteabc-379e07a7\n", - "\t\t\tktype_id: organization\n", - "\t\t\tsummary: None\n", - "\t\t\tavatar_exists: False\n", - "\t\t\tannotations: [{\n", - "\t\t\tiri: www.researchBACiri.org/foo,\n", - "\t\t\tname: foo,\n", - "\t\t\tnamespace: www.researchBACiri.org,\n", - "\t\t\tdescription: None\n", - "\t\t}]\n", - "\t\t\tlinked_kitems: [{\n", - "\t\t\tid: 31a7d354-6dfc-4aa5-832c-a1e581757193\n", - "\t\t}, {\n", - "\t\t\tid: 8155c264-c790-4151-bff5-471e6a64fc21\n", - "\t\t}]\n", - "\t\t\texternal_links: []\n", - "\t\t\tcontacts: []\n", - "\t\t\tauthors: [{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}]\n", - "\t\t\tlinked_affiliations: []\n", - "\t\t\tattachments: []\n", - "\t\t\tuser_groups: []\n", - "\t\t\tcustom_properties: None\n", - "\t\t\tcreated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\tupdated_at: 2024-08-23T18:16:46.777379\n", - "\t\t\n", - "\t], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = False, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\tupdated_at = 2024-08-23 18:16:40.453930, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = {\n", - "\t\tProducer: TestingLab GmBH, \n", - "\t\tRoom Number: A404, \n", - "\t\tDescription: Bending Test Machine\n", - "\t}, \n", - "\n", - "\tdataframe = None, \n", - "\n", - "\trdf_exists = False\n", - ")" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item5.linked_kitems.by_ktype[dsms.ktypes.TestingMachine][0].fetch()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Clean up the DSMS from the tutortial:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item1]\n", - "del dsms[item2]\n", - "del dsms[item3]\n", - "del dsms[item4]\n", - "del dsms[item5]\n", - "\n", - "dsms.commit()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/6_apps.ipynb b/examples/tutorials/6_apps.ipynb deleted file mode 100644 index b658a96..0000000 --- a/examples/tutorials/6_apps.ipynb +++ /dev/null @@ -1,1031 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 6. DSMS Apps and Pipelines\n", - "\n", - "In this tutorial we see how to create apps and run them manually" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6.1: Setting up\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from dsms import DSMS, KItem, AppConfig\n", - "import time" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now source the environmental variables from an `.env` file and start the DSMS-session." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "dsms = DSMS(env=\"../../.env\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6.1. Investigating Available Apps" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can investigate which apps are available:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[AppConfig(name=ckan-fetch, specification={'metadata': {'generateName': 'ckan-resource-request-'}}),\n", - " AppConfig(name=csv_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=csv_tensile_test_f2, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_notched_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_shear_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=excel_tensile_test, specification={'metadata': {'generateName': 'data2rdf-'}}),\n", - " AppConfig(name=ternary-plot, specification={'metadata': {'generateName': 'ckan-tenary-app-'}})]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dsms.app_configs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6.2 Create a new app config and apply it to a KItem" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6.2.1 Arbitrary python code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To be defined." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 6.2.2 - Data2RDF" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 6.2.2.1 Prepare app and its config" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the following example, we would like to upload some csv with some arbitrary data and describe it through an RDF. This will give us the opportunity to harmonize the entities of the data file through ontological concepts and allow us to convert values of the data frame columns in to any compatible unit we would like to have.\n", - "\n", - "Fist of all, let us define the data:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "data = \"\"\"A,B,C\n", - "1.2,1.3,1.5\n", - "1.7,1.8,1.9\n", - "2.0,2.1,2.3\n", - "2.5,2.6,2.8\n", - "3.0,3.2,3.4\n", - "3.6,3.7,3.9\n", - "4.1,4.3,4.4\n", - "4.7,4.8,5.0\n", - "5.2,5.3,5.5\n", - "5.8,6.0,6.1\n", - "\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will also give the config a defined name:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "configname = \"testapp2\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As a next step, we want to create a new app specification. The specification is following the definition of an [**Argo Workflow**](https://argo-workflows.readthedocs.io/en/latest/). The workflow shall trigger a pipeline from a docker image with the [**Data2RDF package**](https://data2rdf.readthedocs.io/en/latest/). \n", - "\n", - "The image has already been deployed on the k8s cluster of the DSMS and the workflow template with the name `dsms-data2rdf` has been implemented previously. Hence we only need to configure our pipeline for our data shown above, which we would like to upload and describe through an RDF.\n", - "\n", - "For more details about the data2rdf package, please refer to the documentation of Data2RDF mentioned above.\n", - "\n", - "The parameters of the app config are defining the inputs for our Data2RDF pipeline. This e.g. are: \n", - "\n", - "* the parser kind (`csv` here)\n", - "* the time series header length (`1` here)\n", - "* the metadata length (`0` here)\n", - "* the time series separator (`,` here)\n", - "* the log level (`DEBUG` here)\n", - "* the mapping \n", - " * `A` is the test time and has a unit in seconds\n", - " * `B` is the standard force in kilonewtons\n", - " * `C` is the absolut cross head travel in millimeters" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "parameters = [\n", - " {\"name\": \"parser\", \"value\": \"csv\"},\n", - " {\"name\": \"time_series_header_length\", \"value\": 1},\n", - " {\"name\": \"metadata_length\", \"value\": 0},\n", - " {\"name\": \"time_series_sep\", \"value\": \",\"},\n", - " {\"name\": \"log_level\", \"value\": \"DEBUG\"},\n", - " {\n", - " \"name\": \"mapping\",\n", - " \"value\": \"\"\"\n", - " [\n", - " {\n", - " \"key\": \"A\",\n", - " \"iri\": \"https://w3id.org/steel/ProcessOntology/TestTime\",\n", - " \"unit\": \"s\"\n", - " },\n", - " {\n", - " \"key\": \"B\",\n", - " \"iri\": \"https://w3id.org/steel/ProcessOntology/StandardForce\",\n", - " \"unit\": \"kN\"\n", - " },\n", - " {\n", - " \"key\": \"C\",\n", - " \"iri\": \"https://w3id.org/steel/ProcessOntology/AbsoluteCrossheadTravel\",\n", - " \"unit\": \"mm\"\n", - " }\n", - " ]\n", - " \"\"\",\n", - " },\n", - "]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we add the parameters to our app specification. We assign a prefix `datardf-` which shall generate a new name with some random characters as suffix. The workflow template with the Docker image we want to run is called `dsms-data2rdf` and its `entrypoint` is `execute_pipeline`." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Define app specification\n", - "specification = {\n", - " \"apiVersion\": \"argoproj.io/v1alpha1\",\n", - " \"kind\": \"Workflow\",\n", - " \"metadata\": {\"generateName\": \"data2rdf-\"},\n", - " \"spec\": {\n", - " \"entrypoint\": \"execute_pipeline\",\n", - " \"workflowTemplateRef\": {\"name\": \"dsms-data2rdf\"},\n", - " \"arguments\": {\"parameters\": parameters},\n", - " },\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we instanciate the new app config:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "appspec = AppConfig(\n", - " name=configname,\n", - " specification=specification, # this can also be a file path to a yaml file instead of a dict\n", - " expose_sdk_config=True,\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Please note that the `expose_sdk_config` is important here, since the pipeline needs to be aware of the settings of our platform and our current SDK-session." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We commit the new app config:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we would like to apply the app config to a KItem. The set the `triggerUponUpload` must be set to `True` so that the app is triggered automatically when we upload an attachment.\n", - "\n", - "Additionally, we must tell the file extension for which the upload shall be triggered. Here it is `.csv`.\n", - "\n", - "We also want to generate a qr code as avatar for the KItem with `avatar={\"include_qr\": True}`." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "item = KItem(\n", - " name=\"my tensile test experiment\",\n", - " ktype_id=dsms.ktypes.Dataset,\n", - " kitem_apps=[\n", - " {\n", - " \"executable\": appspec.name,\n", - " \"title\": \"data2rdf\",\n", - " \"additional_properties\": {\n", - " \"triggerUponUpload\": True,\n", - " \"triggerUponUploadFileExtensions\": [\".csv\"],\n", - " },\n", - " }\n", - " ],\n", - " avatar={\"include_qr\": True},\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We commit the KItem:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we add our data with our attachment:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "item.attachments = [{\"name\": \"dummy_data.csv\", \"content\": data}]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And we commit again:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 6.2.2.2 Get results" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can verify that the data extraction was successful:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KItem(\n", - "\n", - "\tname = my tensile test experiment, \n", - "\n", - "\tid = 58683a2d-7823-4638-bc8e-91b461afa593, \n", - "\n", - "\tktype_id = dataset, \n", - "\n", - "\tin_backend = True, \n", - "\n", - "\tslug = mytensiletestexperiment-58683a2d, \n", - "\n", - "\tannotations = [], \n", - "\n", - "\tattachments = [\n", - "\t\t{\n", - "\t\t\tname: dummy_data.csv\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tlinked_kitems = [], \n", - "\n", - "\taffiliations = [], \n", - "\n", - "\tauthors = [\n", - "\t\t{\n", - "\t\t\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tavatar_exists = True, \n", - "\n", - "\tcontacts = [], \n", - "\n", - "\tcreated_at = 2024-08-20 08:04:25.756982, \n", - "\n", - "\tupdated_at = 2024-08-20 08:04:25.756982, \n", - "\n", - "\texternal_links = [], \n", - "\n", - "\tkitem_apps = [\n", - "\t\t{\n", - "\t\t\tkitem_app_id: 22,\n", - "\t\t\texecutable: testapp2,\n", - "\t\t\ttitle: data2rdf,\n", - "\t\t\tdescription: None,\n", - "\t\t\ttags: None,\n", - "\t\t\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\n", - "\t\t}\n", - "\t], \n", - "\n", - "\tsummary = None, \n", - "\n", - "\tuser_groups = [], \n", - "\n", - "\tcustom_properties = None, \n", - "\n", - "\tdataframe = [\n", - "\t\t{\n", - "\t\t\tcolumn_id: 0,\n", - "\t\t\tname: TestTime\n", - "\t\t}, \n", - "\t\t{\n", - "\t\t\tcolumn_id: 1,\n", - "\t\t\tname: StandardForce\n", - "\t\t}, \n", - "\t\t{\n", - "\t\t\tcolumn_id: 2,\n", - "\t\t\tname: AbsoluteCrossheadTravel\n", - "\t\t}\n", - "\t], \n", - "\n", - "\trdf_exists = True\n", - ")\n" - ] - } - ], - "source": [ - "print(item)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And also that the RDF generation was successful:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "@prefix csvw: .\n", - "@prefix dcat: .\n", - "@prefix dcterms: .\n", - "@prefix ns1: .\n", - "@prefix ns2: .\n", - "@prefix rdfs: .\n", - "@prefix xsd: .\n", - "\n", - " a dcat:Dataset ;\n", - " dcterms:hasPart ;\n", - " dcat:distribution [ a dcat:Distribution ;\n", - " dcat:accessURL \"https://bue.materials-data.space/api/knowledge/data_api/58683a2d-7823-4638-bc8e-91b461afa593\"^^xsd:anyURI ;\n", - " dcat:mediaType \"http://www.iana.org/assignments/media-types/text/csv\"^^xsd:anyURI ] .\n", - "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/MilliM\"^^xsd:anyURI .\n", - "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/KiloN\"^^xsd:anyURI .\n", - "\n", - " a ;\n", - " ns1:hasUnit \"http://qudt.org/vocab/unit/SEC\"^^xsd:anyURI .\n", - "\n", - " a csvw:TableGroup ;\n", - " csvw:table [ a csvw:Table ;\n", - " rdfs:label \"Time series data\" ;\n", - " csvw:tableSchema [ a csvw:Schema ;\n", - " csvw:column [ a csvw:Column ;\n", - " ns1:quantity ;\n", - " csvw:titles \"C\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", - " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", - " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-2\"^^xsd:anyURI ;\n", - " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ],\n", - " [ a csvw:Column ;\n", - " ns1:quantity ;\n", - " csvw:titles \"B\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", - " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", - " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-1\"^^xsd:anyURI ;\n", - " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ],\n", - " [ a csvw:Column ;\n", - " ns1:quantity ;\n", - " csvw:titles \"A\"^^xsd:string ;\n", - " ns2:page [ a ns2:Document ;\n", - " dcterms:format \"https://www.iana.org/assignments/media-types/application/json\"^^xsd:anyURI ;\n", - " dcterms:identifier \"https://bue.materials-data.space/api/knowledge/data_api/column-0\"^^xsd:anyURI ;\n", - " dcterms:type \"http://purl.org/dc/terms/Dataset\"^^xsd:anyURI ] ] ] ] .\n", - "\n", - "\n" - ] - } - ], - "source": [ - "print(item.subgraph.serialize())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And now we are able to convert our data into any compatiable unit we want. For the `StandardForce`, it was previously `kN`, but we want to have it in `N` now:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1300.0,\n", - " 1800.0,\n", - " 2100.0,\n", - " 2600.0,\n", - " 3200.0,\n", - " 3700.0,\n", - " 4300.0,\n", - " 4800.0,\n", - " 5300.0,\n", - " 6000.0]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.dataframe.StandardForce.convert_to(\"N\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 6.2.2.3 Manipulate dataframe" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to retrieve the dataframe as pd.DataFrame:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
TestTimeStandardForceAbsoluteCrossheadTravel
01.21.31.5
11.71.81.9
22.02.12.3
32.52.62.8
43.03.23.4
53.63.73.9
64.14.34.4
74.74.85.0
85.25.35.5
95.86.06.1
\n", - "
" - ], - "text/plain": [ - " TestTime StandardForce AbsoluteCrossheadTravel\n", - "0 1.2 1.3 1.5\n", - "1 1.7 1.8 1.9\n", - "2 2.0 2.1 2.3\n", - "3 2.5 2.6 2.8\n", - "4 3.0 3.2 3.4\n", - "5 3.6 3.7 3.9\n", - "6 4.1 4.3 4.4\n", - "7 4.7 4.8 5.0\n", - "8 5.2 5.3 5.5\n", - "9 5.8 6.0 6.1" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "item.dataframe.to_df()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to overwrite the dataframe with new data:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "item.dataframe = {\n", - " \"TestTime\": list(range(100)),\n", - " \"StandardForce\": list(range(1,101)),\n", - " \"AbsoluteCrossheadTravel\": list(range(2,102))\n", - "}\n", - "dsms.commit()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to retrieve the data colum-wise:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "column: TestTime ,\n", - " data: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n", - "column: StandardForce ,\n", - " data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]\n", - "column: AbsoluteCrossheadTravel ,\n", - " data: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101]\n" - ] - } - ], - "source": [ - "for column in item.dataframe:\n", - " print(\"column:\", column.name, \",\\n\", \"data:\", column.get())\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and also to modify the dataframe directly as we need:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "new_df = item.dataframe.to_df().drop(['TestTime'], axis=1)\n", - "item.dataframe = new_df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 6.2.2.4 Run app on demand" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to run the app on demand, not being triggered automatically during the upload of an attachment every time. For this purpose, we just need to refer to the name of the app we assigned during the KItem creation ( here it is simply `data2rdf`).\n", - "\n", - "Additionally, we need to tell the `attachment_name` and hand over the access token and host url to the app by explicitly setting `expose_sdk_config` to `True`. This is basically telling the SDK that the app is using the SDK also internally and that the app should receive its parameters from the current SDK session.\n", - "\n", - "The app is running synchronously, hence the `job` is created when the pipeline run finished." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "job = item.kitem_apps.by_title[\"data2rdf\"].run(\n", - " attachment_name=item.attachments[0].name,\n", - " expose_sdk_config=True\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to retrieve the job status:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "JobStatus(phase='Succeeded', estimated_duration=None, finished_at='08/20/2024, 08:05:35', started_at='08/20/2024, 08:05:15', message=None, progress='1/1')" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "job.status" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "... and the job logs:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\"[2024-08-20 08:05:23,481 - dsms_data2rdf.main - INFO]: Fetch KItem: \\n KItem(\\n\\n\\tname = my tensile test experiment, \\n\\n\\tid = 58683a2d-7823-4638-bc8e-91b461afa593, \\n\\n\\tktype_id = dataset, \\n\\n\\tin_backend = True, \\n\\n\\tslug = mytensiletestexperiment-58683a2d, \\n\\n\\tannotations = [], \\n\\n\\tattachments = [\\n\\t\\t{\\n\\t\\t\\tname: dummy_data.csv\\n\\t\\t}\\n\\t], \\n\\n\\tlinked_kitems = [], \\n\\n\\taffiliations = [], \\n\\n\\tauthors = [\\n\\t\\t{\\n\\t\\t\\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\n\\t\\t}\\n\\t], \\n\\n\\tavatar_exists = True, \\n\\n\\tcontacts = [], \\n\\n\\tcreated_at = 2024-08-20 08:04:25.756982, \\n\\n\\tupdated_at = 2024-08-20 08:04:25.756982, \\n\\n\\texternal_links = [], \\n\\n\\tkitem_apps = [\\n\\t\\t{\\n\\t\\t\\tkitem_app_id: 22,\\n\\t\\t\\texecutable: testapp2,\\n\\t\\t\\ttitle: data2rdf,\\n\\t\\t\\tdescription: None,\\n\\t\\t\\ttags: None,\\n\\t\\t\\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\\n\\t\\t}\\n\\t], \\n\\n\\tsummary = None, \\n\\n\\tuser_groups = [], \\n\\n\\tcustom_properties = None, \\n\\n\\tdataframe = [\\n\\t\\t{\\n\\t\\t\\tcolumn_id: 0,\\n\\t\\t\\tname: TestTime\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 1,\\n\\t\\t\\tname: StandardForce\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 2,\\n\\t\\t\\tname: AbsoluteCrossheadTravel\\n\\t\\t}\\n\\t], \\n\\n\\trdf_exists = True\\n)\\n[2024-08-20 08:05:23,494 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {'metadata_sep': ',', 'metadata_length': '0', 'time_series_sep': ',', 'time_series_header_length': '1', 'drop_na': 'false', 'fillna': ''}\\n[2024-08-20 08:05:23,494 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\n[2024-08-20 08:05:23,494 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {'base_iri': 'https://bue.materials-data.space/58683a2d-7823-4638-bc8e-91b461afa593', 'data_download_uri': 'https://bue.materials-data.space/api/knowledge/data_api/58683a2d-7823-4638-bc8e-91b461afa593', 'graph_identifier': 'https://bue.materials-data.space/58683a2d-7823-4638-bc8e-91b461afa593', 'separator': '/', 'encoding': 'utf-8'}\\n[2024-08-20 08:05:28,419 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\n[2024-08-20 08:05:28,810 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\n[2024-08-20 08:05:28,810 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\n[2024-08-20 08:05:28,810 - dsms_data2rdf.main - INFO]: Done!\\n\"\n" - ] - } - ], - "source": [ - "print(job.logs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In case we would like to run the job in the background, we simply add a `wait=False`:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "job = item.kitem_apps.by_title[\"data2rdf\"].run(\n", - " attachment_name=item.attachments[0].name,\n", - " expose_sdk_config=True,\n", - " wait=False,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are able to monitor the job status and logs asynchronously:" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Running' estimated_duration=None finished_at=None started_at='08/20/2024, 08:05:39' message=None progress='0/1'\n", - "\n", - " Current logs:\n", - "\"\"\n", - "\n", - " Current status:\n", - "phase='Succeeded' estimated_duration=None finished_at='08/20/2024, 08:05:59' started_at='08/20/2024, 08:05:39' message=None progress='1/1'\n", - "\n", - " Current logs:\n", - "\"[2024-08-20 08:05:45,472 - dsms_data2rdf.main - INFO]: Fetch KItem: \\n KItem(\\n\\n\\tname = my tensile test experiment, \\n\\n\\tid = 58683a2d-7823-4638-bc8e-91b461afa593, \\n\\n\\tktype_id = dataset, \\n\\n\\tin_backend = True, \\n\\n\\tslug = mytensiletestexperiment-58683a2d, \\n\\n\\tannotations = [], \\n\\n\\tattachments = [\\n\\t\\t{\\n\\t\\t\\tname: dummy_data.csv\\n\\t\\t}\\n\\t], \\n\\n\\tlinked_kitems = [], \\n\\n\\taffiliations = [], \\n\\n\\tauthors = [\\n\\t\\t{\\n\\t\\t\\tuser_id: 7f0e5a37-353b-4bbc-b1f1-b6ad575f562d\\n\\t\\t}\\n\\t], \\n\\n\\tavatar_exists = True, \\n\\n\\tcontacts = [], \\n\\n\\tcreated_at = 2024-08-20 08:04:25.756982, \\n\\n\\tupdated_at = 2024-08-20 08:04:25.756982, \\n\\n\\texternal_links = [], \\n\\n\\tkitem_apps = [\\n\\t\\t{\\n\\t\\t\\tkitem_app_id: 22,\\n\\t\\t\\texecutable: testapp2,\\n\\t\\t\\ttitle: data2rdf,\\n\\t\\t\\tdescription: None,\\n\\t\\t\\ttags: None,\\n\\t\\t\\tadditional_properties: {triggerUponUpload: True, triggerUponUploadFileExtensions: ['.csv']}\\n\\t\\t}\\n\\t], \\n\\n\\tsummary = None, \\n\\n\\tuser_groups = [], \\n\\n\\tcustom_properties = None, \\n\\n\\tdataframe = [\\n\\t\\t{\\n\\t\\t\\tcolumn_id: 0,\\n\\t\\t\\tname: TestTime\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 1,\\n\\t\\t\\tname: StandardForce\\n\\t\\t}, \\n\\t\\t{\\n\\t\\t\\tcolumn_id: 2,\\n\\t\\t\\tname: AbsoluteCrossheadTravel\\n\\t\\t}\\n\\t], \\n\\n\\trdf_exists = True\\n)\\n[2024-08-20 08:05:45,485 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser arguments: {'metadata_sep': ',', 'metadata_length': '0', 'time_series_sep': ',', 'time_series_header_length': '1', 'drop_na': 'false', 'fillna': ''}\\n[2024-08-20 08:05:45,485 - dsms_data2rdf.main - INFO]: Run pipeline with the following parser: Parser.csv\\n[2024-08-20 08:05:45,485 - dsms_data2rdf.main - INFO]: Run pipeline with the following config: {'base_iri': 'https://bue.materials-data.space/58683a2d-7823-4638-bc8e-91b461afa593', 'data_download_uri': 'https://bue.materials-data.space/api/knowledge/data_api/58683a2d-7823-4638-bc8e-91b461afa593', 'graph_identifier': 'https://bue.materials-data.space/58683a2d-7823-4638-bc8e-91b461afa593', 'separator': '/', 'encoding': 'utf-8'}\\n[2024-08-20 08:05:50,422 - dsms_data2rdf.main - INFO]: Pipeline did detect any metadata. Will not make annotations for KItem\\n[2024-08-20 08:05:50,816 - dsms_data2rdf.main - INFO]: Checking that dataframe is up to date.\\n[2024-08-20 08:05:50,816 - dsms_data2rdf.main - INFO]: Dataframe upload was successful after 0 retries.\\n[2024-08-20 08:05:50,816 - dsms_data2rdf.main - INFO]: Done!\\n\"\n" - ] - } - ], - "source": [ - "while True:\n", - " time.sleep(1)\n", - " print(\"\\n Current status:\")\n", - " print(job.status)\n", - " print(\"\\n Current logs:\")\n", - " print(job.logs)\n", - " if job.status.phase != \"Running\":\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**IMPORTANT**: When job has run asychronously (in the background), we need to manually refresh the KItem afterwards:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "item.refresh()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Clean up the DSMS from the tutorial" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "del dsms[item]\n", - "del dsms[appspec]\n", - "dsms.commit()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "sdk", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/tutorials/testfile.txt b/examples/tutorials/testfile.txt deleted file mode 100644 index 7976166..0000000 --- a/examples/tutorials/testfile.txt +++ /dev/null @@ -1 +0,0 @@ -This is a calibration protocol! diff --git a/setup.cfg b/setup.cfg index 2fdb9b2..cc3030f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,12 +1,12 @@ [metadata] name = dsms_sdk -version = v2.0.4 +version = v3.0.0 description = Python SDK core-package for working with the Dataspace Management System (DSMS). long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/MI-FraunhoferIWM/dsms-python-sdk -author = Matthias Büschelberger, Yoav Nahshon, Pablo De Andres -author_email = matthias.bueschelberger@iwm.fraunhofer.de, yoav.nahshon@iwm.fraunhofer.de, pablo.de.andres@iwm.fraunhofer.de +author = Matthias Büschelberger, Yoav Nahshon, Pablo De Andres, Arjun Gopalakrishnan, Priyabrat Mishra +author_email = matthias.bueschelberger@iwm.fraunhofer.de, yoav.nahshon@iwm.fraunhofer.de, arjun.gopalakrishnan@iwm.fraunhofer.de, priyabrat.mishra@iwm.fraunhofer.de license = BSD-3-Clause license_files = LICENSE classifiers = @@ -23,8 +23,9 @@ install_requires = click>=8,<9 html5lib>=1,<2 lru-cache<1 + oyaml==1 pandas>=2,<3 - pydantic>=2 + pydantic>=2,<3 pydantic-settings python-dotenv qrcode-artistic>=3,<4 diff --git a/tests/conftest.py b/tests/conftest.py index e2f16d7..bf894bc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -49,6 +49,17 @@ class MockDB: ] } + ktypes = [ + { + "name": "organization", + "id": "organization", + }, + { + "name": "dataset", + "id": "dataset", + }, + ] + @pytest.fixture(scope="function") def custom_address(request) -> str: @@ -89,18 +100,8 @@ def mock_callbacks(custom_address) -> "Dict[str, Any]": ktypes = urljoin(custom_address, "api/knowledge-type/") def return_ktypes(request): - ktypes = [ - { - "name": "organization", - "id": "organization", - }, - { - "name": "dataset", - "id": "dataset", - }, - ] header = {"content_type": "application/json"} - return (200, header, json.dumps(ktypes)) + return (200, header, json.dumps(MockDB.ktypes)) def return_kitems(request): # Extract 'id' parameter from the URL @@ -114,6 +115,19 @@ def return_kitems(request): else: return 200, {}, json.dumps(MockDB.kitems[item_id]) + def return_ktype(request): + # Extract 'id' parameter from the URL + url_parts = request.url.split("/") + ktype_id = url_parts[-1] + ktypes = {ktype["id"]: ktype for ktype in MockDB.ktypes} + + # Your logic to generate a dynamic response based on 'ktype_id' + # This is just a placeholder; you should replace it with your actual logic + if ktype_id not in ktypes: + return 404, {}, "KType does not exist" + else: + return 200, {}, json.dumps(ktypes[ktype_id]) + def return_dataframe(request): # Extract 'id' parameter from the URL url_parts = request.url.split("/") @@ -150,7 +164,7 @@ def _get_kitems() -> "Dict[str, Any]": def _get_dataframe() -> "Dict[str, Any]": return { - urljoin(custom_address, f"api/knowledge/data_api/{uid}"): [ + urljoin(custom_address, f"api/knowledge/data/{uid}"): [ { "method": responses.GET, "returns": { @@ -178,6 +192,20 @@ def _get_slugs() -> "Dict[str, Any]": for slug in MockDB.slugs } + def _get_individual_ktypes() -> "Dict[str, Any]": + return { + urljoin(custom_address, f"api/knowledge-type/{ktype['id']}"): [ + { + "method": responses.GET, + "returns": { + "content_type": "application/json", + "callback": return_ktype, + }, + } + ] + for ktype in MockDB.ktypes + } + return { ktypes: [ { @@ -191,6 +219,7 @@ def _get_slugs() -> "Dict[str, Any]": **_get_kitems(), **_get_dataframe(), **_get_slugs(), + **_get_individual_ktypes(), } @@ -218,10 +247,10 @@ def register_mocks( @pytest.fixture(autouse=True, scope="function") -def reset_dsms_context(): - from dsms.core.context import Context +def reset_dsms_session(): + from dsms.core.session import Session - Context.dsms = None + Session.dsms = None @pytest.fixture(scope="function") diff --git a/tests/test_kitem.py b/tests/test_kitem.py index 6eb399d..0f09770 100644 --- a/tests/test_kitem.py +++ b/tests/test_kitem.py @@ -8,11 +8,11 @@ def test_kitem_basic(custom_address, get_mock_kitem_ids): """Test KItem properties""" from dsms.core.configuration import Configuration - from dsms.core.context import Context from dsms.core.dsms import DSMS + from dsms.core.session import Session from dsms.knowledge.kitem import KItem - assert Context.dsms is None + assert Session.dsms is None with pytest.warns(UserWarning, match="No authentication details"): dsms = DSMS(host_url=custom_address) @@ -25,7 +25,7 @@ def test_kitem_basic(custom_address, get_mock_kitem_ids): assert isinstance(instance.dsms, DSMS) assert isinstance(instance.dsms.config, Configuration) - assert Context.dsms == instance.dsms + assert Session.dsms == instance.dsms @responses.activate @@ -33,11 +33,11 @@ def test_kitem_config_class(custom_address, get_mock_kitem_ids): """Test KItem properties""" from dsms.core.configuration import Configuration - from dsms.core.context import Context from dsms.core.dsms import DSMS + from dsms.core.session import Session from dsms.knowledge.kitem import KItem - assert Context.dsms is None + assert Session.dsms is None with pytest.warns(UserWarning, match="No authentication details"): config = Configuration(host_url=custom_address) @@ -51,7 +51,7 @@ def test_kitem_config_class(custom_address, get_mock_kitem_ids): assert isinstance(instance.dsms, DSMS) assert config == instance.dsms.config - assert Context.dsms == instance.dsms + assert Session.dsms == instance.dsms @responses.activate @@ -100,25 +100,6 @@ def test_dsms_bad_object(): DSMS(config=bad_object) -@responses.activate -def test_kitem_bad_kwarg(get_mock_kitem_ids, custom_address): - from pydantic import ValidationError - - from dsms.core.dsms import DSMS - from dsms.knowledge.kitem import KItem - - with pytest.warns(UserWarning, match="No authentication details"): - dsms = DSMS(host_url=custom_address) - - with pytest.raises(ValidationError): - KItem( - id=get_mock_kitem_ids[0], - name="foo123", - foo="bar", - ktype_id=dsms.ktypes.Organization, - ) - - @responses.activate def test_kitem_connection_error(): from dsms.core.configuration import Configuration @@ -145,7 +126,6 @@ def test_kitem_default_ktypes(custom_address): @responses.activate def test_ktype_property(get_mock_kitem_ids, custom_address): - from dsms.core.context import Context from dsms.core.dsms import DSMS from dsms.knowledge.kitem import KItem @@ -158,7 +138,7 @@ def test_ktype_property(get_mock_kitem_ids, custom_address): ktype_id=dsms.ktypes.Organization, ) - assert kitem.ktype == Context.ktypes.get(dsms.ktypes.Organization.value) + assert kitem.is_a(dsms.ktypes.Organization) # @responses.activate diff --git a/tests/test_utils.py b/tests/test_utils.py index 485c474..9535a90 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -61,9 +61,8 @@ def test_kitem_diffs(get_mock_kitem_ids, custom_address): "annotations": [ { "iri": "http://example.org/", - "name": "bar", + "label": "bar", "namespace": "example", - "description": None, } ], "linked_kitems": [ @@ -99,7 +98,7 @@ def test_kitem_diffs(get_mock_kitem_ids, custom_address): annotations=[ { "iri": "http://example.org/", - "name": "foo", + "label": "foo", "namespace": "example", } ], @@ -115,9 +114,8 @@ def test_kitem_diffs(get_mock_kitem_ids, custom_address): "annotations_to_link": [ { "iri": "http://example.org/", - "name": "foo", + "label": "foo", "namespace": "example", - "description": None, } ], "user_groups_to_add": [], @@ -136,9 +134,8 @@ def test_kitem_diffs(get_mock_kitem_ids, custom_address): "annotations_to_unlink": [ { "iri": "http://example.org/", - "name": "bar", + "label": "bar", "namespace": "example", - "description": None, } ], "user_groups_to_remove": [],