dsp-tools 0.9.13__py3-none-any.whl → 18.3.0.post13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dsp_tools/__init__.py +5 -0
- dsp_tools/cli/args.py +47 -0
- dsp_tools/cli/call_action.py +85 -0
- dsp_tools/cli/call_action_files_only.py +101 -0
- dsp_tools/cli/call_action_with_network.py +207 -0
- dsp_tools/cli/create_parsers.py +479 -0
- dsp_tools/cli/entry_point.py +322 -0
- dsp_tools/cli/utils.py +87 -0
- dsp_tools/clients/CLAUDE.md +420 -0
- dsp_tools/clients/authentication_client.py +14 -0
- dsp_tools/clients/authentication_client_live.py +66 -0
- dsp_tools/clients/connection.py +35 -0
- dsp_tools/clients/connection_live.py +233 -0
- dsp_tools/clients/fuseki_metrics.py +60 -0
- dsp_tools/clients/group_user_clients.py +35 -0
- dsp_tools/clients/group_user_clients_live.py +181 -0
- dsp_tools/clients/legal_info_client.py +23 -0
- dsp_tools/clients/legal_info_client_live.py +132 -0
- dsp_tools/clients/list_client.py +49 -0
- dsp_tools/clients/list_client_live.py +166 -0
- dsp_tools/clients/metadata_client.py +24 -0
- dsp_tools/clients/metadata_client_live.py +47 -0
- dsp_tools/clients/ontology_clients.py +49 -0
- dsp_tools/clients/ontology_create_client_live.py +166 -0
- dsp_tools/clients/ontology_get_client_live.py +80 -0
- dsp_tools/clients/permissions_client.py +68 -0
- dsp_tools/clients/project_client.py +16 -0
- dsp_tools/clients/project_client_live.py +66 -0
- dsp_tools/commands/create/communicate_problems.py +24 -0
- dsp_tools/commands/create/create.py +134 -0
- dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
- dsp_tools/commands/create/create_on_server/classes.py +99 -0
- dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
- dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
- dsp_tools/commands/create/create_on_server/group_users.py +165 -0
- dsp_tools/commands/create/create_on_server/lists.py +163 -0
- dsp_tools/commands/create/create_on_server/mappers.py +12 -0
- dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
- dsp_tools/commands/create/create_on_server/ontology.py +52 -0
- dsp_tools/commands/create/create_on_server/project.py +68 -0
- dsp_tools/commands/create/create_on_server/properties.py +119 -0
- dsp_tools/commands/create/exceptions.py +29 -0
- dsp_tools/commands/create/lists_only.py +66 -0
- dsp_tools/commands/create/models/create_problems.py +87 -0
- dsp_tools/commands/create/models/parsed_ontology.py +88 -0
- dsp_tools/commands/create/models/parsed_project.py +81 -0
- dsp_tools/commands/create/models/rdf_ontology.py +12 -0
- dsp_tools/commands/create/models/server_project_info.py +100 -0
- dsp_tools/commands/create/parsing/parse_lists.py +45 -0
- dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
- dsp_tools/commands/create/parsing/parse_project.py +149 -0
- dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
- dsp_tools/commands/create/project_validate.py +595 -0
- dsp_tools/commands/create/serialisation/ontology.py +119 -0
- dsp_tools/commands/create/serialisation/project.py +44 -0
- dsp_tools/commands/excel2json/CLAUDE.md +101 -0
- dsp_tools/commands/excel2json/json_header.py +321 -0
- dsp_tools/commands/excel2json/lists/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/compliance_checks.py +292 -0
- dsp_tools/commands/excel2json/lists/make_lists.py +247 -0
- dsp_tools/commands/excel2json/lists/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/models/deserialise.py +30 -0
- dsp_tools/commands/excel2json/lists/models/input_error.py +216 -0
- dsp_tools/commands/excel2json/lists/models/serialise.py +57 -0
- dsp_tools/commands/excel2json/lists/utils.py +81 -0
- dsp_tools/commands/excel2json/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/models/input_error.py +416 -0
- dsp_tools/commands/excel2json/models/json_header.py +175 -0
- dsp_tools/commands/excel2json/models/list_node_name.py +16 -0
- dsp_tools/commands/excel2json/models/ontology.py +76 -0
- dsp_tools/commands/excel2json/old_lists.py +328 -0
- dsp_tools/commands/excel2json/project.py +280 -0
- dsp_tools/commands/excel2json/properties.py +370 -0
- dsp_tools/commands/excel2json/resources.py +336 -0
- dsp_tools/commands/excel2json/utils.py +352 -0
- dsp_tools/commands/excel2xml/__init__.py +7 -0
- dsp_tools/commands/excel2xml/excel2xml_cli.py +523 -0
- dsp_tools/commands/excel2xml/excel2xml_lib.py +1953 -0
- dsp_tools/commands/excel2xml/propertyelement.py +47 -0
- dsp_tools/commands/get/__init__.py +0 -0
- dsp_tools/commands/get/get.py +166 -0
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/get/legacy_models/__init__.py +0 -0
- dsp_tools/commands/get/legacy_models/context.py +318 -0
- dsp_tools/commands/get/legacy_models/group.py +241 -0
- dsp_tools/commands/get/legacy_models/helpers.py +47 -0
- dsp_tools/commands/get/legacy_models/listnode.py +390 -0
- dsp_tools/commands/get/legacy_models/model.py +12 -0
- dsp_tools/commands/get/legacy_models/ontology.py +324 -0
- dsp_tools/commands/get/legacy_models/project.py +366 -0
- dsp_tools/commands/get/legacy_models/propertyclass.py +417 -0
- dsp_tools/commands/get/legacy_models/resourceclass.py +676 -0
- dsp_tools/commands/get/legacy_models/user.py +438 -0
- dsp_tools/commands/get/models/__init__.py +0 -0
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +258 -0
- dsp_tools/commands/ingest_xmlupload/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +178 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +69 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +166 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +121 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +64 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +20 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +57 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +66 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +67 -0
- dsp_tools/commands/resume_xmlupload/__init__.py +0 -0
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +96 -0
- dsp_tools/commands/start_stack.py +428 -0
- dsp_tools/commands/update_legal/CLAUDE.md +344 -0
- dsp_tools/commands/update_legal/__init__.py +0 -0
- dsp_tools/commands/update_legal/core.py +182 -0
- dsp_tools/commands/update_legal/csv_operations.py +135 -0
- dsp_tools/commands/update_legal/models.py +87 -0
- dsp_tools/commands/update_legal/xml_operations.py +247 -0
- dsp_tools/commands/validate_data/CLAUDE.md +159 -0
- dsp_tools/commands/validate_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/constants.py +59 -0
- dsp_tools/commands/validate_data/mappers.py +143 -0
- dsp_tools/commands/validate_data/models/__init__.py +0 -0
- dsp_tools/commands/validate_data/models/api_responses.py +45 -0
- dsp_tools/commands/validate_data/models/input_problems.py +119 -0
- dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
- dsp_tools/commands/validate_data/models/validation.py +106 -0
- dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
- dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
- dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
- dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
- dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
- dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
- dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
- dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
- dsp_tools/commands/validate_data/sparql/cardinality_shacl.py +209 -0
- dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
- dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
- dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
- dsp_tools/commands/validate_data/utils.py +59 -0
- dsp_tools/commands/validate_data/validate_data.py +283 -0
- dsp_tools/commands/validate_data/validation/__init__.py +0 -0
- dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
- dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
- dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
- dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
- dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
- dsp_tools/commands/xmlupload/__init__.py +0 -0
- dsp_tools/commands/xmlupload/iri_resolver.py +21 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
- dsp_tools/commands/xmlupload/models/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +10 -0
- dsp_tools/commands/xmlupload/models/ingest.py +143 -0
- dsp_tools/commands/xmlupload/models/input_problems.py +58 -0
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +45 -0
- dsp_tools/commands/xmlupload/models/permissions_parsed.py +93 -0
- dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
- dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
- dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
- dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
- dsp_tools/commands/xmlupload/models/upload_clients.py +14 -0
- dsp_tools/commands/xmlupload/models/upload_state.py +20 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/ark2iri.py +55 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/iiif_uri_validator.py +50 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/list_client.py +120 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
- dsp_tools/commands/xmlupload/resource_create_client.py +25 -0
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/__init__.py +0 -0
- dsp_tools/commands/xmlupload/stash/analyse_circular_reference_graph.py +236 -0
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +87 -0
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +68 -0
- dsp_tools/commands/xmlupload/stash/stash_models.py +109 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +106 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +196 -0
- dsp_tools/commands/xmlupload/upload_config.py +76 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +27 -0
- dsp_tools/commands/xmlupload/xmlupload.py +516 -0
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/config/warnings_config.py +32 -0
- dsp_tools/error/__init__.py +0 -0
- dsp_tools/error/custom_warnings.py +39 -0
- dsp_tools/error/exceptions.py +204 -0
- dsp_tools/error/problems.py +10 -0
- dsp_tools/error/xmllib_errors.py +20 -0
- dsp_tools/error/xmllib_warnings.py +54 -0
- dsp_tools/error/xmllib_warnings_util.py +159 -0
- dsp_tools/error/xsd_validation_error_msg.py +19 -0
- dsp_tools/legacy_models/__init__.py +0 -0
- dsp_tools/legacy_models/datetimestamp.py +81 -0
- dsp_tools/legacy_models/langstring.py +253 -0
- dsp_tools/legacy_models/projectContext.py +49 -0
- dsp_tools/py.typed +0 -0
- dsp_tools/resources/schema/data.xsd +648 -0
- dsp_tools/resources/schema/lists-only.json +72 -0
- dsp_tools/resources/schema/project.json +1258 -0
- dsp_tools/resources/schema/properties-only.json +874 -0
- dsp_tools/resources/schema/resources-only.json +140 -0
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.override.yml +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +88 -0
- dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
- dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
- dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
- dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
- dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
- dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
- dsp_tools/utils/__init__.py +0 -0
- dsp_tools/utils/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/data_formats/date_util.py +166 -0
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/data_formats/shared.py +81 -0
- dsp_tools/utils/data_formats/uri_util.py +76 -0
- dsp_tools/utils/fuseki_bloating.py +63 -0
- dsp_tools/utils/json_parsing.py +22 -0
- dsp_tools/utils/rdf_constants.py +42 -0
- dsp_tools/utils/rdflib_utils.py +10 -0
- dsp_tools/utils/replace_id_with_iri.py +66 -0
- dsp_tools/utils/request_utils.py +238 -0
- dsp_tools/utils/xml_parsing/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
- dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
- dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
- dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
- dsp_tools/xmllib/CLAUDE.md +302 -0
- dsp_tools/xmllib/__init__.py +49 -0
- dsp_tools/xmllib/general_functions.py +877 -0
- dsp_tools/xmllib/internal/__init__.py +0 -0
- dsp_tools/xmllib/internal/checkers.py +162 -0
- dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
- dsp_tools/xmllib/internal/constants.py +46 -0
- dsp_tools/xmllib/internal/input_converters.py +155 -0
- dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
- dsp_tools/xmllib/internal/serialise_resource.py +177 -0
- dsp_tools/xmllib/internal/serialise_values.py +152 -0
- dsp_tools/xmllib/internal/type_aliases.py +11 -0
- dsp_tools/xmllib/models/__init__.py +0 -0
- dsp_tools/xmllib/models/config_options.py +28 -0
- dsp_tools/xmllib/models/date_formats.py +48 -0
- dsp_tools/xmllib/models/dsp_base_resources.py +1542 -0
- dsp_tools/xmllib/models/internal/__init__.py +0 -0
- dsp_tools/xmllib/models/internal/file_values.py +172 -0
- dsp_tools/xmllib/models/internal/geometry.py +162 -0
- dsp_tools/xmllib/models/internal/migration_metadata.py +55 -0
- dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
- dsp_tools/xmllib/models/internal/values.py +342 -0
- dsp_tools/xmllib/models/licenses/__init__.py +0 -0
- dsp_tools/xmllib/models/licenses/other.py +59 -0
- dsp_tools/xmllib/models/licenses/recommended.py +107 -0
- dsp_tools/xmllib/models/permissions.py +41 -0
- dsp_tools/xmllib/models/res.py +1782 -0
- dsp_tools/xmllib/models/root.py +348 -0
- dsp_tools/xmllib/value_checkers.py +434 -0
- dsp_tools/xmllib/value_converters.py +777 -0
- dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
- dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
- dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
- dsp_tools-18.3.0.post13.dist-info/entry_points.txt +3 -0
- dsp_tools-0.9.13.dist-info/LICENSE +0 -674
- dsp_tools-0.9.13.dist-info/METADATA +0 -144
- dsp_tools-0.9.13.dist-info/RECORD +0 -71
- dsp_tools-0.9.13.dist-info/WHEEL +0 -5
- dsp_tools-0.9.13.dist-info/entry_points.txt +0 -3
- dsp_tools-0.9.13.dist-info/top_level.txt +0 -1
- dsplib/models/connection.py +0 -272
- dsplib/models/group.py +0 -296
- dsplib/models/helpers.py +0 -505
- dsplib/models/langstring.py +0 -277
- dsplib/models/listnode.py +0 -578
- dsplib/models/model.py +0 -20
- dsplib/models/ontology.py +0 -448
- dsplib/models/permission.py +0 -112
- dsplib/models/project.py +0 -547
- dsplib/models/propertyclass.py +0 -505
- dsplib/models/resource.py +0 -366
- dsplib/models/resourceclass.py +0 -810
- dsplib/models/sipi.py +0 -30
- dsplib/models/user.py +0 -731
- dsplib/models/value.py +0 -1000
- dsplib/utils/knora-data-schema.xsd +0 -454
- dsplib/utils/knora-schema-lists.json +0 -83
- dsplib/utils/knora-schema.json +0 -434
- dsplib/utils/onto_commons.py +0 -24
- dsplib/utils/onto_create_lists.py +0 -73
- dsplib/utils/onto_create_ontology.py +0 -442
- dsplib/utils/onto_get.py +0 -58
- dsplib/utils/onto_validate.py +0 -33
- dsplib/utils/xml_upload.py +0 -539
- dsplib/widgets/doublepassword.py +0 -80
- knora/MLS-import-libraries.py +0 -84
- knora/dsp_tools.py +0 -96
- knora/dsplib/models/connection.py +0 -272
- knora/dsplib/models/group.py +0 -296
- knora/dsplib/models/helpers.py +0 -506
- knora/dsplib/models/langstring.py +0 -277
- knora/dsplib/models/listnode.py +0 -578
- knora/dsplib/models/model.py +0 -20
- knora/dsplib/models/ontology.py +0 -448
- knora/dsplib/models/permission.py +0 -112
- knora/dsplib/models/project.py +0 -583
- knora/dsplib/models/propertyclass.py +0 -505
- knora/dsplib/models/resource.py +0 -416
- knora/dsplib/models/resourceclass.py +0 -811
- knora/dsplib/models/sipi.py +0 -35
- knora/dsplib/models/user.py +0 -731
- knora/dsplib/models/value.py +0 -1000
- knora/dsplib/utils/knora-data-schema.xsd +0 -464
- knora/dsplib/utils/knora-schema-lists.json +0 -83
- knora/dsplib/utils/knora-schema.json +0 -444
- knora/dsplib/utils/onto_commons.py +0 -24
- knora/dsplib/utils/onto_create_lists.py +0 -73
- knora/dsplib/utils/onto_create_ontology.py +0 -451
- knora/dsplib/utils/onto_get.py +0 -58
- knora/dsplib/utils/onto_validate.py +0 -33
- knora/dsplib/utils/xml_upload.py +0 -540
- knora/dsplib/widgets/doublepassword.py +0 -80
- knora/knora.py +0 -2108
- knora/test.py +0 -99
- knora/testit.py +0 -76
- knora/xml2knora.py +0 -633
- {dsplib → dsp_tools/cli}/__init__.py +0 -0
- {dsplib/models → dsp_tools/clients}/__init__.py +0 -0
- {dsplib/utils → dsp_tools/commands}/__init__.py +0 -0
- {dsplib/widgets → dsp_tools/commands/create}/__init__.py +0 -0
- {knora → dsp_tools/commands/create/create_on_server}/__init__.py +0 -0
- {knora/dsplib → dsp_tools/commands/create/models}/__init__.py +0 -0
- {knora/dsplib/models → dsp_tools/commands/create/parsing}/__init__.py +0 -0
- {knora/dsplib/utils → dsp_tools/commands/create/serialisation}/__init__.py +0 -0
- {knora/dsplib/widgets → dsp_tools/commands/excel2json}/__init__.py +0 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This model implements the handling of resource classes. It contains two classes that work closely together:
|
|
3
|
+
* "HasProperty" deals with the association of Property-instances with the Resource-instances. This association
|
|
4
|
+
is done using the "cardinality"-clause
|
|
5
|
+
* "ResourceClass" is the main class representing a DSP resource class.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections.abc import Sequence
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import Any
|
|
13
|
+
from typing import Optional
|
|
14
|
+
from typing import Union
|
|
15
|
+
|
|
16
|
+
import regex
|
|
17
|
+
|
|
18
|
+
from dsp_tools.clients.connection import Connection
|
|
19
|
+
from dsp_tools.commands.get.legacy_models.context import Context
|
|
20
|
+
from dsp_tools.commands.get.legacy_models.helpers import Cardinality
|
|
21
|
+
from dsp_tools.commands.get.legacy_models.model import Model
|
|
22
|
+
from dsp_tools.error.exceptions import BaseError
|
|
23
|
+
from dsp_tools.legacy_models.datetimestamp import DateTimeStamp
|
|
24
|
+
from dsp_tools.legacy_models.langstring import LangString
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class HasProperty(Model):
|
|
28
|
+
ROUTE: str = "/v2/ontologies/cardinalities"
|
|
29
|
+
|
|
30
|
+
class Ptype(Enum):
|
|
31
|
+
system = 1
|
|
32
|
+
knora = 2
|
|
33
|
+
other = 3
|
|
34
|
+
|
|
35
|
+
_context: Context
|
|
36
|
+
_ontology_id: str
|
|
37
|
+
_property_id: str
|
|
38
|
+
_resclass_id: str
|
|
39
|
+
_cardinality: Cardinality
|
|
40
|
+
_gui_order: int
|
|
41
|
+
_ptype: Ptype
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
con: Connection,
|
|
46
|
+
context: Context,
|
|
47
|
+
ontology_id: Optional[str] = None,
|
|
48
|
+
property_id: Optional[str] = None,
|
|
49
|
+
resclass_id: Optional[str] = None,
|
|
50
|
+
cardinality: Optional[Cardinality] = None,
|
|
51
|
+
gui_order: Optional[int] = None,
|
|
52
|
+
ptype: Optional[Ptype] = None,
|
|
53
|
+
):
|
|
54
|
+
super().__init__(con)
|
|
55
|
+
if not isinstance(context, Context):
|
|
56
|
+
raise BaseError('"context"-parameter must be an instance of Context')
|
|
57
|
+
self._context = context
|
|
58
|
+
if ontology_id is not None:
|
|
59
|
+
self._ontology_id = context.iri_from_prefix(ontology_id)
|
|
60
|
+
else:
|
|
61
|
+
self._ontology_id = None
|
|
62
|
+
self._property_id = property_id
|
|
63
|
+
self._resclass_id = resclass_id
|
|
64
|
+
self._cardinality = cardinality
|
|
65
|
+
self._gui_order = gui_order
|
|
66
|
+
self._ptype = ptype
|
|
67
|
+
self._changed = set()
|
|
68
|
+
|
|
69
|
+
#
|
|
70
|
+
# Here follows a list of getters/setters
|
|
71
|
+
#
|
|
72
|
+
@property
|
|
73
|
+
def ontology_id(self) -> Optional[str]:
|
|
74
|
+
return self._ontology_id
|
|
75
|
+
|
|
76
|
+
@ontology_id.setter
|
|
77
|
+
def ontology_id(self, value: Optional[str]) -> None:
|
|
78
|
+
self._ontology_id = value
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def property_id(self) -> Optional[str]:
|
|
82
|
+
return self._property_id
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def resclass_id(self) -> Optional[str]:
|
|
86
|
+
return self._resclass_id
|
|
87
|
+
|
|
88
|
+
@resclass_id.setter
|
|
89
|
+
def resclass_id(self, value: Optional[str]) -> None:
|
|
90
|
+
self._resclass_id = value
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def cardinality(self) -> Optional[Cardinality]:
|
|
94
|
+
return self._cardinality
|
|
95
|
+
|
|
96
|
+
@cardinality.setter
|
|
97
|
+
def cardinality(self, value: Optional[Cardinality]) -> None:
|
|
98
|
+
self._cardinality = value
|
|
99
|
+
self._changed.add("cardinality")
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def gui_order(self) -> Optional[int]:
|
|
103
|
+
return self._gui_order
|
|
104
|
+
|
|
105
|
+
@gui_order.setter
|
|
106
|
+
def gui_order(self, value: int) -> None:
|
|
107
|
+
self._gui_order = value
|
|
108
|
+
self._changed.add("gui_order")
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def ptype(self) -> Ptype:
|
|
112
|
+
return self._ptype
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def fromJsonObj(cls, con: Connection, context: Context, jsonld_obj: dict[str, Any]) -> tuple[str, HasProperty]:
|
|
116
|
+
rdf_iri = context.prefix_from_iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
|
117
|
+
rdfs_iri = context.prefix_from_iri("http://www.w3.org/2000/01/rdf-schema#")
|
|
118
|
+
owl_iri = context.prefix_from_iri("http://www.w3.org/2002/07/owl#")
|
|
119
|
+
knora_api_iri = context.prefix_from_iri("http://api.knora.org/ontology/knora-api/v2#")
|
|
120
|
+
salsah_gui_iri = context.prefix_from_iri("http://api.knora.org/ontology/salsah-gui/v2#")
|
|
121
|
+
|
|
122
|
+
if jsonld_obj.get("@type") is None or jsonld_obj.get("@type") != owl_iri + ":Restriction":
|
|
123
|
+
raise BaseError("Expected restriction type")
|
|
124
|
+
|
|
125
|
+
cardinality = cls._fromJsonObj_get_cardinality(jsonld_obj, owl_iri)
|
|
126
|
+
|
|
127
|
+
ontology_id, property_id, ptype = cls._fromJsonObj_get_prop_type_iri(
|
|
128
|
+
context, jsonld_obj, knora_api_iri, owl_iri, rdf_iri, rdfs_iri
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
gui_order: int = None
|
|
132
|
+
if jsonld_obj.get(salsah_gui_iri + ":guiOrder") is not None:
|
|
133
|
+
gui_order = jsonld_obj[salsah_gui_iri + ":guiOrder"]
|
|
134
|
+
return property_id, cls(
|
|
135
|
+
con=con,
|
|
136
|
+
context=context,
|
|
137
|
+
ontology_id=ontology_id,
|
|
138
|
+
property_id=property_id,
|
|
139
|
+
cardinality=cardinality,
|
|
140
|
+
gui_order=gui_order,
|
|
141
|
+
ptype=ptype,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def _fromJsonObj_get_prop_type_iri(
|
|
146
|
+
context: Context, jsonld_obj: dict[str, Any], knora_api_iri: str, owl_iri: str, rdf_iri: str, rdfs_iri: str
|
|
147
|
+
) -> tuple[str, str, HasProperty.Ptype]:
|
|
148
|
+
property_id: str
|
|
149
|
+
ptype: HasProperty.Ptype
|
|
150
|
+
ontology_id: Optional[str] = None
|
|
151
|
+
if jsonld_obj.get(owl_iri + ":onProperty") is None:
|
|
152
|
+
raise BaseError("No property IRI given")
|
|
153
|
+
p = jsonld_obj[owl_iri + ":onProperty"].get("@id")
|
|
154
|
+
if p is None:
|
|
155
|
+
raise BaseError("No property IRI given")
|
|
156
|
+
pp = p.split(":")
|
|
157
|
+
if pp[0] == rdf_iri or pp[0] == rdfs_iri or pp[0] == owl_iri:
|
|
158
|
+
ptype = HasProperty.Ptype.system
|
|
159
|
+
elif pp[0] == knora_api_iri:
|
|
160
|
+
ptype = HasProperty.Ptype.knora
|
|
161
|
+
else:
|
|
162
|
+
ptype = HasProperty.Ptype.other
|
|
163
|
+
ontology_id = context.iri_from_prefix(pp[0])
|
|
164
|
+
property_id = p
|
|
165
|
+
return ontology_id, property_id, ptype
|
|
166
|
+
|
|
167
|
+
@staticmethod
|
|
168
|
+
def _fromJsonObj_get_cardinality(jsonld_obj: dict[str, Any], owl_iri: str):
|
|
169
|
+
cardinality: Cardinality
|
|
170
|
+
if jsonld_obj.get(owl_iri + ":cardinality") is not None:
|
|
171
|
+
cardinality = Cardinality.C_1
|
|
172
|
+
elif jsonld_obj.get(owl_iri + ":maxCardinality") is not None:
|
|
173
|
+
cardinality = Cardinality.C_0_1
|
|
174
|
+
elif jsonld_obj.get(owl_iri + ":minCardinality") is not None:
|
|
175
|
+
if jsonld_obj.get(owl_iri + ":minCardinality") == 0:
|
|
176
|
+
cardinality = Cardinality.C_0_n
|
|
177
|
+
elif jsonld_obj.get(owl_iri + ":minCardinality") == 1:
|
|
178
|
+
cardinality = Cardinality.C_1_n
|
|
179
|
+
else:
|
|
180
|
+
raise BaseError("Problem with cardinality")
|
|
181
|
+
else:
|
|
182
|
+
raise BaseError("Problem with cardinality")
|
|
183
|
+
return cardinality
|
|
184
|
+
|
|
185
|
+
def create(self, last_modification_date: DateTimeStamp) -> tuple[DateTimeStamp, ResourceClass]:
|
|
186
|
+
if self._ontology_id is None:
|
|
187
|
+
raise BaseError("Ontology id required")
|
|
188
|
+
if self._property_id is None:
|
|
189
|
+
raise BaseError("Property id required")
|
|
190
|
+
if self._cardinality is None:
|
|
191
|
+
raise BaseError("Cardinality id required")
|
|
192
|
+
|
|
193
|
+
jsonobj = self._toJsonObj_create(last_modification_date)
|
|
194
|
+
result = self._con.post(HasProperty.ROUTE, jsonobj)
|
|
195
|
+
last_modification_date = DateTimeStamp(result["knora-api:lastModificationDate"])
|
|
196
|
+
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result["@graph"])
|
|
197
|
+
|
|
198
|
+
def update(self, last_modification_date: DateTimeStamp) -> tuple[DateTimeStamp, ResourceClass]:
|
|
199
|
+
if self._ontology_id is None:
|
|
200
|
+
raise BaseError("Ontology id required")
|
|
201
|
+
if self._property_id is None:
|
|
202
|
+
raise BaseError("Property id required")
|
|
203
|
+
if self._cardinality is None:
|
|
204
|
+
raise BaseError("Cardinality id required")
|
|
205
|
+
jsonobj = self._toJsonObj_update(last_modification_date)
|
|
206
|
+
result = self._con.put(HasProperty.ROUTE, jsonobj)
|
|
207
|
+
last_modification_date = DateTimeStamp(result["knora-api:lastModificationDate"])
|
|
208
|
+
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result["@graph"])
|
|
209
|
+
|
|
210
|
+
def _toJsonObj_update(self, lastModificationDate: DateTimeStamp) -> dict[str, Any]:
|
|
211
|
+
occurrence = self._toJsonObj_get_owl_cardinality()
|
|
212
|
+
tmp = {
|
|
213
|
+
"@id": self._ontology_id,
|
|
214
|
+
"@type": "owl:Ontology",
|
|
215
|
+
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
216
|
+
"@graph": [
|
|
217
|
+
{
|
|
218
|
+
"@id": self._resclass_id,
|
|
219
|
+
"@type": "owl:Class",
|
|
220
|
+
"rdfs:subClassOf": {
|
|
221
|
+
"@type": "owl:Restriction",
|
|
222
|
+
occurrence[0]: occurrence[1],
|
|
223
|
+
"owl:onProperty": {"@id": self._property_id},
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
"@context": self._context.toJsonObj(),
|
|
228
|
+
}
|
|
229
|
+
if self._gui_order is not None and "gui_order" in self._changed:
|
|
230
|
+
tmp["@graph"][0]["rdfs:subClassOf"]["salsah-gui:guiOrder"] = self._gui_order
|
|
231
|
+
return tmp
|
|
232
|
+
|
|
233
|
+
def _toJsonObj_create(self, lastModificationDate: DateTimeStamp) -> dict[str, Any]:
|
|
234
|
+
occurrence = self._toJsonObj_get_owl_cardinality()
|
|
235
|
+
tmp = {
|
|
236
|
+
"@id": self._ontology_id,
|
|
237
|
+
"@type": "owl:Ontology",
|
|
238
|
+
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
239
|
+
"@graph": [
|
|
240
|
+
{
|
|
241
|
+
"@id": self._resclass_id,
|
|
242
|
+
"@type": "owl:Class",
|
|
243
|
+
"rdfs:subClassOf": {
|
|
244
|
+
"@type": "owl:Restriction",
|
|
245
|
+
occurrence[0]: occurrence[1],
|
|
246
|
+
"owl:onProperty": {"@id": self._property_id},
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
"@context": self._context.toJsonObj(),
|
|
251
|
+
}
|
|
252
|
+
if self._gui_order is not None:
|
|
253
|
+
tmp["@graph"][0]["rdfs:subClassOf"]["salsah-gui:guiOrder"] = self._gui_order
|
|
254
|
+
return tmp
|
|
255
|
+
|
|
256
|
+
def _toJsonObj_get_owl_cardinality(self) -> tuple[str, int]:
|
|
257
|
+
if self._cardinality is None:
|
|
258
|
+
raise BaseError("There must be a cardinality given!")
|
|
259
|
+
switcher = {
|
|
260
|
+
Cardinality.C_1: ("owl:cardinality", 1),
|
|
261
|
+
Cardinality.C_0_1: ("owl:maxCardinality", 1),
|
|
262
|
+
Cardinality.C_0_n: ("owl:minCardinality", 0),
|
|
263
|
+
Cardinality.C_1_n: ("owl:minCardinality", 1),
|
|
264
|
+
}
|
|
265
|
+
return switcher.get(self._cardinality)
|
|
266
|
+
|
|
267
|
+
def createDefinitionFileObj(self, context: Context, shortname: str) -> dict[str, Any]:
|
|
268
|
+
cardinality = {}
|
|
269
|
+
if self._ptype == HasProperty.Ptype.other or self.property_id in [
|
|
270
|
+
"knora-api:isPartOf",
|
|
271
|
+
"knora-api:seqnum",
|
|
272
|
+
]:
|
|
273
|
+
cardinality["propname"] = context.reduce_iri(self._property_id, shortname)
|
|
274
|
+
cardinality["cardinality"] = self._cardinality.value
|
|
275
|
+
if self._gui_order is not None:
|
|
276
|
+
cardinality["gui_order"] = self._gui_order
|
|
277
|
+
return cardinality
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class ResourceClass(Model):
|
|
281
|
+
"""
|
|
282
|
+
This class represents a DSP resource class
|
|
283
|
+
|
|
284
|
+
Attributes
|
|
285
|
+
----------
|
|
286
|
+
|
|
287
|
+
con : Connection
|
|
288
|
+
A Connection instance to a DSP server
|
|
289
|
+
|
|
290
|
+
iri : str
|
|
291
|
+
IRI of the ResourceClass [readonly, cannot be modified after creation of instance]
|
|
292
|
+
|
|
293
|
+
name: str
|
|
294
|
+
The name of the resource class, e.g. "Book", "Person", "Portait". Usually these names start
|
|
295
|
+
with a capital letter
|
|
296
|
+
|
|
297
|
+
ontology_id: str
|
|
298
|
+
The IRI/Id of the ontology this resource class belongs to
|
|
299
|
+
|
|
300
|
+
superclasses: str, list[str]
|
|
301
|
+
This is a list of superclasses for this resource class. Usually a project specific class must at least
|
|
302
|
+
be a subclass of "Resource", but can be subclassed of any other valid resource class. In addition, external
|
|
303
|
+
ontologies may be referenced:
|
|
304
|
+
e.g.:
|
|
305
|
+
```
|
|
306
|
+
"super": "Resource"
|
|
307
|
+
|
|
308
|
+
"super": ":MySpecialTYpe"
|
|
309
|
+
|
|
310
|
+
"super": [":MySpecialType", "dcterms:BibliographicResource"]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
label: language dependent string, that is a dict like {"en": "Biblography", "de": "Literaturverzeichnis"}
|
|
314
|
+
A label (human readable name) for the resource
|
|
315
|
+
|
|
316
|
+
comment: language dependent string, that is a dict like {"en": "a comment", "de": "Ein Kommentar"}
|
|
317
|
+
A commentary to further explain what this resource class is used for
|
|
318
|
+
|
|
319
|
+
permission: str
|
|
320
|
+
The default permissions to be used if an instance of this resource class is being created
|
|
321
|
+
|
|
322
|
+
has_properties: dict[str, HasProperty]
|
|
323
|
+
Holds a dict with the property names as keys and a HasProperty instance. HasProperty holds
|
|
324
|
+
the information, how this resource class uses this property (basically the cardinality)
|
|
325
|
+
|
|
326
|
+
changed: bool
|
|
327
|
+
is set to True, if one of the fields has been chaned by the user (internal use only!)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
Methods
|
|
331
|
+
-------
|
|
332
|
+
|
|
333
|
+
getProperty: Get information about a property defined for this resource class
|
|
334
|
+
getPropertery(prop_id: str) -> HasProperty
|
|
335
|
+
returns a HasProperty-instance
|
|
336
|
+
|
|
337
|
+
addProperty: Add a new property to the resource class
|
|
338
|
+
addProperty(property_id: str, cardinality: Cardinality, last_modification_date: DateTimeStamp)
|
|
339
|
+
-> Optional[DateTimeStamp]
|
|
340
|
+
|
|
341
|
+
create: Create a new resource class on the connected server
|
|
342
|
+
|
|
343
|
+
update: Update the information of a resource class on the connected server
|
|
344
|
+
|
|
345
|
+
delete: Mark a resource class as deleted (on the connected server)
|
|
346
|
+
|
|
347
|
+
createDefinitionFileObj: Create an object suitable for jsonification that conforms the the DSP-TOOLS ontology tools
|
|
348
|
+
|
|
349
|
+
print: Print the content of this class to the console
|
|
350
|
+
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
ROUTE: str = "/v2/ontologies/classes"
|
|
354
|
+
|
|
355
|
+
_context: Context
|
|
356
|
+
_iri: str
|
|
357
|
+
_name: str
|
|
358
|
+
_ontology_id: str
|
|
359
|
+
_superclasses: list[str]
|
|
360
|
+
_label: LangString
|
|
361
|
+
_comment: LangString
|
|
362
|
+
_permissions: str
|
|
363
|
+
_has_properties: dict[str, HasProperty]
|
|
364
|
+
|
|
365
|
+
def __init__(
|
|
366
|
+
self,
|
|
367
|
+
con: Connection,
|
|
368
|
+
context: Context,
|
|
369
|
+
iri: Optional[str] = None,
|
|
370
|
+
name: Optional[str] = None,
|
|
371
|
+
ontology_id: Optional[str] = None,
|
|
372
|
+
superclasses: Optional[Sequence[Union[ResourceClass, str]]] = None,
|
|
373
|
+
label: Optional[Union[LangString, str]] = None,
|
|
374
|
+
comment: Optional[Union[LangString, str]] = None,
|
|
375
|
+
permissions: Optional[str] = None,
|
|
376
|
+
has_properties: Optional[dict[str, HasProperty]] = None,
|
|
377
|
+
):
|
|
378
|
+
"""
|
|
379
|
+
Create an instance of ResourceClass
|
|
380
|
+
|
|
381
|
+
:param con:
|
|
382
|
+
:param context:
|
|
383
|
+
:param iri:
|
|
384
|
+
:param name:
|
|
385
|
+
:param ontology_id:
|
|
386
|
+
:param superclasses:
|
|
387
|
+
:param label:
|
|
388
|
+
:param comment:
|
|
389
|
+
:param permissions:
|
|
390
|
+
:param has_properties:
|
|
391
|
+
"""
|
|
392
|
+
super().__init__(con)
|
|
393
|
+
self._context = context
|
|
394
|
+
self._iri = iri
|
|
395
|
+
self._name = name
|
|
396
|
+
if ontology_id is not None:
|
|
397
|
+
self._ontology_id = context.iri_from_prefix(ontology_id)
|
|
398
|
+
if isinstance(superclasses, ResourceClass):
|
|
399
|
+
self._superclasses = list(map(lambda a: a.iri, superclasses))
|
|
400
|
+
else:
|
|
401
|
+
self._superclasses = superclasses
|
|
402
|
+
|
|
403
|
+
self._label = self._check_process_langstring(label, "label")
|
|
404
|
+
self._comment = self._check_process_langstring(comment, "comment")
|
|
405
|
+
self._permissions = permissions
|
|
406
|
+
self._has_properties = has_properties
|
|
407
|
+
self._changed = set()
|
|
408
|
+
|
|
409
|
+
@staticmethod
|
|
410
|
+
def _check_process_langstring(langstring_to_check: None | str | LangString, what: str) -> LangString:
|
|
411
|
+
if langstring_to_check is not None:
|
|
412
|
+
if isinstance(langstring_to_check, str):
|
|
413
|
+
return LangString(langstring_to_check)
|
|
414
|
+
elif isinstance(langstring_to_check, LangString):
|
|
415
|
+
return langstring_to_check
|
|
416
|
+
else:
|
|
417
|
+
raise BaseError(f"Invalid LangString for {what}!")
|
|
418
|
+
else:
|
|
419
|
+
return LangString({})
|
|
420
|
+
|
|
421
|
+
#
|
|
422
|
+
# Here follows a list of getters/setters
|
|
423
|
+
#
|
|
424
|
+
@property
|
|
425
|
+
def name(self) -> Optional[str]:
|
|
426
|
+
return self._name
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def iri(self) -> Optional[str]:
|
|
430
|
+
return self._iri
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def ontology_id(self) -> Optional[str]:
|
|
434
|
+
return self._ontology_id
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def superclasses(self) -> Optional[list[str]]:
|
|
438
|
+
return self._superclasses
|
|
439
|
+
|
|
440
|
+
@property
|
|
441
|
+
def label(self) -> LangString:
|
|
442
|
+
return self._label
|
|
443
|
+
|
|
444
|
+
@label.setter
|
|
445
|
+
def label(self, value: Optional[Union[LangString, str]]) -> None:
|
|
446
|
+
if value is None:
|
|
447
|
+
self._label.empty() # clear all labels
|
|
448
|
+
elif isinstance(value, LangString):
|
|
449
|
+
self._label = value
|
|
450
|
+
elif isinstance(value, str):
|
|
451
|
+
self._label = LangString(value)
|
|
452
|
+
else:
|
|
453
|
+
raise BaseError("Not a valid LangString")
|
|
454
|
+
self._changed.add("label")
|
|
455
|
+
|
|
456
|
+
@property
|
|
457
|
+
def comment(self) -> LangString:
|
|
458
|
+
return self._comment
|
|
459
|
+
|
|
460
|
+
@comment.setter
|
|
461
|
+
def comment(self, value: Optional[LangString]) -> None:
|
|
462
|
+
if value is None:
|
|
463
|
+
self._comment.empty() # clear all comments!
|
|
464
|
+
elif isinstance(value, LangString):
|
|
465
|
+
self._comment = value
|
|
466
|
+
elif isinstance(value, str):
|
|
467
|
+
self._comment = LangString(value)
|
|
468
|
+
else:
|
|
469
|
+
raise BaseError("Not a valid LangString")
|
|
470
|
+
self._changed.add("comment")
|
|
471
|
+
|
|
472
|
+
@property
|
|
473
|
+
def permissions(self) -> Optional[str]:
|
|
474
|
+
return self._permissions
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def has_properties(self) -> dict[str, HasProperty]:
|
|
478
|
+
return self._has_properties
|
|
479
|
+
|
|
480
|
+
@classmethod
|
|
481
|
+
def fromJsonObj(cls, con: Connection, context: Context, json_obj: Any) -> ResourceClass:
|
|
482
|
+
if isinstance(json_obj, list):
|
|
483
|
+
json_obj = json_obj[0]
|
|
484
|
+
rdfs = context.prefix_from_iri("http://www.w3.org/2000/01/rdf-schema#")
|
|
485
|
+
owl = context.prefix_from_iri("http://www.w3.org/2002/07/owl#")
|
|
486
|
+
knora_api = context.prefix_from_iri("http://api.knora.org/ontology/knora-api/v2#")
|
|
487
|
+
|
|
488
|
+
if not (json_obj.get(knora_api + ":isResourceClass") or json_obj.get(knora_api + ":isStandoffClass")):
|
|
489
|
+
raise BaseError("This is not a resource!")
|
|
490
|
+
|
|
491
|
+
if json_obj.get("@id") is None:
|
|
492
|
+
raise BaseError('Resource class has no "@id"!')
|
|
493
|
+
|
|
494
|
+
tmp_id = json_obj.get("@id").split(":")
|
|
495
|
+
iri = context.iri_from_prefix(tmp_id[0]) + "#" + tmp_id[1]
|
|
496
|
+
ontology_id = tmp_id[0]
|
|
497
|
+
name = tmp_id[1]
|
|
498
|
+
|
|
499
|
+
has_properties, superclasses = cls._fromJsonObj_get_superclass(con, context, json_obj, rdfs, owl)
|
|
500
|
+
|
|
501
|
+
label = LangString.fromJsonLdObj(json_obj.get(rdfs + ":label"))
|
|
502
|
+
comment = LangString.fromJsonLdObj(json_obj.get(rdfs + ":comment"))
|
|
503
|
+
return cls(
|
|
504
|
+
con=con,
|
|
505
|
+
context=context,
|
|
506
|
+
name=name,
|
|
507
|
+
iri=iri,
|
|
508
|
+
ontology_id=ontology_id,
|
|
509
|
+
superclasses=superclasses,
|
|
510
|
+
label=label,
|
|
511
|
+
comment=comment,
|
|
512
|
+
has_properties=has_properties,
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
@staticmethod
|
|
516
|
+
def _fromJsonObj_get_superclass(
|
|
517
|
+
con: Connection, context: Context, json_obj: dict[str, Any], rdfs: str, owl: str
|
|
518
|
+
) -> tuple[None | dict[str, HasProperty], None | list[str]]:
|
|
519
|
+
superclasses_obj = json_obj.get(rdfs + ":subClassOf")
|
|
520
|
+
if superclasses_obj is not None:
|
|
521
|
+
supercls = list(filter(lambda a: a.get("@id") is not None, superclasses_obj))
|
|
522
|
+
superclasses = list(map(lambda a: a["@id"], supercls))
|
|
523
|
+
has_props = list(filter(lambda a: a.get("@type") == (owl + ":Restriction"), superclasses_obj))
|
|
524
|
+
has_properties = dict(map(lambda a: HasProperty.fromJsonObj(con, context, a), has_props))
|
|
525
|
+
#
|
|
526
|
+
# now remove the ...Value stuff from resource pointers: A resource pointer is returned as 2 properties:
|
|
527
|
+
# one a direct link, the other the pointer to a link value
|
|
528
|
+
#
|
|
529
|
+
tmp = dict(has_properties)
|
|
530
|
+
for key in tmp.keys():
|
|
531
|
+
if key.endswith("Value"):
|
|
532
|
+
key_without_value = key.removesuffix("Value")
|
|
533
|
+
if key_without_value in has_properties:
|
|
534
|
+
del has_properties[key]
|
|
535
|
+
else:
|
|
536
|
+
superclasses = None
|
|
537
|
+
has_properties = None
|
|
538
|
+
return has_properties, superclasses
|
|
539
|
+
|
|
540
|
+
def create(self, last_modification_date: DateTimeStamp) -> tuple[DateTimeStamp, ResourceClass]:
|
|
541
|
+
jsonobj = self._toJsonObj_create(last_modification_date)
|
|
542
|
+
result = self._con.post(ResourceClass.ROUTE, jsonobj)
|
|
543
|
+
last_modification_date = DateTimeStamp(result["knora-api:lastModificationDate"])
|
|
544
|
+
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result["@graph"])
|
|
545
|
+
|
|
546
|
+
def update(self, last_modification_date: DateTimeStamp) -> tuple[DateTimeStamp, ResourceClass]:
|
|
547
|
+
#
|
|
548
|
+
# Note: DSP is able to change only one thing per call, either label or comment!
|
|
549
|
+
#
|
|
550
|
+
result = None
|
|
551
|
+
something_changed = False
|
|
552
|
+
if "label" in self._changed:
|
|
553
|
+
jsonobj = self._toJsonObj_update(last_modification_date, "label")
|
|
554
|
+
result = self._con.put(ResourceClass.ROUTE, jsonobj)
|
|
555
|
+
last_modification_date = DateTimeStamp(result["knora-api:lastModificationDate"])
|
|
556
|
+
something_changed = True
|
|
557
|
+
if "comment" in self._changed:
|
|
558
|
+
jsonobj = self._toJsonObj_update(last_modification_date, "comment")
|
|
559
|
+
result = self._con.put(ResourceClass.ROUTE, jsonobj)
|
|
560
|
+
last_modification_date = DateTimeStamp(result["knora-api:lastModificationDate"])
|
|
561
|
+
something_changed = True
|
|
562
|
+
if something_changed:
|
|
563
|
+
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result["@graph"])
|
|
564
|
+
else:
|
|
565
|
+
return last_modification_date, self
|
|
566
|
+
|
|
567
|
+
def _toJsonObj_update(self, lastModificationDate: DateTimeStamp, what_changed: str) -> dict[str, Any]:
|
|
568
|
+
ontid, resid = self._get_onto_res_iri()
|
|
569
|
+
tmp = {
|
|
570
|
+
"@id": ontid, # self._ontology_id,
|
|
571
|
+
"@type": "owl:Ontology",
|
|
572
|
+
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
573
|
+
"@graph": [
|
|
574
|
+
{
|
|
575
|
+
"@id": resid,
|
|
576
|
+
"@type": "owl:Class",
|
|
577
|
+
}
|
|
578
|
+
],
|
|
579
|
+
"@context": self._context.toJsonObj(),
|
|
580
|
+
}
|
|
581
|
+
if what_changed == "label":
|
|
582
|
+
if not self._label.isEmpty() and "label" in self._changed:
|
|
583
|
+
tmp["@graph"][0]["rdfs:label"] = self._label.toJsonLdObj()
|
|
584
|
+
if what_changed == "comment":
|
|
585
|
+
if not self._comment.isEmpty() and "comment" in self._changed:
|
|
586
|
+
tmp["@graph"][0]["rdfs:comment"] = self._comment.toJsonLdObj()
|
|
587
|
+
return tmp
|
|
588
|
+
|
|
589
|
+
def _toJsonObj_create(self, lastModificationDate: DateTimeStamp) -> dict[str, Any]:
|
|
590
|
+
ontid, resid = self._get_onto_res_iri()
|
|
591
|
+
if self._name is None:
|
|
592
|
+
raise BaseError("There must be a valid resource class name!")
|
|
593
|
+
if self._ontology_id is None:
|
|
594
|
+
raise BaseError("There must be a valid ontology_id given!")
|
|
595
|
+
if self._superclasses is None:
|
|
596
|
+
superclasses = [{"@id": "knora-api:Resource"}]
|
|
597
|
+
else:
|
|
598
|
+
superclasses = list(map(self._resolve_resref, self._superclasses))
|
|
599
|
+
if self._label is None or self._label.isEmpty():
|
|
600
|
+
self._label = LangString("no label available")
|
|
601
|
+
tmp = {
|
|
602
|
+
"@id": ontid, # self._ontology_id,
|
|
603
|
+
"@type": "owl:Ontology",
|
|
604
|
+
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
605
|
+
"@graph": [
|
|
606
|
+
{
|
|
607
|
+
"@id": resid,
|
|
608
|
+
"@type": "owl:Class",
|
|
609
|
+
"rdfs:label": self._label.toJsonLdObj(),
|
|
610
|
+
"rdfs:subClassOf": superclasses,
|
|
611
|
+
}
|
|
612
|
+
],
|
|
613
|
+
"@context": self._context.toJsonObj(),
|
|
614
|
+
}
|
|
615
|
+
if self._comment:
|
|
616
|
+
tmp["@graph"][0]["rdfs:comment"] = self._comment.toJsonLdObj()
|
|
617
|
+
return tmp
|
|
618
|
+
|
|
619
|
+
def _get_onto_res_iri(self) -> tuple[str, str]:
|
|
620
|
+
exp = regex.compile("^http.*") # It is already a fully IRI
|
|
621
|
+
if exp.match(self._ontology_id):
|
|
622
|
+
resid = self._context.prefix_from_iri(self._ontology_id) + ":" + self._name
|
|
623
|
+
ontid = self._ontology_id
|
|
624
|
+
else:
|
|
625
|
+
resid = self._ontology_id + ":" + self._name
|
|
626
|
+
ontid = self._context.iri_from_prefix(self._ontology_id)
|
|
627
|
+
return ontid, resid
|
|
628
|
+
|
|
629
|
+
def _resolve_resref(self, resref: str) -> dict[str, str]:
|
|
630
|
+
tmp = resref.split(":")
|
|
631
|
+
if len(tmp) > 1:
|
|
632
|
+
if tmp[0] and self._context.iri_from_prefix(tmp[0]) != self._ontology_id:
|
|
633
|
+
self._context.add_context(tmp[0])
|
|
634
|
+
return {"@id": resref} # fully qualified name in the form "prefix:name"
|
|
635
|
+
else:
|
|
636
|
+
return {
|
|
637
|
+
"@id": self._context.prefix_from_iri(self._ontology_id) + ":" + tmp[1]
|
|
638
|
+
} # ":name" in current ontology
|
|
639
|
+
else:
|
|
640
|
+
return {"@id": "knora-api:" + resref} # no ":", must be from knora-api!
|
|
641
|
+
|
|
642
|
+
def createDefinitionFileObj(self, context: Context, shortname: str, skiplist: list[str]) -> dict[str, Any]:
|
|
643
|
+
resource = {"name": self._name}
|
|
644
|
+
if self._superclasses:
|
|
645
|
+
resource["super"] = self._create_DefinitionFileObj_superclass(context, shortname)
|
|
646
|
+
resource["labels"] = self._label.createDefinitionFileObj()
|
|
647
|
+
if not self._comment.isEmpty():
|
|
648
|
+
resource["comments"] = self._comment.createDefinitionFileObj()
|
|
649
|
+
if self._has_properties:
|
|
650
|
+
self._create_DefinitionFileObj_cardinalities(context, resource, shortname, skiplist)
|
|
651
|
+
return resource
|
|
652
|
+
|
|
653
|
+
def _create_DefinitionFileObj_cardinalities(
|
|
654
|
+
self, context: Context, resource: dict[str, str], shortname: str, skiplist: list[str]
|
|
655
|
+
) -> dict[str, Any]:
|
|
656
|
+
cardinalities: list[dict[str, Any]] = []
|
|
657
|
+
for _, hp in self._has_properties.items():
|
|
658
|
+
if hp.property_id in skiplist:
|
|
659
|
+
continue
|
|
660
|
+
if hp.ptype == HasProperty.Ptype.other or hp.property_id in [
|
|
661
|
+
"knora-api:isPartOf",
|
|
662
|
+
"knora-api:seqnum",
|
|
663
|
+
]:
|
|
664
|
+
cardinalities.append(hp.createDefinitionFileObj(context, shortname))
|
|
665
|
+
if cardinalities:
|
|
666
|
+
resource["cardinalities"] = cardinalities
|
|
667
|
+
return resource
|
|
668
|
+
|
|
669
|
+
def _create_DefinitionFileObj_superclass(self, context: Context, shortname: str) -> list[str] | str:
|
|
670
|
+
if len(self._superclasses) > 1:
|
|
671
|
+
superclasses = []
|
|
672
|
+
for sc in self._superclasses:
|
|
673
|
+
superclasses.append(context.reduce_iri(sc, shortname))
|
|
674
|
+
else:
|
|
675
|
+
superclasses = context.reduce_iri(self._superclasses[0], shortname)
|
|
676
|
+
return superclasses
|