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
|
@@ -1,811 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import re
|
|
3
|
-
from pystrict import strict
|
|
4
|
-
from typing import List, Set, Dict, Tuple, Optional, Any, Union
|
|
5
|
-
from enum import Enum
|
|
6
|
-
from urllib.parse import quote_plus
|
|
7
|
-
|
|
8
|
-
from pprint import pprint
|
|
9
|
-
|
|
10
|
-
from .helpers import Actions, BaseError, Context, Cardinality, LastModificationDate
|
|
11
|
-
from .connection import Connection
|
|
12
|
-
from .model import Model
|
|
13
|
-
from .langstring import Languages, LangString
|
|
14
|
-
|
|
15
|
-
class SetEncoder(json.JSONEncoder):
|
|
16
|
-
def default(self, obj):
|
|
17
|
-
if isinstance(obj, set):
|
|
18
|
-
return list(obj)
|
|
19
|
-
return json.JSONEncoder.default(self, obj)
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
This model implements the handling of resource classes. It contains two classes that work closely together:
|
|
23
|
-
* "HasProperty" deals with the association of Property-instances with the Resource-instances. This association
|
|
24
|
-
is done using the "cardinality"-clause
|
|
25
|
-
* "ResourceClass" is the main class representing a knora resource class.
|
|
26
|
-
"""
|
|
27
|
-
@strict
|
|
28
|
-
class HasProperty(Model):
|
|
29
|
-
class Ptype(Enum):
|
|
30
|
-
system = 1
|
|
31
|
-
knora = 2
|
|
32
|
-
other = 3
|
|
33
|
-
|
|
34
|
-
_context: Context
|
|
35
|
-
_ontology_id: str
|
|
36
|
-
_property_id: str
|
|
37
|
-
_resclass_id: str
|
|
38
|
-
_cardinality: Cardinality
|
|
39
|
-
_gui_order: int
|
|
40
|
-
_is_inherited: bool
|
|
41
|
-
_ptype: Ptype
|
|
42
|
-
|
|
43
|
-
def __init__(self,
|
|
44
|
-
con: Connection,
|
|
45
|
-
context: Context,
|
|
46
|
-
ontology_id: Optional[str] = None,
|
|
47
|
-
property_id: Optional[str] = None,
|
|
48
|
-
resclass_id: Optional[str] = None,
|
|
49
|
-
cardinality: Optional[Cardinality] = None,
|
|
50
|
-
gui_order: Optional[int] = None,
|
|
51
|
-
is_inherited: Optional[bool] = None,
|
|
52
|
-
ptype: Optional[Ptype] = None):
|
|
53
|
-
super().__init__(con)
|
|
54
|
-
if not isinstance(context, Context):
|
|
55
|
-
raise BaseError('"context"-parameter must be an instance of Context')
|
|
56
|
-
self._context = context
|
|
57
|
-
if ontology_id is not None:
|
|
58
|
-
self._ontology_id = context.iri_from_prefix(ontology_id)
|
|
59
|
-
else:
|
|
60
|
-
self._ontology_id = None
|
|
61
|
-
self._property_id = property_id
|
|
62
|
-
self._resclass_id = resclass_id
|
|
63
|
-
self._cardinality = cardinality
|
|
64
|
-
self._gui_order = gui_order
|
|
65
|
-
self._is_inherited = is_inherited
|
|
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_id.setter
|
|
85
|
-
def property_id(self, value: str) -> None:
|
|
86
|
-
raise BaseError('property_id "{}" cannot be modified!'.format(self._property_id))
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def resclass_id(self) -> Optional[str]:
|
|
90
|
-
return self._resclass_id
|
|
91
|
-
|
|
92
|
-
@resclass_id.setter
|
|
93
|
-
def resclass_id(self, value: Optional[str]) -> None:
|
|
94
|
-
self._resclass_id = value
|
|
95
|
-
|
|
96
|
-
@property
|
|
97
|
-
def cardinality(self) -> Optional[Cardinality]:
|
|
98
|
-
return self._cardinality
|
|
99
|
-
|
|
100
|
-
@cardinality.setter
|
|
101
|
-
def cardinality(self, value: Optional[Cardinality]) -> None:
|
|
102
|
-
self._cardinality = value
|
|
103
|
-
self._changed.add('cardinality')
|
|
104
|
-
|
|
105
|
-
@property
|
|
106
|
-
def gui_order(self) -> Optional[int]:
|
|
107
|
-
return self._gui_order
|
|
108
|
-
|
|
109
|
-
@gui_order.setter
|
|
110
|
-
def gui_order(self, value: int) -> None:
|
|
111
|
-
self._gui_order = value
|
|
112
|
-
self._changed.add('gui_order')
|
|
113
|
-
|
|
114
|
-
@property
|
|
115
|
-
def ptype(self) -> Ptype:
|
|
116
|
-
return self._ptype
|
|
117
|
-
|
|
118
|
-
@classmethod
|
|
119
|
-
def fromJsonObj(cls, con: Connection, context: Context, jsonld_obj: Any) -> Tuple[str, 'HasProperty']:
|
|
120
|
-
if not isinstance(con, Connection):
|
|
121
|
-
raise BaseError('"con"-parameter must be an instance of Connection')
|
|
122
|
-
if not isinstance(context, Context):
|
|
123
|
-
raise BaseError('"context"-parameter must be an instance of Context')
|
|
124
|
-
|
|
125
|
-
rdf = context.prefix_from_iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
|
126
|
-
rdfs = context.prefix_from_iri("http://www.w3.org/2000/01/rdf-schema#")
|
|
127
|
-
owl = context.prefix_from_iri("http://www.w3.org/2002/07/owl#")
|
|
128
|
-
xsd = context.prefix_from_iri("http://www.w3.org/2001/XMLSchema#")
|
|
129
|
-
knora_api = context.prefix_from_iri("http://api.knora.org/ontology/knora-api/v2#")
|
|
130
|
-
salsah_gui = context.prefix_from_iri("http://api.knora.org/ontology/salsah-gui/v2#")
|
|
131
|
-
|
|
132
|
-
if jsonld_obj.get('@type') is None or jsonld_obj.get('@type') != owl + ":Restriction":
|
|
133
|
-
raise BaseError('Expected restriction type')
|
|
134
|
-
|
|
135
|
-
#
|
|
136
|
-
# let's get the inherited field...
|
|
137
|
-
#
|
|
138
|
-
tmp = jsonld_obj.get(knora_api + ':isInherited')
|
|
139
|
-
is_inherited = tmp if tmp is not None else False
|
|
140
|
-
|
|
141
|
-
#
|
|
142
|
-
# let's get the cardinality
|
|
143
|
-
#
|
|
144
|
-
cardinality: Cardinality
|
|
145
|
-
if jsonld_obj.get(owl + ':cardinality') is not None:
|
|
146
|
-
cardinality = Cardinality.C_1
|
|
147
|
-
elif jsonld_obj.get(owl + ':maxCardinality') is not None:
|
|
148
|
-
cardinality = Cardinality.C_0_1
|
|
149
|
-
elif jsonld_obj.get(owl + ':minCardinality') is not None:
|
|
150
|
-
if jsonld_obj.get(owl + ':minCardinality') == 0:
|
|
151
|
-
cardinality = Cardinality.C_0_n
|
|
152
|
-
elif jsonld_obj.get(owl + ':minCardinality') == 1:
|
|
153
|
-
cardinality = Cardinality.C_1_n
|
|
154
|
-
else:
|
|
155
|
-
raise BaseError('Problem with cardinality')
|
|
156
|
-
else:
|
|
157
|
-
raise BaseError('Problem with cardinality')
|
|
158
|
-
|
|
159
|
-
#
|
|
160
|
-
# Now let's get the property IRI
|
|
161
|
-
#
|
|
162
|
-
property_id: str
|
|
163
|
-
ptype: HasProperty.Ptype
|
|
164
|
-
ontology_id: Optional[str] = None
|
|
165
|
-
if jsonld_obj.get(owl + ':onProperty') is None:
|
|
166
|
-
raise BaseError('No property IRI given')
|
|
167
|
-
p = jsonld_obj[owl + ':onProperty'].get('@id')
|
|
168
|
-
if p is None:
|
|
169
|
-
raise BaseError('No property IRI given')
|
|
170
|
-
pp = p.split(':')
|
|
171
|
-
if pp[0] == rdf or pp[0] == rdfs or pp[0] == owl:
|
|
172
|
-
ptype = HasProperty.Ptype.system
|
|
173
|
-
elif pp[0] == knora_api:
|
|
174
|
-
ptype = HasProperty.Ptype.knora
|
|
175
|
-
else:
|
|
176
|
-
ptype = HasProperty.Ptype.other
|
|
177
|
-
ontology_id = context.iri_from_prefix(pp[0])
|
|
178
|
-
property_id = p
|
|
179
|
-
|
|
180
|
-
gui_order: int = None
|
|
181
|
-
if jsonld_obj.get(salsah_gui + ':guiOrder') is not None:
|
|
182
|
-
gui_order = jsonld_obj[salsah_gui + ':guiOrder']
|
|
183
|
-
return property_id, cls(con=con,
|
|
184
|
-
context=context,
|
|
185
|
-
ontology_id=ontology_id,
|
|
186
|
-
property_id=property_id,
|
|
187
|
-
cardinality=cardinality,
|
|
188
|
-
gui_order=gui_order,
|
|
189
|
-
is_inherited=is_inherited,
|
|
190
|
-
ptype=ptype)
|
|
191
|
-
|
|
192
|
-
def toJsonObj(self, lastModificationDate: LastModificationDate, action: Actions) -> Any:
|
|
193
|
-
if self._cardinality is None:
|
|
194
|
-
raise BaseError("There must be a cardinality given!")
|
|
195
|
-
tmp = {}
|
|
196
|
-
switcher = {
|
|
197
|
-
Cardinality.C_1: ("owl:cardinality", 1),
|
|
198
|
-
Cardinality.C_0_1: ("owl:maxCardinality", 1),
|
|
199
|
-
Cardinality.C_0_n: ("owl:minCardinality", 0),
|
|
200
|
-
Cardinality.C_1_n: ("owl:minCardinality", 1)
|
|
201
|
-
}
|
|
202
|
-
occurrence = switcher.get(self._cardinality)
|
|
203
|
-
if action == Actions.Create:
|
|
204
|
-
tmp = {
|
|
205
|
-
"@id": self._ontology_id,
|
|
206
|
-
"@type": "owl:Ontology",
|
|
207
|
-
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
208
|
-
"@graph": [{
|
|
209
|
-
"@id": self._resclass_id,
|
|
210
|
-
"@type": "owl:Class",
|
|
211
|
-
"rdfs:subClassOf": {
|
|
212
|
-
"@type": "owl:Restriction",
|
|
213
|
-
occurrence[0]: occurrence[1],
|
|
214
|
-
"owl:onProperty": {
|
|
215
|
-
"@id": self._property_id
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}],
|
|
219
|
-
"@context": self._context.toJsonObj()
|
|
220
|
-
}
|
|
221
|
-
if self._gui_order is not None:
|
|
222
|
-
tmp["@graph"][0]["rdfs:subClassOf"]["salsah-gui:guiOrder"] = self._gui_order
|
|
223
|
-
elif action == Actions.Update:
|
|
224
|
-
tmp = {
|
|
225
|
-
"@id": self._ontology_id,
|
|
226
|
-
"@type": "owl:Ontology",
|
|
227
|
-
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
228
|
-
"@graph": [{
|
|
229
|
-
"@id": self._resclass_id,
|
|
230
|
-
"@type": "owl:Class",
|
|
231
|
-
"rdfs:subClassOf": {
|
|
232
|
-
"@type": "owl:Restriction",
|
|
233
|
-
occurrence[0]: occurrence[1],
|
|
234
|
-
"owl:onProperty": {
|
|
235
|
-
"@id": self._property_id
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}],
|
|
239
|
-
"@context": self._context.toJsonObj()
|
|
240
|
-
}
|
|
241
|
-
if self._gui_order is not None and 'gui_order' in self._changed:
|
|
242
|
-
tmp["@graph"][0]["rdfs:subClassOf"]["salsah-gui:guiOrder"] = self._gui_order
|
|
243
|
-
return tmp
|
|
244
|
-
|
|
245
|
-
def create(self, last_modification_date: LastModificationDate) -> Tuple[LastModificationDate, 'ResourceClass']:
|
|
246
|
-
if self._ontology_id is None:
|
|
247
|
-
raise BaseError("Ontology id required")
|
|
248
|
-
if self._property_id is None:
|
|
249
|
-
raise BaseError("Property id required")
|
|
250
|
-
if self._cardinality is None:
|
|
251
|
-
raise BaseError("Cardinality id required")
|
|
252
|
-
|
|
253
|
-
jsonobj = self.toJsonObj(last_modification_date, Actions.Create)
|
|
254
|
-
jsondata = json.dumps(jsonobj, cls=SetEncoder, indent=2)
|
|
255
|
-
result = self._con.post('/v2/ontologies/cardinalities', jsondata)
|
|
256
|
-
last_modification_date = LastModificationDate(result['knora-api:lastModificationDate'])
|
|
257
|
-
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result['@graph'])
|
|
258
|
-
|
|
259
|
-
def update(self, last_modification_date: LastModificationDate) -> Tuple[LastModificationDate, 'ResourceClass']:
|
|
260
|
-
if self._ontology_id is None:
|
|
261
|
-
raise BaseError("Ontology id required")
|
|
262
|
-
if self._property_id is None:
|
|
263
|
-
raise BaseError("Property id required")
|
|
264
|
-
if self._cardinality is None:
|
|
265
|
-
raise BaseError("Cardinality id required")
|
|
266
|
-
jsonobj = self.toJsonObj(last_modification_date, Actions.Update)
|
|
267
|
-
jsondata = json.dumps(jsonobj, indent=3, cls=SetEncoder)
|
|
268
|
-
result = self._con.put('/v2/ontologies/cardinalities', jsondata)
|
|
269
|
-
last_modification_date = LastModificationDate(result['knora-api:lastModificationDate'])
|
|
270
|
-
# TODO: self._changed = str()
|
|
271
|
-
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result['@graph'])
|
|
272
|
-
|
|
273
|
-
def delete(self, last_modification_date: LastModificationDate) -> LastModificationDate:
|
|
274
|
-
raise BaseError("Cannot remove a single property from a class!")
|
|
275
|
-
# ToDo: Check with Ben if we could add this feature...
|
|
276
|
-
|
|
277
|
-
def createDefinitionFileObj(self, context: Context, shortname: str):
|
|
278
|
-
cardinality = {}
|
|
279
|
-
if self._ptype == HasProperty.Ptype.other:
|
|
280
|
-
cardinality["propname"] = context.reduce_iri(self._property_id, shortname)
|
|
281
|
-
cardinality["cardinality"] = self._cardinality.value
|
|
282
|
-
if self._gui_order is not None:
|
|
283
|
-
cardinality["gui_order"] = self._gui_order
|
|
284
|
-
return cardinality
|
|
285
|
-
|
|
286
|
-
def print(self, offset: int = 0):
|
|
287
|
-
blank = ' '
|
|
288
|
-
if self._ptype == HasProperty.Ptype.system:
|
|
289
|
-
print(f'{blank:>{offset}}Has Property (system)')
|
|
290
|
-
elif self._ptype == HasProperty.Ptype.knora:
|
|
291
|
-
print(f'{blank:>{offset}}Has Property (knora)')
|
|
292
|
-
else:
|
|
293
|
-
print(f'{blank:>{offset}}Has Property (project)')
|
|
294
|
-
print(f'{blank:>{offset + 2}}Property: {self._property_id}')
|
|
295
|
-
print(f'{blank:>{offset + 2}}Cardinality: {self._cardinality.value}')
|
|
296
|
-
if self._ptype == HasProperty.Ptype.other:
|
|
297
|
-
print(f'{blank:>{offset + 2}}Ontology_id: {self._ontology_id}')
|
|
298
|
-
print(f'{blank:>{offset + 2}}Resclass: {self._resclass_id}')
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
@strict
|
|
302
|
-
class ResourceClass(Model):
|
|
303
|
-
"""
|
|
304
|
-
This class represents a knora resource class
|
|
305
|
-
|
|
306
|
-
Attributes
|
|
307
|
-
----------
|
|
308
|
-
|
|
309
|
-
con : Connection
|
|
310
|
-
A Connection instance to a Knora server
|
|
311
|
-
|
|
312
|
-
id : str
|
|
313
|
-
IRI of the ResourceClass [readonly, cannot be modified after creation of instance]
|
|
314
|
-
|
|
315
|
-
name: str
|
|
316
|
-
The name of the resource class, e.g. "Book", "Person", "Portait". Usually these names start
|
|
317
|
-
with a capital letter
|
|
318
|
-
|
|
319
|
-
ontology_id: str
|
|
320
|
-
The IRI/Id of the ontology this resource class belongs to
|
|
321
|
-
|
|
322
|
-
superlcasses: str, List[str]
|
|
323
|
-
This is a list of superclasses for this resource class. Usually a project specific class must at least
|
|
324
|
-
be a subclass of "Resource", but can be subclassed of any other valid resource class. In addition, external
|
|
325
|
-
ontologies may be referenced:
|
|
326
|
-
e.g.:
|
|
327
|
-
```
|
|
328
|
-
"super": "Resource"
|
|
329
|
-
|
|
330
|
-
"super": ":MySpecialTYpe"
|
|
331
|
-
|
|
332
|
-
"super": [":MySpecialType", "dcterms:BibliographicResource"]
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
label: language dependent string, that is a dict like {"en": "Biblography", "de": "Literaturverzeichnis"}
|
|
336
|
-
A label (human readable name) for the resource
|
|
337
|
-
|
|
338
|
-
comment: language dependent string, that is a dict like {"en": "a comment", "de": "Ein Kommentar"}
|
|
339
|
-
A commentary to further explain what this resource class is used for
|
|
340
|
-
|
|
341
|
-
permission: str
|
|
342
|
-
The default permissions to be used if an instance of this resource class is being created
|
|
343
|
-
|
|
344
|
-
has_properties: Dict[str, HasProperty]
|
|
345
|
-
Holds a dict with the property names as keys and a HasProperty instance. HasProperty holds
|
|
346
|
-
the information, how this resource class uses this property (basically the cardinality)
|
|
347
|
-
|
|
348
|
-
changed: bool
|
|
349
|
-
is set to True, if one of the fields has been chaned by the user (internal use only!)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
Methods
|
|
353
|
-
-------
|
|
354
|
-
|
|
355
|
-
addLabel: Add a new label to the resource
|
|
356
|
-
addLabel(self, lang: Union[Languages, str], value: str) -> None
|
|
357
|
-
|
|
358
|
-
getProperty: Get information about a property defined for this resource class
|
|
359
|
-
getPropertery(prop_id: str) -> HasProperty
|
|
360
|
-
returns a HasProperty-instance
|
|
361
|
-
|
|
362
|
-
addProperty: Add a new property to the resource class
|
|
363
|
-
addProperty(property_id: str, cardinality: Cardinality, last_modification_date: LastModificationDate)
|
|
364
|
-
-> Optional[LastModificationDate]
|
|
365
|
-
|
|
366
|
-
updateProperty: Updates the cardinality parameters of the given property with the resource class
|
|
367
|
-
updateProperty(self, property_id: str, cardinality: Cardinality, last_modification_date: LastModificationDate)
|
|
368
|
-
-> Optional[LastModificationDate]
|
|
369
|
-
Please note that the cardinality usually can only be changed to be *less* restrictive!
|
|
370
|
-
|
|
371
|
-
create: Create a new resource class on the connected server
|
|
372
|
-
|
|
373
|
-
update: Update the information of a resource class on the connected server
|
|
374
|
-
|
|
375
|
-
delete: Mark a resource class as deleted (on the connected server)
|
|
376
|
-
|
|
377
|
-
createDefinitionFileObj: Create an object suitable for jsonification that conforms the the knora-py ontology tools
|
|
378
|
-
|
|
379
|
-
print: Print the content of this class to the console
|
|
380
|
-
|
|
381
|
-
"""
|
|
382
|
-
_context: Context
|
|
383
|
-
_id: str
|
|
384
|
-
_name: str
|
|
385
|
-
_ontology_id: str
|
|
386
|
-
_superclasses: List[str]
|
|
387
|
-
_label: LangString
|
|
388
|
-
_comment: LangString
|
|
389
|
-
_permissions: str
|
|
390
|
-
_has_properties: Dict[str, HasProperty]
|
|
391
|
-
|
|
392
|
-
def __init__(self,
|
|
393
|
-
con: Connection,
|
|
394
|
-
context: Context,
|
|
395
|
-
id: Optional[str] = None,
|
|
396
|
-
name: Optional[str] = None,
|
|
397
|
-
ontology_id: Optional[str] = None,
|
|
398
|
-
superclasses: Optional[List[Union['ResourceClass', str]]] = None,
|
|
399
|
-
label: Optional[Union[LangString, str]] = None,
|
|
400
|
-
comment: Optional[Union[LangString, str]] = None,
|
|
401
|
-
permissions: Optional[str] = None,
|
|
402
|
-
has_properties: Optional[Dict[str, HasProperty]] = None):
|
|
403
|
-
"""
|
|
404
|
-
Create an instance of ResourceClass
|
|
405
|
-
|
|
406
|
-
:param con:
|
|
407
|
-
:param context:
|
|
408
|
-
:param id:
|
|
409
|
-
:param name:
|
|
410
|
-
:param ontology_id:
|
|
411
|
-
:param superclasses:
|
|
412
|
-
:param label:
|
|
413
|
-
:param comment:
|
|
414
|
-
:param permissions:
|
|
415
|
-
:param has_properties:
|
|
416
|
-
"""
|
|
417
|
-
super().__init__(con)
|
|
418
|
-
if not isinstance(con, Connection):
|
|
419
|
-
raise BaseError('"con"-parameter must be an instance of Connection')
|
|
420
|
-
if not isinstance(context, Context):
|
|
421
|
-
raise BaseError('"context"-parameter must be an instance of Context')
|
|
422
|
-
self._context = context
|
|
423
|
-
self._id = id
|
|
424
|
-
self._name = name
|
|
425
|
-
if ontology_id is not None:
|
|
426
|
-
self._ontology_id = context.iri_from_prefix(ontology_id)
|
|
427
|
-
if isinstance(superclasses, ResourceClass):
|
|
428
|
-
self._superclasses = list(map(lambda a: a.id, superclasses))
|
|
429
|
-
else:
|
|
430
|
-
self._superclasses = superclasses
|
|
431
|
-
#
|
|
432
|
-
# process label
|
|
433
|
-
#
|
|
434
|
-
if label is not None:
|
|
435
|
-
if isinstance(label, str):
|
|
436
|
-
self._label = LangString(label)
|
|
437
|
-
elif isinstance(label, LangString):
|
|
438
|
-
self._label = label
|
|
439
|
-
else:
|
|
440
|
-
raise BaseError('Invalid LangString for label!')
|
|
441
|
-
else:
|
|
442
|
-
self._label = None
|
|
443
|
-
#
|
|
444
|
-
# process comment
|
|
445
|
-
#
|
|
446
|
-
if comment is not None:
|
|
447
|
-
if isinstance(comment, str):
|
|
448
|
-
self._comment = LangString(comment)
|
|
449
|
-
elif isinstance(comment, LangString):
|
|
450
|
-
self._comment = comment
|
|
451
|
-
else:
|
|
452
|
-
raise BaseError('Invalid LangString for comment!')
|
|
453
|
-
else:
|
|
454
|
-
self._comment = None
|
|
455
|
-
self._permissions = permissions
|
|
456
|
-
self._has_properties = has_properties
|
|
457
|
-
self._changed = set()
|
|
458
|
-
|
|
459
|
-
#
|
|
460
|
-
# Here follows a list of getters/setters
|
|
461
|
-
#
|
|
462
|
-
@property
|
|
463
|
-
def name(self) -> Optional[str]:
|
|
464
|
-
return self._name
|
|
465
|
-
|
|
466
|
-
@name.setter
|
|
467
|
-
def name(self, value: str) -> None:
|
|
468
|
-
raise BaseError('"name" cannot be modified!')
|
|
469
|
-
|
|
470
|
-
@property
|
|
471
|
-
def id(self) -> Optional[str]:
|
|
472
|
-
return self._id
|
|
473
|
-
|
|
474
|
-
@id.setter
|
|
475
|
-
def id(self, value: str) -> None:
|
|
476
|
-
raise BaseError('"id" cannot be modified!')
|
|
477
|
-
|
|
478
|
-
@property
|
|
479
|
-
def ontology_id(self) -> Optional[str]:
|
|
480
|
-
return self._ontology_id
|
|
481
|
-
|
|
482
|
-
@ontology_id.setter
|
|
483
|
-
def ontology_id(self, value: str) -> None:
|
|
484
|
-
raise BaseError('"ontology_id" cannot be modified!')
|
|
485
|
-
|
|
486
|
-
@property
|
|
487
|
-
def superclasses(self) -> Optional[List[str]]:
|
|
488
|
-
return self._superclasses
|
|
489
|
-
|
|
490
|
-
@superclasses.setter
|
|
491
|
-
def superclasses(self, value: List[str]) -> None:
|
|
492
|
-
raise BaseError('"superclasses" cannot be modified!')
|
|
493
|
-
|
|
494
|
-
@property
|
|
495
|
-
def label(self) -> Optional[LangString]:
|
|
496
|
-
return self._label
|
|
497
|
-
|
|
498
|
-
@label.setter
|
|
499
|
-
def label(self, value: Optional[Union[LangString, str]]) -> None:
|
|
500
|
-
if value is None:
|
|
501
|
-
self._label.empty() # clear all labels
|
|
502
|
-
else:
|
|
503
|
-
if isinstance(value, LangString):
|
|
504
|
-
self._label = value
|
|
505
|
-
elif isinstance(value, str):
|
|
506
|
-
self._label = LangString(value)
|
|
507
|
-
else:
|
|
508
|
-
raise BaseError('Not a valid LangString')
|
|
509
|
-
self._changed.add('label')
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
def addLabel(self, lang: Union[Languages, str], value: str) -> None:
|
|
513
|
-
self._label[lang] = value
|
|
514
|
-
self._changed.add('label')
|
|
515
|
-
|
|
516
|
-
def rmLabel(self, lang: Union[Languages, str]) -> None:
|
|
517
|
-
del self._label[lang]
|
|
518
|
-
self._changed.add('label')
|
|
519
|
-
|
|
520
|
-
@property
|
|
521
|
-
def comment(self) -> Optional[LangString]:
|
|
522
|
-
return self._comment
|
|
523
|
-
|
|
524
|
-
@comment.setter
|
|
525
|
-
def comment(self, value: Optional[LangString]) -> None:
|
|
526
|
-
if value is None:
|
|
527
|
-
self._comment.empty() # clear all comments!
|
|
528
|
-
else:
|
|
529
|
-
if isinstance(value, LangString):
|
|
530
|
-
self._comment = value
|
|
531
|
-
elif isinstance(value, str):
|
|
532
|
-
self._comment = LangString(value)
|
|
533
|
-
else:
|
|
534
|
-
raise BaseError('Not a valid LangString')
|
|
535
|
-
self._changed.add('comment')
|
|
536
|
-
|
|
537
|
-
def addComment(self, lang: Union[Languages, str], value: str) -> None:
|
|
538
|
-
self._comment[lang] = value
|
|
539
|
-
self._changed.add('comment')
|
|
540
|
-
|
|
541
|
-
def rmComment(self, lang: Union[Languages, str]) -> None:
|
|
542
|
-
del self._comment[lang]
|
|
543
|
-
self._changed.add('comment')
|
|
544
|
-
|
|
545
|
-
@property
|
|
546
|
-
def permissions(self) -> Optional[str]:
|
|
547
|
-
return self._permissions
|
|
548
|
-
|
|
549
|
-
@permissions.setter
|
|
550
|
-
def permissions(self, value: str) -> None:
|
|
551
|
-
raise BaseError('"permissions" cannot be modified!')
|
|
552
|
-
|
|
553
|
-
@property
|
|
554
|
-
def has_properties(self) -> Dict[str, HasProperty]:
|
|
555
|
-
return self._has_properties
|
|
556
|
-
|
|
557
|
-
@has_properties.setter
|
|
558
|
-
def has_properties(self, value: str) -> None:
|
|
559
|
-
raise BaseError('"has_property" cannot be modified!')
|
|
560
|
-
|
|
561
|
-
def getProperty(self, property_id) -> Optional[HasProperty]:
|
|
562
|
-
if self._has_properties is None:
|
|
563
|
-
return None
|
|
564
|
-
else:
|
|
565
|
-
return self._has_properties.get(self._context.get_prefixed_iri(property_id))
|
|
566
|
-
|
|
567
|
-
def addProperty(self,
|
|
568
|
-
last_modification_date: LastModificationDate,
|
|
569
|
-
property_id: str,
|
|
570
|
-
cardinality: Cardinality,
|
|
571
|
-
gui_order: Optional[int] = None,
|
|
572
|
-
) -> Optional[LastModificationDate]:
|
|
573
|
-
if self._has_properties.get(property_id) is None:
|
|
574
|
-
latest_modification_date, resclass = HasProperty(con=self._con,
|
|
575
|
-
context=self._context,
|
|
576
|
-
ontology_id=self._ontology_id,
|
|
577
|
-
property_id=property_id,
|
|
578
|
-
resclass_id=self.id,
|
|
579
|
-
cardinality=cardinality,
|
|
580
|
-
gui_order=gui_order).create(last_modification_date)
|
|
581
|
-
hp = resclass.getProperty(property_id)
|
|
582
|
-
hp._ontology_id = self._context.iri_from_prefix(self._ontology_id)
|
|
583
|
-
hp._resclass_id = self._id
|
|
584
|
-
self._has_properties[hp.property_id] = hp
|
|
585
|
-
return latest_modification_date
|
|
586
|
-
else:
|
|
587
|
-
raise BaseError("Property already has cardinality in this class! " + property_id)
|
|
588
|
-
|
|
589
|
-
def updateProperty(self,
|
|
590
|
-
last_modification_date: LastModificationDate,
|
|
591
|
-
property_id: str,
|
|
592
|
-
cardinality: Optional[Cardinality],
|
|
593
|
-
gui_order: Optional[int] = None,
|
|
594
|
-
) -> Optional[LastModificationDate]:
|
|
595
|
-
property_id = self._context.get_prefixed_iri(property_id)
|
|
596
|
-
if self._has_properties.get(property_id) is not None:
|
|
597
|
-
has_properties = self._has_properties[property_id]
|
|
598
|
-
#onto_id = has_properties.ontology_id # save for later user
|
|
599
|
-
#rescl_id = has_properties.resclass_id # save for later user
|
|
600
|
-
has_properties.ontology_id = self._ontology_id
|
|
601
|
-
has_properties.resclass_id = self._id
|
|
602
|
-
if cardinality:
|
|
603
|
-
has_properties.cardinality = cardinality
|
|
604
|
-
if gui_order:
|
|
605
|
-
has_properties.gui_order = gui_order
|
|
606
|
-
latest_modification_date, resclass = has_properties.update(last_modification_date)
|
|
607
|
-
hp = resclass.getProperty(property_id)
|
|
608
|
-
hp.ontology_id = self._ontology_id # self.__context.iri_from_prefix(onto_id) # restore value
|
|
609
|
-
hp.resclass_id = self._id # rescl_id # restore value
|
|
610
|
-
self._has_properties[hp.property_id] = hp
|
|
611
|
-
return latest_modification_date
|
|
612
|
-
else:
|
|
613
|
-
return last_modification_date
|
|
614
|
-
|
|
615
|
-
@classmethod
|
|
616
|
-
def fromJsonObj(cls, con: Connection, context: Context, json_obj: Any) -> Any:
|
|
617
|
-
if isinstance(json_obj, list):
|
|
618
|
-
json_obj = json_obj[0] # TODO: Is it possible to have more than one element in the list??
|
|
619
|
-
if not isinstance(con, Connection):
|
|
620
|
-
raise BaseError('"con"-parameter must be an instance of Connection')
|
|
621
|
-
if not isinstance(context, Context):
|
|
622
|
-
raise BaseError('"context"-parameter must be an instance of Context')
|
|
623
|
-
rdf = context.prefix_from_iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
|
624
|
-
rdfs = context.prefix_from_iri("http://www.w3.org/2000/01/rdf-schema#")
|
|
625
|
-
owl = context.prefix_from_iri("http://www.w3.org/2002/07/owl#")
|
|
626
|
-
xsd = context.prefix_from_iri("http://www.w3.org/2001/XMLSchema#")
|
|
627
|
-
knora_api = context.prefix_from_iri("http://api.knora.org/ontology/knora-api/v2#")
|
|
628
|
-
salsah_gui = context.prefix_from_iri("http://api.knora.org/ontology/salsah-gui/v2#")
|
|
629
|
-
|
|
630
|
-
if not (json_obj.get(knora_api + ':isResourceClass') or json_obj.get(knora_api + ':isStandoffClass')):
|
|
631
|
-
raise BaseError("This is not a resource!")
|
|
632
|
-
|
|
633
|
-
if json_obj.get('@id') is None:
|
|
634
|
-
raise BaseError('Resource class has no "@id"!')
|
|
635
|
-
tmp_id = json_obj.get('@id').split(':')
|
|
636
|
-
id = context.iri_from_prefix(tmp_id[0]) + '#' + tmp_id[1]
|
|
637
|
-
ontology_id = tmp_id[0]
|
|
638
|
-
name = tmp_id[1]
|
|
639
|
-
superclasses_obj = json_obj.get(rdfs + ':subClassOf')
|
|
640
|
-
if superclasses_obj is not None:
|
|
641
|
-
supercls: List[Any] = list(filter(lambda a: a.get('@id') is not None, superclasses_obj))
|
|
642
|
-
superclasses: List[str] = list(map(lambda a: a['@id'], supercls))
|
|
643
|
-
has_props: List[Any] = list(filter(lambda a: a.get('@type') == (owl + ':Restriction'), superclasses_obj))
|
|
644
|
-
has_properties: Dict[HasProperty] = dict(map(lambda a: HasProperty.fromJsonObj(con, context, a), has_props))
|
|
645
|
-
else:
|
|
646
|
-
superclasses = None
|
|
647
|
-
has_properties = None
|
|
648
|
-
|
|
649
|
-
label = LangString.fromJsonLdObj(json_obj.get(rdfs + ':label'))
|
|
650
|
-
comment = LangString.fromJsonLdObj(json_obj.get(rdfs + ':comment'))
|
|
651
|
-
return cls(con=con,
|
|
652
|
-
context=context,
|
|
653
|
-
name=name,
|
|
654
|
-
id=id,
|
|
655
|
-
ontology_id=ontology_id,
|
|
656
|
-
superclasses=superclasses,
|
|
657
|
-
label=label,
|
|
658
|
-
comment=comment,
|
|
659
|
-
has_properties=has_properties)
|
|
660
|
-
|
|
661
|
-
def toJsonObj(self, lastModificationDate: LastModificationDate, action: Actions, what: Optional[str] = None) -> Any:
|
|
662
|
-
|
|
663
|
-
def resolve_resref(resref: str):
|
|
664
|
-
tmp = resref.split(':')
|
|
665
|
-
if len(tmp) > 1:
|
|
666
|
-
if tmp[0]:
|
|
667
|
-
self._context.add_context(tmp[0])
|
|
668
|
-
return {"@id": resref} # fully qualified name in the form "prefix:name"
|
|
669
|
-
else:
|
|
670
|
-
return {"@id": self._context.prefix_from_iri(self._ontology_id) + ':' + tmp[1]} # ":name" in current ontology
|
|
671
|
-
else:
|
|
672
|
-
return {"@id": "knora-api:" + resref} # no ":", must be from knora-api!
|
|
673
|
-
|
|
674
|
-
tmp = {}
|
|
675
|
-
exp = re.compile('^http.*') # It is already a fully IRI
|
|
676
|
-
if exp.match(self._ontology_id):
|
|
677
|
-
resid = self._context.prefix_from_iri(self._ontology_id) + ":" + self._name
|
|
678
|
-
ontid = self._ontology_id
|
|
679
|
-
else:
|
|
680
|
-
resid = self._ontology_id + ":" + self._name
|
|
681
|
-
ontid = self._context.iri_from_prefix(self._ontology_id)
|
|
682
|
-
if action == Actions.Create:
|
|
683
|
-
if self._name is None:
|
|
684
|
-
raise BaseError("There must be a valid resource class name!")
|
|
685
|
-
if self._ontology_id is None:
|
|
686
|
-
raise BaseError("There must be a valid ontology_id given!")
|
|
687
|
-
if self._superclasses is None:
|
|
688
|
-
superclasses = [{"@id": "knora-api:Resource"}]
|
|
689
|
-
else:
|
|
690
|
-
superclasses = list(map(resolve_resref, self._superclasses))
|
|
691
|
-
if self._comment is None or self._comment.isEmpty():
|
|
692
|
-
self._comment = LangString("no comment available")
|
|
693
|
-
if self._label is None or self._label.isEmpty():
|
|
694
|
-
self._label = LangString("no label available")
|
|
695
|
-
tmp = {
|
|
696
|
-
"@id": ontid, # self._ontology_id,
|
|
697
|
-
"@type": "owl:Ontology",
|
|
698
|
-
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
699
|
-
"@graph": [{
|
|
700
|
-
"@id": resid,
|
|
701
|
-
"@type": "owl:Class",
|
|
702
|
-
"rdfs:label": self._label.toJsonLdObj(),
|
|
703
|
-
"rdfs:comment": self._comment.toJsonLdObj(),
|
|
704
|
-
"rdfs:subClassOf": superclasses
|
|
705
|
-
}],
|
|
706
|
-
"@context": self._context.toJsonObj(),
|
|
707
|
-
}
|
|
708
|
-
elif action == Actions.Update:
|
|
709
|
-
tmp = {
|
|
710
|
-
"@id": ontid, # self._ontology_id,
|
|
711
|
-
"@type": "owl:Ontology",
|
|
712
|
-
"knora-api:lastModificationDate": lastModificationDate.toJsonObj(),
|
|
713
|
-
"@graph": [{
|
|
714
|
-
"@id": resid,
|
|
715
|
-
"@type": "owl:Class",
|
|
716
|
-
}],
|
|
717
|
-
"@context": self._context.toJsonObj(),
|
|
718
|
-
}
|
|
719
|
-
if what == 'label':
|
|
720
|
-
if not self._label.isEmpty() and 'label' in self._changed:
|
|
721
|
-
tmp['@graph'][0]['rdfs:label'] = self._label.toJsonLdObj()
|
|
722
|
-
if what == 'comment':
|
|
723
|
-
if not self._comment.isEmpty() and 'comment' in self._changed:
|
|
724
|
-
tmp['@graph'][0]['rdfs:comment'] = self._comment.toJsonLdObj()
|
|
725
|
-
return tmp
|
|
726
|
-
|
|
727
|
-
def create(self, last_modification_date: LastModificationDate) -> Tuple[LastModificationDate, 'ResourceClass']:
|
|
728
|
-
jsonobj = self.toJsonObj(last_modification_date, Actions.Create)
|
|
729
|
-
jsondata = json.dumps(jsonobj, cls=SetEncoder, indent=4)
|
|
730
|
-
result = self._con.post('/v2/ontologies/classes', jsondata)
|
|
731
|
-
last_modification_date = LastModificationDate(result['knora-api:lastModificationDate'])
|
|
732
|
-
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result['@graph'])
|
|
733
|
-
|
|
734
|
-
def update(self, last_modification_date: LastModificationDate) -> Tuple[LastModificationDate, 'ResourceClass']:
|
|
735
|
-
#
|
|
736
|
-
# Note: Knora is able to change only one thing per call, either label or comment!
|
|
737
|
-
#
|
|
738
|
-
result = None
|
|
739
|
-
something_changed = False
|
|
740
|
-
if 'label' in self._changed:
|
|
741
|
-
jsonobj = self.toJsonObj(last_modification_date, Actions.Update, 'label')
|
|
742
|
-
jsondata = json.dumps(jsonobj, cls=SetEncoder, indent=4)
|
|
743
|
-
result = self._con.put('v2/ontologies/classes', jsondata)
|
|
744
|
-
last_modification_date = LastModificationDate(result['knora-api:lastModificationDate'])
|
|
745
|
-
something_changed = True
|
|
746
|
-
if 'comment' in self._changed:
|
|
747
|
-
jsonobj = self.toJsonObj(last_modification_date, Actions.Update, 'comment')
|
|
748
|
-
jsondata = json.dumps(jsonobj, cls=SetEncoder, indent=4)
|
|
749
|
-
result = self._con.put('v2/ontologies/classes', jsondata)
|
|
750
|
-
last_modification_date = LastModificationDate(result['knora-api:lastModificationDate'])
|
|
751
|
-
something_changed = True
|
|
752
|
-
if something_changed:
|
|
753
|
-
return last_modification_date, ResourceClass.fromJsonObj(self._con, self._context, result['@graph'])
|
|
754
|
-
else:
|
|
755
|
-
return last_modification_date, self
|
|
756
|
-
|
|
757
|
-
def delete(self, last_modification_date: LastModificationDate) -> LastModificationDate:
|
|
758
|
-
result = self._con.delete('v2/ontologies/classes/' + quote_plus(self._id) + '?lastModificationDate=' + str(last_modification_date))
|
|
759
|
-
return LastModificationDate(result['knora-api:lastModificationDate'])
|
|
760
|
-
|
|
761
|
-
def createDefinitionFileObj(self, context: Context, shortname: str, skiplist: List[str]):
|
|
762
|
-
resource = {
|
|
763
|
-
"name": self._name,
|
|
764
|
-
"labels": self._label.createDefinitionFileObj(),
|
|
765
|
-
}
|
|
766
|
-
if self._comment:
|
|
767
|
-
resource["comments"] = self._comment.createDefinitionFileObj()
|
|
768
|
-
if self._superclasses:
|
|
769
|
-
if len(self._superclasses) > 1:
|
|
770
|
-
superclasses = []
|
|
771
|
-
for sc in self._superclasses:
|
|
772
|
-
superclasses.append(context.reduce_iri(sc, shortname))
|
|
773
|
-
else:
|
|
774
|
-
superclasses = context.reduce_iri(self._superclasses[0], shortname)
|
|
775
|
-
resource["super"] = superclasses
|
|
776
|
-
if self._has_properties:
|
|
777
|
-
cardinalities = []
|
|
778
|
-
for pid, hp in self._has_properties.items():
|
|
779
|
-
if hp.property_id in skiplist:
|
|
780
|
-
continue
|
|
781
|
-
if hp.ptype == HasProperty.Ptype.other:
|
|
782
|
-
cardinalities.append(hp.createDefinitionFileObj(context, shortname))
|
|
783
|
-
resource["cardinalities"] = cardinalities
|
|
784
|
-
|
|
785
|
-
return resource
|
|
786
|
-
|
|
787
|
-
def print(self, offset: int = 0):
|
|
788
|
-
blank = ' '
|
|
789
|
-
print(f'{blank:>{offset}}Resource Class Info')
|
|
790
|
-
print(f'{blank:>{offset+2}}Name: {self._name}')
|
|
791
|
-
print(f'{blank:>{offset+2}}Ontology prefix: {self._ontology_id}')
|
|
792
|
-
print(f'{blank:>{offset+2}}Superclasses:')
|
|
793
|
-
if self._superclasses is not None:
|
|
794
|
-
for sc in self._superclasses:
|
|
795
|
-
print(f'{blank:>{offset + 4}}{sc}')
|
|
796
|
-
if self._label is not None:
|
|
797
|
-
print(f'{blank:>{offset + 2}}Labels:')
|
|
798
|
-
self._label.print(offset + 4)
|
|
799
|
-
if self._comment is not None:
|
|
800
|
-
print(f'{blank:>{offset + 2}}Comments:')
|
|
801
|
-
self._comment.print(offset + 4)
|
|
802
|
-
if self._has_properties is not None:
|
|
803
|
-
print(f'{blank:>{offset + 2}}Has properties:')
|
|
804
|
-
if self._has_properties is not None:
|
|
805
|
-
for pid, hp in self._has_properties.items():
|
|
806
|
-
hp.print(offset + 4)
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|