dsp-tools 9.1.0.post11__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 +4 -0
- dsp_tools/cli/args.py +36 -0
- dsp_tools/cli/call_action.py +51 -231
- 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 +156 -58
- dsp_tools/cli/entry_point.py +56 -26
- 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/{utils → clients}/connection.py +2 -18
- 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 +57 -23
- dsp_tools/commands/excel2json/{new_lists → lists}/compliance_checks.py +26 -26
- dsp_tools/commands/excel2json/{new_lists/make_new_lists.py → lists/make_lists.py} +19 -18
- dsp_tools/commands/excel2json/{new_lists → lists}/models/input_error.py +1 -12
- dsp_tools/commands/excel2json/{new_lists → lists}/models/serialise.py +9 -5
- dsp_tools/commands/excel2json/{new_lists → lists}/utils.py +4 -4
- dsp_tools/commands/excel2json/models/input_error.py +31 -11
- dsp_tools/commands/excel2json/models/json_header.py +53 -15
- dsp_tools/commands/excel2json/models/ontology.py +4 -3
- dsp_tools/commands/excel2json/{lists.py → old_lists.py} +26 -112
- dsp_tools/commands/excel2json/project.py +78 -34
- dsp_tools/commands/excel2json/properties.py +57 -36
- dsp_tools/commands/excel2json/resources.py +32 -12
- dsp_tools/commands/excel2json/utils.py +20 -1
- dsp_tools/commands/excel2xml/__init__.py +2 -2
- dsp_tools/commands/excel2xml/excel2xml_cli.py +7 -15
- dsp_tools/commands/excel2xml/excel2xml_lib.py +138 -493
- dsp_tools/commands/excel2xml/propertyelement.py +5 -5
- dsp_tools/commands/{project → get}/get.py +29 -13
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/{project/models → get/legacy_models}/context.py +6 -6
- dsp_tools/commands/{project/models → get/legacy_models}/group.py +5 -10
- dsp_tools/commands/{project/models → get/legacy_models}/listnode.py +5 -35
- dsp_tools/commands/{project/models → get/legacy_models}/model.py +1 -1
- dsp_tools/commands/{project/models → get/legacy_models}/ontology.py +9 -14
- dsp_tools/commands/{project/models → get/legacy_models}/project.py +13 -6
- dsp_tools/commands/{project/models → get/legacy_models}/propertyclass.py +9 -16
- dsp_tools/commands/{project/models → get/legacy_models}/resourceclass.py +8 -46
- dsp_tools/commands/{project/models → get/legacy_models}/user.py +19 -60
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +20 -10
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +81 -56
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +4 -10
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +97 -37
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +2 -2
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +9 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +3 -3
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +2 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +12 -2
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +8 -9
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +18 -18
- dsp_tools/commands/start_stack.py +126 -77
- 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/{xml_validate/sparql/resource_shacl.py → validate_data/sparql/cardinality_shacl.py} +45 -47
- 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/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/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +0 -25
- dsp_tools/commands/xmlupload/models/ingest.py +56 -70
- dsp_tools/commands/xmlupload/models/input_problems.py +6 -14
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +0 -39
- dsp_tools/commands/xmlupload/models/{deserialise/xmlpermission.py → permissions_parsed.py} +2 -2
- 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 +3 -3
- dsp_tools/commands/xmlupload/models/upload_state.py +2 -4
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/{ark2iri.py → prepare_xml_input/ark2iri.py} +1 -1
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/{iiif_uri_validator.py → prepare_xml_input/iiif_uri_validator.py} +2 -14
- dsp_tools/commands/xmlupload/{list_client.py → prepare_xml_input/list_client.py} +15 -10
- 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 +7 -468
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/{construct_and_analyze_graph.py → analyse_circular_reference_graph.py} +64 -157
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +13 -8
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +48 -115
- dsp_tools/commands/xmlupload/stash/stash_models.py +4 -9
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +34 -40
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +98 -108
- dsp_tools/commands/xmlupload/upload_config.py +8 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +14 -9
- dsp_tools/commands/xmlupload/xmlupload.py +214 -192
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/{utils → config}/warnings_config.py +4 -1
- 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/{models → legacy_models}/datetimestamp.py +7 -7
- dsp_tools/{models → legacy_models}/langstring.py +1 -1
- dsp_tools/{models → legacy_models}/projectContext.py +4 -4
- dsp_tools/resources/schema/data.xsd +108 -83
- dsp_tools/resources/schema/lists-only.json +4 -23
- dsp_tools/resources/schema/project.json +80 -35
- dsp_tools/resources/schema/properties-only.json +1 -4
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +34 -30
- 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/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/{date_util.py → data_formats/date_util.py} +13 -1
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/{shared.py → data_formats/shared.py} +1 -35
- dsp_tools/utils/{uri_util.py → data_formats/uri_util.py} +12 -2
- 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/config_options.py +28 -0
- dsp_tools/xmllib/models/date_formats.py +48 -0
- dsp_tools/xmllib/models/dsp_base_resources.py +1380 -400
- 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/{migration_metadata.py → internal/migration_metadata.py} +14 -10
- 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 +313 -26
- dsp_tools/xmllib/value_checkers.py +310 -47
- dsp_tools/xmllib/value_converters.py +765 -8
- 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-9.1.0.post11.dist-info → dsp_tools-18.3.0.post13.dist-info}/entry_points.txt +1 -0
- dsp_tools/commands/project/create/project_create.py +0 -1107
- dsp_tools/commands/project/create/project_create_lists.py +0 -204
- dsp_tools/commands/project/create/project_validate.py +0 -453
- dsp_tools/commands/project/models/project_definition.py +0 -12
- dsp_tools/commands/rosetta.py +0 -124
- dsp_tools/commands/template.py +0 -30
- dsp_tools/commands/xml_validate/api_connection.py +0 -122
- dsp_tools/commands/xml_validate/deserialise_input.py +0 -135
- dsp_tools/commands/xml_validate/make_data_rdf.py +0 -193
- dsp_tools/commands/xml_validate/models/data_deserialised.py +0 -108
- dsp_tools/commands/xml_validate/models/data_rdf.py +0 -214
- dsp_tools/commands/xml_validate/models/input_problems.py +0 -191
- dsp_tools/commands/xml_validate/models/validation.py +0 -29
- dsp_tools/commands/xml_validate/reformat_validaton_result.py +0 -89
- dsp_tools/commands/xml_validate/sparql/construct_shapes.py +0 -16
- dsp_tools/commands/xml_validate/xml_validate.py +0 -151
- dsp_tools/commands/xmlupload/check_consistency_with_ontology.py +0 -253
- dsp_tools/commands/xmlupload/models/deserialise/deserialise_value.py +0 -236
- dsp_tools/commands/xmlupload/models/deserialise/xmlresource.py +0 -171
- dsp_tools/commands/xmlupload/models/namespace_context.py +0 -39
- dsp_tools/commands/xmlupload/models/ontology_lookup_models.py +0 -161
- dsp_tools/commands/xmlupload/models/ontology_problem_models.py +0 -178
- dsp_tools/commands/xmlupload/models/serialise/jsonld_serialiser.py +0 -40
- dsp_tools/commands/xmlupload/models/serialise/serialise_value.py +0 -51
- dsp_tools/commands/xmlupload/ontology_client.py +0 -92
- dsp_tools/commands/xmlupload/project_client.py +0 -91
- dsp_tools/commands/xmlupload/read_validate_xml_file.py +0 -99
- dsp_tools/models/custom_warnings.py +0 -31
- dsp_tools/models/exceptions.py +0 -90
- dsp_tools/resources/0100-template-repo/template.json +0 -45
- dsp_tools/resources/0100-template-repo/template.xml +0 -27
- dsp_tools/resources/start-stack/docker-compose-validation.yml +0 -5
- dsp_tools/resources/start-stack/start-stack-config.yml +0 -4
- dsp_tools/resources/xml_validate/api-shapes.ttl +0 -411
- dsp_tools/resources/xml_validate/replace_namespace.xslt +0 -61
- dsp_tools/utils/connection_live.py +0 -383
- dsp_tools/utils/iri_util.py +0 -14
- dsp_tools/utils/logger_config.py +0 -41
- dsp_tools/utils/set_encoder.py +0 -20
- dsp_tools/utils/xml_utils.py +0 -145
- dsp_tools/utils/xml_validation.py +0 -197
- dsp_tools/utils/xml_validation_models.py +0 -68
- dsp_tools/xmllib/models/file_values.py +0 -78
- dsp_tools/xmllib/models/resource.py +0 -415
- dsp_tools/xmllib/models/values.py +0 -428
- dsp_tools-9.1.0.post11.dist-info/METADATA +0 -130
- dsp_tools-9.1.0.post11.dist-info/RECORD +0 -167
- dsp_tools-9.1.0.post11.dist-info/WHEEL +0 -4
- dsp_tools-9.1.0.post11.dist-info/licenses/LICENSE +0 -674
- /dsp_tools/{commands/excel2json/new_lists → clients}/__init__.py +0 -0
- /dsp_tools/commands/{excel2json/new_lists/models → create}/__init__.py +0 -0
- /dsp_tools/commands/{project → create/create_on_server}/__init__.py +0 -0
- /dsp_tools/commands/{project/create → create/models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → create/parsing}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate → create/serialisation}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/models → excel2json/lists}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/sparql → excel2json/lists/models}/__init__.py +0 -0
- /dsp_tools/commands/excel2json/{new_lists → lists}/models/deserialise.py +0 -0
- /dsp_tools/commands/{xmlupload/models/deserialise → get}/__init__.py +0 -0
- /dsp_tools/commands/{xmlupload/models/serialise → get/legacy_models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → get/legacy_models}/helpers.py +0 -0
- /dsp_tools/{models → commands/get/models}/__init__.py +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
from loguru import logger
|
|
2
|
+
from rdflib import RDF
|
|
3
|
+
from rdflib import SH
|
|
4
|
+
from rdflib import XSD
|
|
5
|
+
from rdflib import BNode
|
|
6
|
+
from rdflib import Graph
|
|
7
|
+
from rdflib import Literal
|
|
8
|
+
from rdflib import URIRef
|
|
9
|
+
from rdflib.collection import Collection
|
|
10
|
+
|
|
11
|
+
from dsp_tools.clients.list_client import OneList
|
|
12
|
+
from dsp_tools.commands.validate_data.models.api_responses import SHACLListInfo
|
|
13
|
+
from dsp_tools.utils.rdf_constants import KNORA_API
|
|
14
|
+
from dsp_tools.utils.rdf_constants import PropertyTypeAlias
|
|
15
|
+
from dsp_tools.utils.rdf_constants import SubjectObjectTypeAlias
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def construct_property_shapes(onto: Graph, project_lists: list[OneList]) -> Graph:
|
|
19
|
+
"""
|
|
20
|
+
Returns the sh:PropertyShape for the properties in the ontology.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
onto: ontology graph
|
|
24
|
+
project_lists: all lists from a project
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Graph with the property shapes
|
|
28
|
+
"""
|
|
29
|
+
logger.debug("Constructing property shapes for ontology.")
|
|
30
|
+
g = Graph()
|
|
31
|
+
g += _construct_link_value_shape(onto)
|
|
32
|
+
g += _construct_link_value_node_shape(onto)
|
|
33
|
+
g += _construct_property_type_text_value(onto)
|
|
34
|
+
g += _construct_list_shapes(onto, project_lists)
|
|
35
|
+
g += _construct_seqnum_is_part_of_prop_shape(onto)
|
|
36
|
+
g += _construct_value_type_shapes_to_class_shapes(onto)
|
|
37
|
+
g += _construct_link_value_type_shapes_to_class_shapes(onto)
|
|
38
|
+
return g + _add_property_shapes_to_class_shapes(onto)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _add_property_shapes_to_class_shapes(onto: Graph) -> Graph:
|
|
42
|
+
logger.debug("Add property shape to resources")
|
|
43
|
+
query_s = """
|
|
44
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
45
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
46
|
+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
47
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
48
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
49
|
+
|
|
50
|
+
CONSTRUCT {
|
|
51
|
+
|
|
52
|
+
?class a sh:NodeShape ;
|
|
53
|
+
sh:property ?propShapesIRI .
|
|
54
|
+
|
|
55
|
+
} WHERE {
|
|
56
|
+
|
|
57
|
+
?class a owl:Class ;
|
|
58
|
+
knora-api:isResourceClass true ;
|
|
59
|
+
knora-api:canBeInstantiated true ;
|
|
60
|
+
rdfs:subClassOf ?restriction .
|
|
61
|
+
?restriction a owl:Restriction ;
|
|
62
|
+
owl:onProperty ?propRestriction .
|
|
63
|
+
|
|
64
|
+
?propRestriction knora-api:isEditable true .
|
|
65
|
+
FILTER NOT EXISTS { ?propRestriction knora-api:isLinkValueProperty true }
|
|
66
|
+
|
|
67
|
+
BIND(IRI(CONCAT(str(?propRestriction), "_PropShape")) AS ?propShapesIRI)
|
|
68
|
+
}
|
|
69
|
+
"""
|
|
70
|
+
if results_graph := onto.query(query_s).graph:
|
|
71
|
+
return results_graph
|
|
72
|
+
return Graph()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _construct_value_type_shapes_to_class_shapes(onto: Graph) -> Graph:
|
|
76
|
+
logger.debug("Add value type shape to resources")
|
|
77
|
+
query_s = """
|
|
78
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
79
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
80
|
+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
81
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
82
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
83
|
+
|
|
84
|
+
CONSTRUCT {
|
|
85
|
+
|
|
86
|
+
?shapesIRI a sh:PropertyShape ;
|
|
87
|
+
sh:path ?propRestriction ;
|
|
88
|
+
sh:class ?objectType ;
|
|
89
|
+
sh:message ?objectTypeMessage .
|
|
90
|
+
|
|
91
|
+
} WHERE {
|
|
92
|
+
|
|
93
|
+
?class a owl:Class ;
|
|
94
|
+
knora-api:isResourceClass true ;
|
|
95
|
+
knora-api:canBeInstantiated true ;
|
|
96
|
+
rdfs:subClassOf ?restriction .
|
|
97
|
+
?restriction a owl:Restriction ;
|
|
98
|
+
owl:onProperty ?propRestriction .
|
|
99
|
+
|
|
100
|
+
?propRestriction knora-api:isEditable true ;
|
|
101
|
+
knora-api:objectType ?objectType .
|
|
102
|
+
|
|
103
|
+
FILTER NOT EXISTS { ?propRestriction knora-api:isLinkProperty true }
|
|
104
|
+
FILTER NOT EXISTS { ?propRestriction knora-api:isLinkValueProperty true }
|
|
105
|
+
|
|
106
|
+
BIND(IRI(CONCAT(str(?propRestriction), "_PropShape")) AS ?shapesIRI)
|
|
107
|
+
BIND(CONCAT("This property requires a ", STRAFTER(STR(?objectType), "#")) AS ?objectTypeMessage)
|
|
108
|
+
}
|
|
109
|
+
"""
|
|
110
|
+
if results_graph := onto.query(query_s).graph:
|
|
111
|
+
return results_graph
|
|
112
|
+
return Graph()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _construct_link_value_type_shapes_to_class_shapes(onto: Graph) -> Graph:
|
|
116
|
+
logger.debug("Add value type shape to resources")
|
|
117
|
+
query_s = """
|
|
118
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
119
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
120
|
+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
121
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
122
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
123
|
+
|
|
124
|
+
CONSTRUCT {
|
|
125
|
+
|
|
126
|
+
?shapesIRI a sh:PropertyShape ;
|
|
127
|
+
sh:path ?propRestriction ;
|
|
128
|
+
sh:class knora-api:LinkValue ;
|
|
129
|
+
sh:message "This property requires a LinkValue" .
|
|
130
|
+
|
|
131
|
+
} WHERE {
|
|
132
|
+
|
|
133
|
+
?class a owl:Class ;
|
|
134
|
+
knora-api:isResourceClass true ;
|
|
135
|
+
knora-api:canBeInstantiated true ;
|
|
136
|
+
rdfs:subClassOf ?restriction .
|
|
137
|
+
?restriction a owl:Restriction ;
|
|
138
|
+
owl:onProperty ?propRestriction .
|
|
139
|
+
|
|
140
|
+
?propRestriction knora-api:isEditable true ;
|
|
141
|
+
knora-api:isLinkProperty true .
|
|
142
|
+
|
|
143
|
+
BIND(IRI(CONCAT(str(?propRestriction), "_PropShape")) AS ?shapesIRI)
|
|
144
|
+
}
|
|
145
|
+
"""
|
|
146
|
+
if results_graph := onto.query(query_s).graph:
|
|
147
|
+
return results_graph
|
|
148
|
+
return Graph()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _construct_link_value_shape(onto: Graph) -> Graph:
|
|
152
|
+
logger.debug("Constructing LinkValue PropertyShape")
|
|
153
|
+
query_s = """
|
|
154
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
155
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
156
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
157
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
158
|
+
PREFIX salsah-gui: <http://api.knora.org/ontology/salsah-gui/v2#>
|
|
159
|
+
|
|
160
|
+
CONSTRUCT {
|
|
161
|
+
|
|
162
|
+
?shapesIRI a sh:PropertyShape ;
|
|
163
|
+
sh:path ?prop ;
|
|
164
|
+
sh:node ?nodeShapeIRI .
|
|
165
|
+
|
|
166
|
+
} WHERE {
|
|
167
|
+
|
|
168
|
+
?prop a owl:ObjectProperty ;
|
|
169
|
+
salsah-gui:guiElement salsah-gui:Searchbox .
|
|
170
|
+
|
|
171
|
+
BIND(IRI(CONCAT(str(?prop), "_PropShape")) AS ?shapesIRI)
|
|
172
|
+
BIND(IRI(CONCAT(str(?prop), "_NodeShape")) AS ?nodeShapeIRI)
|
|
173
|
+
}
|
|
174
|
+
"""
|
|
175
|
+
if results_graph := onto.query(query_s).graph:
|
|
176
|
+
return results_graph
|
|
177
|
+
return Graph()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _construct_link_value_node_shape(onto: Graph) -> Graph:
|
|
181
|
+
logger.debug("Constructing LinkValue NodeShape")
|
|
182
|
+
query_s = """
|
|
183
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
184
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
185
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
186
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
187
|
+
PREFIX salsah-gui: <http://api.knora.org/ontology/salsah-gui/v2#>
|
|
188
|
+
|
|
189
|
+
CONSTRUCT {
|
|
190
|
+
|
|
191
|
+
?nodeShapeIRI a sh:NodeShape ;
|
|
192
|
+
sh:property [
|
|
193
|
+
a sh:PropertyShape ;
|
|
194
|
+
sh:path api-shapes:linkValueHasTargetID ;
|
|
195
|
+
sh:class ?rangeClass ;
|
|
196
|
+
sh:message ?msg
|
|
197
|
+
] ;
|
|
198
|
+
sh:severity sh:Violation .
|
|
199
|
+
|
|
200
|
+
} WHERE {
|
|
201
|
+
|
|
202
|
+
?prop a owl:ObjectProperty ;
|
|
203
|
+
knora-api:isLinkProperty true ;
|
|
204
|
+
knora-api:objectType ?rangeClass .
|
|
205
|
+
|
|
206
|
+
BIND(IRI(CONCAT(str(?prop), "_NodeShape")) AS ?nodeShapeIRI)
|
|
207
|
+
BIND(CONCAT("Range is ", str(?rangeClass), " or a subclass") AS ?msg)
|
|
208
|
+
}
|
|
209
|
+
"""
|
|
210
|
+
if results_graph := onto.query(query_s).graph:
|
|
211
|
+
return results_graph
|
|
212
|
+
return Graph()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _construct_property_type_text_value(onto: Graph) -> Graph:
|
|
216
|
+
property_type_mapper = {
|
|
217
|
+
"salsah-gui:SimpleText": "api-shapes:SimpleTextValue_ClassShape",
|
|
218
|
+
"salsah-gui:Textarea": "api-shapes:TextareaTextValue_ClassShape",
|
|
219
|
+
"salsah-gui:Richtext": "api-shapes:FormattedTextValue_ClassShape",
|
|
220
|
+
}
|
|
221
|
+
g = Graph()
|
|
222
|
+
for object_type, shacl_shape in property_type_mapper.items():
|
|
223
|
+
g += _construct_one_property_type_text_value(onto, object_type, shacl_shape)
|
|
224
|
+
return g
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _construct_one_property_type_text_value(onto: Graph, gui_element: str, shacl_shape: str) -> Graph:
|
|
228
|
+
logger.debug(f"Constructing shape for {gui_element}")
|
|
229
|
+
query_s = """
|
|
230
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
231
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
232
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
233
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
234
|
+
PREFIX salsah-gui: <http://api.knora.org/ontology/salsah-gui/v2#>
|
|
235
|
+
|
|
236
|
+
CONSTRUCT {
|
|
237
|
+
|
|
238
|
+
?shapesIRI a sh:PropertyShape ;
|
|
239
|
+
sh:path ?prop ;
|
|
240
|
+
sh:node %(shacl_shape)s .
|
|
241
|
+
|
|
242
|
+
} WHERE {
|
|
243
|
+
|
|
244
|
+
?prop a owl:ObjectProperty ;
|
|
245
|
+
knora-api:objectType knora-api:TextValue ;
|
|
246
|
+
salsah-gui:guiElement %(gui_element)s .
|
|
247
|
+
|
|
248
|
+
BIND(IRI(CONCAT(str(?prop), "_PropShape")) AS ?shapesIRI)
|
|
249
|
+
}
|
|
250
|
+
""" % {"gui_element": gui_element, "shacl_shape": shacl_shape} # noqa: UP031 (printf-string-formatting)
|
|
251
|
+
if results_graph := onto.query(query_s).graph:
|
|
252
|
+
return results_graph
|
|
253
|
+
return Graph()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _construct_list_shapes(onto: Graph, project_lists: list[OneList]) -> Graph:
|
|
257
|
+
lists_graph = Graph()
|
|
258
|
+
for one_list in project_lists:
|
|
259
|
+
lists_graph += _construct_one_list_node_shape(one_list)
|
|
260
|
+
for one_list in project_lists:
|
|
261
|
+
lists_graph += _construct_one_list_property_shape(onto, one_list)
|
|
262
|
+
return lists_graph
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _construct_one_list_node_shape(one_list: OneList) -> Graph:
|
|
266
|
+
g = Graph()
|
|
267
|
+
list_iri = URIRef(one_list.list_iri)
|
|
268
|
+
g.add((list_iri, RDF.type, SH.NodeShape))
|
|
269
|
+
g.add((list_iri, SH.severity, SH.Violation))
|
|
270
|
+
list_iris = [nd.iri for nd in one_list.nodes]
|
|
271
|
+
node_prop_info = SHACLListInfo(
|
|
272
|
+
list_iri=list_iri,
|
|
273
|
+
sh_path=KNORA_API.listValueAsListNode,
|
|
274
|
+
sh_message=(
|
|
275
|
+
f"A valid node from the list '{one_list.list_name}' must be used with this property "
|
|
276
|
+
f"(input displayed in format 'listName / NodeName')."
|
|
277
|
+
),
|
|
278
|
+
sh_in=list_iris,
|
|
279
|
+
)
|
|
280
|
+
g += _construct_one_list_property_shape_with_collection(node_prop_info)
|
|
281
|
+
return g
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _construct_one_list_property_shape_with_collection(shacl_info: SHACLListInfo) -> Graph:
|
|
285
|
+
g = Graph()
|
|
286
|
+
collection_bn = BNode()
|
|
287
|
+
collection_literals: list[SubjectObjectTypeAlias] = [Literal(lit, datatype=XSD.string) for lit in shacl_info.sh_in]
|
|
288
|
+
Collection(g, collection_bn, collection_literals)
|
|
289
|
+
prop_shape: list[tuple[PropertyTypeAlias, SubjectObjectTypeAlias]] = [
|
|
290
|
+
(RDF.type, SH.PropertyShape),
|
|
291
|
+
(SH.path, shacl_info.sh_path),
|
|
292
|
+
(URIRef("http://www.w3.org/ns/shacl#in"), collection_bn),
|
|
293
|
+
(SH.message, Literal(shacl_info.sh_message, datatype=XSD.string)),
|
|
294
|
+
]
|
|
295
|
+
prop_bn: SubjectObjectTypeAlias = BNode()
|
|
296
|
+
for prop, obj in prop_shape:
|
|
297
|
+
g.add((prop_bn, prop, obj))
|
|
298
|
+
g.add((shacl_info.list_iri, SH.property, prop_bn))
|
|
299
|
+
return g
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _construct_one_list_property_shape(onto: Graph, one_list: OneList) -> Graph:
|
|
303
|
+
logger.debug(f"Constructing Collection Shape for ListValue: {one_list.list_iri}")
|
|
304
|
+
query_s = """
|
|
305
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
306
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
307
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
308
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
309
|
+
PREFIX salsah-gui: <http://api.knora.org/ontology/salsah-gui/v2#>
|
|
310
|
+
|
|
311
|
+
CONSTRUCT {
|
|
312
|
+
?shapesIRI a sh:PropertyShape ;
|
|
313
|
+
sh:path ?prop ;
|
|
314
|
+
sh:node <%(list)s> ;
|
|
315
|
+
sh:severity sh:Violation .
|
|
316
|
+
} WHERE {
|
|
317
|
+
?prop a owl:ObjectProperty ;
|
|
318
|
+
knora-api:objectType knora-api:ListValue ;
|
|
319
|
+
salsah-gui:guiAttribute %(guiAttribute)s .
|
|
320
|
+
|
|
321
|
+
BIND(IRI(CONCAT(str(?prop), "_PropShape")) AS ?shapesIRI)
|
|
322
|
+
}
|
|
323
|
+
""" % {"guiAttribute": one_list.hlist(), "list": one_list.list_iri} # noqa: UP031 (printf-string-formatting)
|
|
324
|
+
if results_graph := onto.query(query_s).graph:
|
|
325
|
+
return results_graph
|
|
326
|
+
return Graph()
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _construct_seqnum_is_part_of_prop_shape(onto: Graph) -> Graph:
|
|
330
|
+
logger.debug("Constructing Collection Shape seqnum / isPartOf")
|
|
331
|
+
query_s = """
|
|
332
|
+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
333
|
+
PREFIX sh: <http://www.w3.org/ns/shacl#>
|
|
334
|
+
PREFIX dash: <http://datashapes.org/dash#>
|
|
335
|
+
PREFIX api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#>
|
|
336
|
+
PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
|
|
337
|
+
PREFIX salsah-gui: <http://api.knora.org/ontology/salsah-gui/v2#>
|
|
338
|
+
|
|
339
|
+
CONSTRUCT {
|
|
340
|
+
?resourceClass sh:property api-shapes:seqnum_PropShape .
|
|
341
|
+
} WHERE {
|
|
342
|
+
?resourceClass rdfs:subClassOf ?restriction .
|
|
343
|
+
?restriction a owl:Restriction .
|
|
344
|
+
{
|
|
345
|
+
?restriction owl:onProperty knora-api:seqnum .
|
|
346
|
+
}
|
|
347
|
+
UNION
|
|
348
|
+
{
|
|
349
|
+
?restriction owl:onProperty knora-api:isPartOf .
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
"""
|
|
353
|
+
# The API allows the ontology to declare cardinalities for seqnum without isPartOf and vice versa.
|
|
354
|
+
# Therefore, we have a union query.
|
|
355
|
+
if results_graph := onto.query(query_s).graph:
|
|
356
|
+
return results_graph
|
|
357
|
+
return Graph()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from tempfile import TemporaryDirectory
|
|
4
|
+
|
|
5
|
+
from dsp_tools.utils.rdf_constants import SubjectObjectTypeAlias
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_temp_directory() -> TemporaryDirectory[str]:
|
|
9
|
+
ttl_dir = (Path.home() / ".dsp-tools" / "validate-data").absolute()
|
|
10
|
+
ttl_dir.mkdir(exist_ok=True, parents=True)
|
|
11
|
+
t_dir = TemporaryDirectory(dir=ttl_dir)
|
|
12
|
+
return t_dir
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def clean_up_temp_directory(temp_dir: TemporaryDirectory[str], save_graphs_dir: Path | None) -> None:
|
|
16
|
+
if save_graphs_dir:
|
|
17
|
+
tmp_folder = Path(temp_dir.name)
|
|
18
|
+
save_graphs_dir.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
for tmp_filepath in tmp_folder.glob("*"):
|
|
20
|
+
if tmp_filepath.is_file():
|
|
21
|
+
dest_filepath = save_graphs_dir / tmp_filepath.relative_to(tmp_folder)
|
|
22
|
+
shutil.copy2(tmp_filepath, dest_filepath)
|
|
23
|
+
temp_dir.cleanup()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def reformat_any_iri(iri: SubjectObjectTypeAlias | str) -> str:
|
|
27
|
+
"""
|
|
28
|
+
Reformats any kind of IRI, if it starts with data then it treats is like a data IRI.
|
|
29
|
+
Otherwise, like an ontology IRI.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
iri: Input IRI
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
reformatted string
|
|
36
|
+
"""
|
|
37
|
+
iri_str = str(iri)
|
|
38
|
+
if iri_str.startswith("http://data/"):
|
|
39
|
+
return reformat_data_iri(iri_str)
|
|
40
|
+
if iri_str.startswith("http://rdfh.ch/"):
|
|
41
|
+
return iri_str
|
|
42
|
+
return reformat_onto_iri(iri_str)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def reformat_onto_iri(iri: SubjectObjectTypeAlias | str) -> str:
|
|
46
|
+
"""Takes a rdflib Node and returns a prefixed IRI in string form."""
|
|
47
|
+
iri_str = str(iri)
|
|
48
|
+
if "http://www.w3.org/2000/01/rdf-schema#" in iri_str:
|
|
49
|
+
return f"rdfs:{iri_str.split('#')[-1]}"
|
|
50
|
+
onto = iri_str.split("/")[-2]
|
|
51
|
+
ending = iri_str.split("#")[-1]
|
|
52
|
+
if onto == "knora-api":
|
|
53
|
+
return ending
|
|
54
|
+
return f"{onto}:{ending}"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def reformat_data_iri(iri: SubjectObjectTypeAlias | str) -> str:
|
|
58
|
+
"""Takes a rdflib Node with in the data namespace and returns only the suffix."""
|
|
59
|
+
return str(iri).replace("http://data/", "", 1)
|