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,58 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from lxml import etree
|
|
8
|
+
from tqdm import tqdm
|
|
9
|
+
|
|
10
|
+
from dsp_tools.commands.xmlupload.models.input_problems import AllIIIFUriProblems
|
|
11
|
+
from dsp_tools.commands.xmlupload.prepare_xml_input.iiif_uri_validator import IIIFUriValidator
|
|
12
|
+
from dsp_tools.error.custom_warnings import DspToolsUserWarning
|
|
13
|
+
from dsp_tools.error.exceptions import InputError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def validate_iiif_uris(root: etree._Element) -> None:
|
|
17
|
+
uris = [uri.strip() for node in root.iter(tag="iiif-uri") if (uri := node.text)]
|
|
18
|
+
if (num := len(uris)) > 1001:
|
|
19
|
+
warnings.warn(
|
|
20
|
+
DspToolsUserWarning(
|
|
21
|
+
f"Your data contains {num} IIIF-URIs. "
|
|
22
|
+
f"Each validation makes a server call. "
|
|
23
|
+
f"Due to the large number, the validation of the IIIF-URIs has to be skipped."
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
return
|
|
27
|
+
progress_bar = tqdm(uris, desc="Checking IIIF-URIs", dynamic_ncols=True)
|
|
28
|
+
validator = IIIFUriValidator()
|
|
29
|
+
problems = []
|
|
30
|
+
for uri in progress_bar:
|
|
31
|
+
if result := validator.validate_one_uri(uri):
|
|
32
|
+
problems.append(result)
|
|
33
|
+
if problems:
|
|
34
|
+
msg = AllIIIFUriProblems(problems).get_msg()
|
|
35
|
+
warnings.warn(DspToolsUserWarning(msg))
|
|
36
|
+
logger.warning(msg)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def check_if_bitstreams_exist(root: etree._Element, imgdir: str) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Make sure that all bitstreams referenced in the XML file exist in the imgdir.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
root: parsed XML file
|
|
45
|
+
imgdir: folder where the bitstreams are stored
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
InputError: if a bitstream does not exist in the imgdir
|
|
49
|
+
"""
|
|
50
|
+
logger.debug("Checking if filepaths exist.")
|
|
51
|
+
multimedia_resources = [x for x in root if any(y.tag == "bitstream" for y in x.iter())]
|
|
52
|
+
progress_bar = tqdm(multimedia_resources, desc="Checking multimedia filepaths", dynamic_ncols=True)
|
|
53
|
+
for res in progress_bar:
|
|
54
|
+
pth = next(Path(x.text.strip()) for x in res.iter() if x.tag == "bitstream" and x.text)
|
|
55
|
+
if not Path(imgdir / pth).is_file():
|
|
56
|
+
raise InputError(
|
|
57
|
+
f"Bitstream '{pth!s}' of resource '{res.attrib['label']}' does not exist in the imgdir '{imgdir}'."
|
|
58
|
+
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from json.decoder import JSONDecodeError
|
|
7
|
+
from typing import Union
|
|
8
|
+
from typing import assert_never
|
|
9
|
+
from typing import cast
|
|
10
|
+
|
|
11
|
+
from dsp_tools.commands.xmlupload.models.formatted_text_value import FormattedTextValue
|
|
12
|
+
from dsp_tools.commands.xmlupload.models.processed.values import IntervalFloats
|
|
13
|
+
from dsp_tools.commands.xmlupload.models.processed.values import ProcessedValue
|
|
14
|
+
from dsp_tools.commands.xmlupload.models.processed.values import ProcessedValueTypes
|
|
15
|
+
from dsp_tools.error.exceptions import XmlInputConversionError
|
|
16
|
+
from dsp_tools.utils.data_formats.date_util import Date
|
|
17
|
+
from dsp_tools.utils.data_formats.date_util import parse_date_string
|
|
18
|
+
|
|
19
|
+
type InputTypes = Union[str, FormattedTextValue, tuple[str | None, str | None] | None]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class TypeTransformerMapper:
|
|
24
|
+
val_type: type[ProcessedValue]
|
|
25
|
+
val_transformer: Callable[[InputTypes], ProcessedValueTypes]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def assert_is_string(value: InputTypes) -> str:
|
|
29
|
+
"""Assert a value is a string."""
|
|
30
|
+
match value:
|
|
31
|
+
case str() as s:
|
|
32
|
+
return s
|
|
33
|
+
case FormattedTextValue() as xml:
|
|
34
|
+
raise XmlInputConversionError(f"Expected string value, but got XML value: {xml.xmlstr}")
|
|
35
|
+
case tuple():
|
|
36
|
+
raise XmlInputConversionError(f"Expected string value, but got tuple value: {value}")
|
|
37
|
+
case None:
|
|
38
|
+
raise XmlInputConversionError("Expected string value, but got None")
|
|
39
|
+
case _:
|
|
40
|
+
assert_never(value)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def assert_is_tuple(value: InputTypes) -> tuple[str, str]:
|
|
44
|
+
"""Assert a value is a tuple."""
|
|
45
|
+
match value:
|
|
46
|
+
case tuple() as t:
|
|
47
|
+
if len(t) == 2 and isinstance(t[0], str) and isinstance(t[1], str):
|
|
48
|
+
return cast(tuple[str, str], t)
|
|
49
|
+
raise XmlInputConversionError(f"Expected tuple with two elements but got {value}")
|
|
50
|
+
case FormattedTextValue() as xml:
|
|
51
|
+
raise XmlInputConversionError(f"Expected tuple value, but got XML value: {xml.xmlstr}")
|
|
52
|
+
case str():
|
|
53
|
+
raise XmlInputConversionError(f"Expected tuple value, but got string value: {value}")
|
|
54
|
+
case None:
|
|
55
|
+
raise XmlInputConversionError("Expected tuple value, but got None")
|
|
56
|
+
case _:
|
|
57
|
+
assert_never(value)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def transform_boolean(value: InputTypes) -> bool:
|
|
61
|
+
"""Transform the value into a boolean"""
|
|
62
|
+
match value:
|
|
63
|
+
case "True" | "true" | "1" | 1 | True:
|
|
64
|
+
return True
|
|
65
|
+
case "False" | "false" | "0" | 0 | False:
|
|
66
|
+
return False
|
|
67
|
+
case _:
|
|
68
|
+
raise XmlInputConversionError(f"Could not parse boolean value: {value}")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def transform_date(input_value: InputTypes) -> Date:
|
|
72
|
+
"""Transform a date string into a date object."""
|
|
73
|
+
val = assert_is_string(input_value)
|
|
74
|
+
return parse_date_string(val)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def transform_decimal(value: InputTypes) -> float:
|
|
78
|
+
"""Transform a value into a float"""
|
|
79
|
+
str_val = assert_is_string(value)
|
|
80
|
+
return float(str_val)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def transform_integer(value: InputTypes) -> int:
|
|
84
|
+
"""Transform a value into an integer"""
|
|
85
|
+
str_val = assert_is_string(value)
|
|
86
|
+
return int(str_val)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def transform_interval(input_value: InputTypes) -> IntervalFloats:
|
|
90
|
+
"""Transform a string input into an interval object."""
|
|
91
|
+
val = assert_is_tuple(input_value)
|
|
92
|
+
try:
|
|
93
|
+
return IntervalFloats(float(val[0]), float(val[1]))
|
|
94
|
+
except ValueError:
|
|
95
|
+
raise XmlInputConversionError(f"Could not parse interval: {val}") from None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def transform_geometry(value: InputTypes) -> str:
|
|
99
|
+
"""Transform a value into a geometry string"""
|
|
100
|
+
str_val = assert_is_string(value)
|
|
101
|
+
try:
|
|
102
|
+
return json.dumps(json.loads(str_val))
|
|
103
|
+
except JSONDecodeError:
|
|
104
|
+
raise XmlInputConversionError(f"Could not parse json value: {value}") from None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def transform_simpletext(value: InputTypes) -> str:
|
|
108
|
+
str_val = assert_is_string(value)
|
|
109
|
+
if len(str_val) == 0:
|
|
110
|
+
raise XmlInputConversionError("After removing redundant whitespaces and newlines the input string is empty.")
|
|
111
|
+
return str_val
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def transform_richtext(value: InputTypes) -> FormattedTextValue:
|
|
115
|
+
str_val = assert_is_string(value)
|
|
116
|
+
if len(str_val) == 0:
|
|
117
|
+
raise XmlInputConversionError("After removing redundant whitespaces and newlines the input string is empty.")
|
|
118
|
+
return FormattedTextValue(str_val)
|
|
@@ -1,43 +1,10 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from dataclasses import dataclass
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Any
|
|
5
|
-
from typing import assert_never
|
|
6
2
|
from typing import cast
|
|
7
3
|
|
|
8
|
-
from loguru import logger
|
|
9
|
-
from rdflib import RDF
|
|
10
|
-
from rdflib import BNode
|
|
11
4
|
from rdflib import Graph
|
|
12
|
-
from rdflib import Literal
|
|
13
|
-
from rdflib import Namespace
|
|
14
|
-
from rdflib import URIRef
|
|
15
5
|
|
|
16
|
-
from dsp_tools.
|
|
17
|
-
from dsp_tools.commands.xmlupload.
|
|
18
|
-
from dsp_tools.commands.xmlupload.models.deserialise.deserialise_value import IIIFUriInfo
|
|
19
|
-
from dsp_tools.commands.xmlupload.models.deserialise.deserialise_value import XMLProperty
|
|
20
|
-
from dsp_tools.commands.xmlupload.models.deserialise.deserialise_value import XMLValue
|
|
21
|
-
from dsp_tools.commands.xmlupload.models.deserialise.xmlresource import BitstreamInfo
|
|
22
|
-
from dsp_tools.commands.xmlupload.models.deserialise.xmlresource import XMLResource
|
|
23
|
-
from dsp_tools.commands.xmlupload.models.formatted_text_value import FormattedTextValue
|
|
24
|
-
from dsp_tools.commands.xmlupload.models.namespace_context import get_json_ld_context_for_project
|
|
25
|
-
from dsp_tools.commands.xmlupload.models.namespace_context import make_namespace_dict_from_onto_names
|
|
26
|
-
from dsp_tools.commands.xmlupload.models.permission import Permissions
|
|
27
|
-
from dsp_tools.commands.xmlupload.models.serialise.jsonld_serialiser import serialise_property_graph
|
|
28
|
-
from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseProperty
|
|
29
|
-
from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseURI
|
|
30
|
-
from dsp_tools.commands.xmlupload.models.serialise.serialise_value import SerialiseValue
|
|
31
|
-
from dsp_tools.models.exceptions import BaseError
|
|
32
|
-
from dsp_tools.models.exceptions import InputError
|
|
33
|
-
from dsp_tools.models.exceptions import PermissionNotExistsError
|
|
34
|
-
from dsp_tools.models.exceptions import UserError
|
|
35
|
-
from dsp_tools.utils.connection import Connection
|
|
36
|
-
from dsp_tools.utils.date_util import parse_date_string
|
|
37
|
-
from dsp_tools.utils.iri_util import is_resource_iri
|
|
38
|
-
from dsp_tools.utils.logger_config import WARNINGS_SAVEPATH
|
|
39
|
-
|
|
40
|
-
KNORA_API = Namespace("http://api.knora.org/ontology/knora-api/v2#")
|
|
6
|
+
from dsp_tools.clients.connection import Connection
|
|
7
|
+
from dsp_tools.commands.xmlupload.make_rdf_graph.jsonld_utils import serialise_jsonld_for_resource
|
|
41
8
|
|
|
42
9
|
|
|
43
10
|
@dataclass(frozen=True)
|
|
@@ -45,442 +12,14 @@ class ResourceCreateClient:
|
|
|
45
12
|
"""client class that creates resources on a DSP server."""
|
|
46
13
|
|
|
47
14
|
con: Connection
|
|
48
|
-
project_iri: str
|
|
49
|
-
iri_resolver: IriResolver
|
|
50
|
-
project_onto_dict: dict[str, str]
|
|
51
|
-
permissions_lookup: dict[str, Permissions]
|
|
52
|
-
listnode_lookup: dict[str, str]
|
|
53
|
-
media_previously_ingested: bool = False
|
|
54
15
|
|
|
55
16
|
def create_resource(
|
|
56
17
|
self,
|
|
57
|
-
|
|
58
|
-
|
|
18
|
+
graph: Graph,
|
|
19
|
+
resource_has_bitstream: bool,
|
|
59
20
|
) -> str:
|
|
60
21
|
"""Creates a resource on the DSP server, and returns its IRI"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
resource_dict = self._make_resource_with_values(resource, bitstream_information)
|
|
65
|
-
headers = {"X-Asset-Ingested": "true"} if bitstream_information else None
|
|
66
|
-
res = self.con.post(route="/v2/resources", data=resource_dict, headers=headers)
|
|
22
|
+
res_dict = serialise_jsonld_for_resource(graph)
|
|
23
|
+
headers = {"X-Asset-Ingested": "true"} if resource_has_bitstream else None
|
|
24
|
+
res = self.con.post(route="/v2/resources", data=res_dict, headers=headers)
|
|
67
25
|
return cast(str, res["@id"])
|
|
68
|
-
|
|
69
|
-
def _make_resource_with_values(
|
|
70
|
-
self,
|
|
71
|
-
resource: XMLResource,
|
|
72
|
-
bitstream_information: BitstreamInfo | None,
|
|
73
|
-
) -> dict[str, Any]:
|
|
74
|
-
res_bnode = BNode()
|
|
75
|
-
namespaces = make_namespace_dict_from_onto_names(self.project_onto_dict)
|
|
76
|
-
res = self._make_resource(
|
|
77
|
-
resource=resource,
|
|
78
|
-
bitstream_information=bitstream_information,
|
|
79
|
-
)
|
|
80
|
-
vals = self._make_values(resource, res_bnode, namespaces)
|
|
81
|
-
res.update(vals)
|
|
82
|
-
return res
|
|
83
|
-
|
|
84
|
-
def _make_resource(
|
|
85
|
-
self,
|
|
86
|
-
resource: XMLResource,
|
|
87
|
-
bitstream_information: BitstreamInfo | None,
|
|
88
|
-
) -> dict[str, Any]:
|
|
89
|
-
resource_iri = resource.iri
|
|
90
|
-
if resource.ark:
|
|
91
|
-
resource_iri = convert_ark_v0_to_resource_iri(resource.ark)
|
|
92
|
-
context = get_json_ld_context_for_project(self.project_onto_dict)
|
|
93
|
-
res = {
|
|
94
|
-
"@type": resource.restype,
|
|
95
|
-
"rdfs:label": resource.label,
|
|
96
|
-
"knora-api:attachedToProject": {"@id": self.project_iri},
|
|
97
|
-
"@context": context,
|
|
98
|
-
}
|
|
99
|
-
if resource_iri:
|
|
100
|
-
res["@id"] = resource_iri
|
|
101
|
-
if resource.permissions:
|
|
102
|
-
if perm := self.permissions_lookup.get(resource.permissions):
|
|
103
|
-
res["knora-api:hasPermissions"] = str(perm)
|
|
104
|
-
else:
|
|
105
|
-
raise PermissionNotExistsError(
|
|
106
|
-
f"Could not find permissions for resource {resource.res_id} with permissions {resource.permissions}"
|
|
107
|
-
)
|
|
108
|
-
if resource.creation_date:
|
|
109
|
-
res["knora-api:creationDate"] = {
|
|
110
|
-
"@type": "xsd:dateTimeStamp",
|
|
111
|
-
"@value": str(resource.creation_date),
|
|
112
|
-
}
|
|
113
|
-
if bitstream_information:
|
|
114
|
-
res.update(_make_bitstream_file_value(bitstream_information))
|
|
115
|
-
return res
|
|
116
|
-
|
|
117
|
-
def _make_values(self, resource: XMLResource, res_bnode: BNode, namespaces: dict[str, Namespace]) -> dict[str, Any]:
|
|
118
|
-
def prop_name(p: XMLProperty) -> str:
|
|
119
|
-
if p.valtype != "resptr":
|
|
120
|
-
return p.name
|
|
121
|
-
elif p.name == "knora-api:isSegmentOf" and resource.restype == "knora-api:VideoSegment":
|
|
122
|
-
return "knora-api:isVideoSegmentOfValue"
|
|
123
|
-
elif p.name == "knora-api:isSegmentOf" and resource.restype == "knora-api:AudioSegment":
|
|
124
|
-
return "knora-api:isAudioSegmentOfValue"
|
|
125
|
-
else:
|
|
126
|
-
return f"{p.name}Value"
|
|
127
|
-
|
|
128
|
-
def make_values(p: XMLProperty) -> list[dict[str, Any]]:
|
|
129
|
-
return [self._make_value(v, p.valtype) for v in p.values]
|
|
130
|
-
|
|
131
|
-
properties_serialised = {}
|
|
132
|
-
properties_graph = Graph()
|
|
133
|
-
# To frame the json-ld correctly, we need one property used in the graph. It does not matter which.
|
|
134
|
-
last_prop_name = None
|
|
135
|
-
|
|
136
|
-
for prop in resource.properties:
|
|
137
|
-
match prop.valtype:
|
|
138
|
-
case "uri":
|
|
139
|
-
properties_serialised.update(_serialise_uri_prop(prop, self.permissions_lookup))
|
|
140
|
-
case "integer":
|
|
141
|
-
int_prop_name = self._get_absolute_prop_iri(prop.name, namespaces)
|
|
142
|
-
int_graph = _make_integer_prop(prop, res_bnode, int_prop_name, self.permissions_lookup)
|
|
143
|
-
properties_graph += int_graph
|
|
144
|
-
last_prop_name = int_prop_name
|
|
145
|
-
case "boolean":
|
|
146
|
-
bool_prop_name = self._get_absolute_prop_iri(prop.name, namespaces)
|
|
147
|
-
bool_graph = _make_boolean_prop(prop, res_bnode, bool_prop_name, self.permissions_lookup)
|
|
148
|
-
properties_graph += bool_graph
|
|
149
|
-
last_prop_name = bool_prop_name
|
|
150
|
-
case _:
|
|
151
|
-
properties_serialised[prop_name(prop)] = make_values(prop)
|
|
152
|
-
if resource.iiif_uri:
|
|
153
|
-
properties_graph += _make_iiif_uri_value(resource.iiif_uri, res_bnode, self.permissions_lookup)
|
|
154
|
-
last_prop_name = KNORA_API.hasStillImageFileValue
|
|
155
|
-
if last_prop_name:
|
|
156
|
-
serialised_graph_props = serialise_property_graph(properties_graph, last_prop_name)
|
|
157
|
-
properties_serialised.update(serialised_graph_props)
|
|
158
|
-
return properties_serialised
|
|
159
|
-
|
|
160
|
-
def _get_absolute_prop_iri(self, prefixed_prop: str, namespaces: dict[str, Namespace]) -> URIRef:
|
|
161
|
-
prefix, prop = prefixed_prop.split(":", maxsplit=1)
|
|
162
|
-
if not (namespace := namespaces.get(prefix)):
|
|
163
|
-
raise InputError(f"Could not find namespace for prefix: {prefix}")
|
|
164
|
-
return namespace[prop]
|
|
165
|
-
|
|
166
|
-
def _make_value(self, value: XMLValue, value_type: str) -> dict[str, Any]: # noqa: PLR0912 (too many branches)
|
|
167
|
-
match value_type:
|
|
168
|
-
case "color":
|
|
169
|
-
res = _make_color_value(value)
|
|
170
|
-
case "date":
|
|
171
|
-
res = _make_date_value(value)
|
|
172
|
-
case "decimal":
|
|
173
|
-
res = _make_decimal_value(value)
|
|
174
|
-
case "geometry":
|
|
175
|
-
res = _make_geometry_value(value)
|
|
176
|
-
case "geoname":
|
|
177
|
-
res = _make_geoname_value(value)
|
|
178
|
-
case "interval":
|
|
179
|
-
res = _make_interval_value(value)
|
|
180
|
-
case "resptr":
|
|
181
|
-
res = _make_link_value(value, self.iri_resolver)
|
|
182
|
-
case "list":
|
|
183
|
-
res = _make_list_value(value, self.listnode_lookup)
|
|
184
|
-
case "text":
|
|
185
|
-
res = _make_text_value(value, self.iri_resolver)
|
|
186
|
-
case "time":
|
|
187
|
-
res = _make_time_value(value)
|
|
188
|
-
case _:
|
|
189
|
-
raise UserError(f"Unknown value type: {value_type}")
|
|
190
|
-
if value.comment:
|
|
191
|
-
res["knora-api:valueHasComment"] = value.comment
|
|
192
|
-
if value.permissions:
|
|
193
|
-
if perm := self.permissions_lookup.get(value.permissions):
|
|
194
|
-
res["knora-api:hasPermissions"] = str(perm)
|
|
195
|
-
else:
|
|
196
|
-
raise PermissionNotExistsError(f"Could not find permissions for value: {value.permissions}")
|
|
197
|
-
return res
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
def _add_optional_permission_triple(
|
|
201
|
-
value: XMLValue | IIIFUriInfo, val_bn: BNode, g: Graph, permissions_lookup: dict[str, Permissions]
|
|
202
|
-
) -> None:
|
|
203
|
-
if value.permissions:
|
|
204
|
-
if not (per := permissions_lookup.get(value.permissions)):
|
|
205
|
-
raise PermissionNotExistsError(f"Could not find permissions for value: {value.permissions}")
|
|
206
|
-
g.add((val_bn, KNORA_API.hasPermissions, Literal(str(per))))
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def _make_iiif_uri_value(iiif_uri: IIIFUriInfo, res_bnode: BNode, permissions_lookup: dict[str, Permissions]) -> Graph:
|
|
210
|
-
g = Graph()
|
|
211
|
-
iiif_bn = BNode()
|
|
212
|
-
g.add((res_bnode, KNORA_API.hasStillImageFileValue, iiif_bn))
|
|
213
|
-
g.add((iiif_bn, RDF.type, KNORA_API.StillImageExternalFileValue))
|
|
214
|
-
g.add((iiif_bn, KNORA_API.fileValueHasExternalUrl, Literal(iiif_uri.value)))
|
|
215
|
-
_add_optional_permission_triple(iiif_uri, iiif_bn, g, permissions_lookup)
|
|
216
|
-
return g
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def _make_bitstream_file_value(bitstream_info: BitstreamInfo) -> dict[str, Any]:
|
|
220
|
-
local_file = Path(bitstream_info.local_file)
|
|
221
|
-
file_ending = local_file.suffix[1:]
|
|
222
|
-
match file_ending.lower():
|
|
223
|
-
case "zip" | "tar" | "gz" | "z" | "tgz" | "gzip" | "7z":
|
|
224
|
-
prop = "knora-api:hasArchiveFileValue"
|
|
225
|
-
value_type = "ArchiveFileValue"
|
|
226
|
-
case "mp3" | "wav":
|
|
227
|
-
prop = "knora-api:hasAudioFileValue"
|
|
228
|
-
value_type = "AudioFileValue"
|
|
229
|
-
case "pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx":
|
|
230
|
-
prop = "knora-api:hasDocumentFileValue"
|
|
231
|
-
value_type = "DocumentFileValue"
|
|
232
|
-
case "mp4":
|
|
233
|
-
prop = "knora-api:hasMovingImageFileValue"
|
|
234
|
-
value_type = "MovingImageFileValue"
|
|
235
|
-
# jpx is the extension of the files returned by dsp-ingest
|
|
236
|
-
case "jpg" | "jpeg" | "jp2" | "png" | "tif" | "tiff" | "jpx":
|
|
237
|
-
prop = "knora-api:hasStillImageFileValue"
|
|
238
|
-
value_type = "StillImageFileValue"
|
|
239
|
-
case "odd" | "rng" | "txt" | "xml" | "xsd" | "xsl" | "csv":
|
|
240
|
-
prop = "knora-api:hasTextFileValue"
|
|
241
|
-
value_type = "TextFileValue"
|
|
242
|
-
case _:
|
|
243
|
-
raise BaseError(f"Unknown file ending '{file_ending}' for file '{local_file}'")
|
|
244
|
-
file_value = {
|
|
245
|
-
"@type": f"knora-api:{value_type}",
|
|
246
|
-
"knora-api:fileValueHasFilename": bitstream_info.internal_file_name,
|
|
247
|
-
}
|
|
248
|
-
if bitstream_info.permissions:
|
|
249
|
-
file_value["knora-api:hasPermissions"] = str(bitstream_info.permissions)
|
|
250
|
-
return {prop: file_value}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def _to_boolean(s: str | int | bool) -> bool:
|
|
254
|
-
match s:
|
|
255
|
-
case "True" | "true" | "1" | 1 | True:
|
|
256
|
-
return True
|
|
257
|
-
case "False" | "false" | "0" | 0 | False:
|
|
258
|
-
return False
|
|
259
|
-
case _:
|
|
260
|
-
raise BaseError(f"Could not parse boolean value: {s}")
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
def _make_color_value(value: XMLValue) -> dict[str, Any]:
|
|
264
|
-
return {
|
|
265
|
-
"@type": "knora-api:ColorValue",
|
|
266
|
-
"knora-api:colorValueAsColor": value.value,
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
def _make_date_value(value: XMLValue) -> dict[str, Any]:
|
|
271
|
-
string_value = _assert_is_string(value.value)
|
|
272
|
-
date = parse_date_string(string_value)
|
|
273
|
-
res: dict[str, Any] = {
|
|
274
|
-
"@type": "knora-api:DateValue",
|
|
275
|
-
"knora-api:dateValueHasStartYear": date.start.year,
|
|
276
|
-
}
|
|
277
|
-
if month := date.start.month:
|
|
278
|
-
res["knora-api:dateValueHasStartMonth"] = month
|
|
279
|
-
if day := date.start.day:
|
|
280
|
-
res["knora-api:dateValueHasStartDay"] = day
|
|
281
|
-
if era := date.start.era:
|
|
282
|
-
res["knora-api:dateValueHasStartEra"] = era.value
|
|
283
|
-
if calendar := date.calendar:
|
|
284
|
-
res["knora-api:dateValueHasCalendar"] = calendar.value
|
|
285
|
-
if date.end:
|
|
286
|
-
res["knora-api:dateValueHasEndYear"] = date.end.year
|
|
287
|
-
if month := date.end.month:
|
|
288
|
-
res["knora-api:dateValueHasEndMonth"] = month
|
|
289
|
-
if day := date.end.day:
|
|
290
|
-
res["knora-api:dateValueHasEndDay"] = day
|
|
291
|
-
if era := date.end.era:
|
|
292
|
-
res["knora-api:dateValueHasEndEra"] = era.value
|
|
293
|
-
return res
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
def _make_decimal_value(value: XMLValue) -> dict[str, Any]:
|
|
297
|
-
s = _assert_is_string(value.value)
|
|
298
|
-
return {
|
|
299
|
-
"@type": "knora-api:DecimalValue",
|
|
300
|
-
"knora-api:decimalValueAsDecimal": {
|
|
301
|
-
"@type": "xsd:decimal",
|
|
302
|
-
"@value": str(float(s)),
|
|
303
|
-
},
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def _make_geometry_value(value: XMLValue) -> dict[str, Any]:
|
|
308
|
-
s = _assert_is_string(value.value)
|
|
309
|
-
# this removes all whitespaces from the embedded json string
|
|
310
|
-
encoded_value = json.dumps(json.loads(s))
|
|
311
|
-
return {
|
|
312
|
-
"@type": "knora-api:GeomValue",
|
|
313
|
-
"knora-api:geometryValueAsGeometry": encoded_value,
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
def _make_geoname_value(value: XMLValue) -> dict[str, Any]:
|
|
318
|
-
return {
|
|
319
|
-
"@type": "knora-api:GeonameValue",
|
|
320
|
-
"knora-api:geonameValueAsGeonameCode": value.value,
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
def _make_boolean_prop(
|
|
325
|
-
prop: XMLProperty, res_bn: BNode, prop_name: URIRef, permissions_lookup: dict[str, Permissions]
|
|
326
|
-
) -> Graph:
|
|
327
|
-
g = Graph()
|
|
328
|
-
for value in prop.values:
|
|
329
|
-
single_val_bn = BNode()
|
|
330
|
-
g.add((res_bn, prop_name, single_val_bn))
|
|
331
|
-
g += _make_boolean_value(value, single_val_bn, permissions_lookup)
|
|
332
|
-
return g
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
def _make_boolean_value(value: XMLValue, val_bn: BNode, permissions_lookup: dict[str, Permissions]) -> Graph:
|
|
336
|
-
s = _assert_is_string(value.value)
|
|
337
|
-
g = Graph()
|
|
338
|
-
g.add((val_bn, RDF.type, KNORA_API.BooleanValue))
|
|
339
|
-
g.add((val_bn, KNORA_API.booleanValueAsBoolean, Literal(_to_boolean(s))))
|
|
340
|
-
_add_optional_permission_triple(value, val_bn, g, permissions_lookup)
|
|
341
|
-
if value.comment:
|
|
342
|
-
g.add((val_bn, KNORA_API.valueHasComment, Literal(value.comment)))
|
|
343
|
-
return g
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
def _make_integer_prop(
|
|
347
|
-
prop: XMLProperty, res_bn: BNode, prop_name: URIRef, permissions_lookup: dict[str, Permissions]
|
|
348
|
-
) -> Graph:
|
|
349
|
-
g = Graph()
|
|
350
|
-
for value in prop.values:
|
|
351
|
-
single_val_bn = BNode()
|
|
352
|
-
g.add((res_bn, prop_name, single_val_bn))
|
|
353
|
-
g += _make_integer_value(value, single_val_bn, permissions_lookup)
|
|
354
|
-
return g
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
def _make_integer_value(value: XMLValue, val_bn: BNode, permissions_lookup: dict[str, Permissions]) -> Graph:
|
|
358
|
-
s = _assert_is_string(value.value)
|
|
359
|
-
g = Graph()
|
|
360
|
-
g.add((val_bn, RDF.type, KNORA_API.IntValue))
|
|
361
|
-
g.add((val_bn, KNORA_API.intValueAsInt, Literal(int(s))))
|
|
362
|
-
_add_optional_permission_triple(value, val_bn, g, permissions_lookup)
|
|
363
|
-
if value.comment:
|
|
364
|
-
g.add((val_bn, KNORA_API.valueHasComment, Literal(value.comment)))
|
|
365
|
-
return g
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
def _make_interval_value(value: XMLValue) -> dict[str, Any]:
|
|
369
|
-
s = _assert_is_string(value.value)
|
|
370
|
-
match s.split(":", 1):
|
|
371
|
-
case [start, end]:
|
|
372
|
-
return {
|
|
373
|
-
"@type": "knora-api:IntervalValue",
|
|
374
|
-
"knora-api:intervalValueHasStart": {
|
|
375
|
-
"@type": "xsd:decimal",
|
|
376
|
-
"@value": str(float(start)),
|
|
377
|
-
},
|
|
378
|
-
"knora-api:intervalValueHasEnd": {
|
|
379
|
-
"@type": "xsd:decimal",
|
|
380
|
-
"@value": str(float(end)),
|
|
381
|
-
},
|
|
382
|
-
}
|
|
383
|
-
case _:
|
|
384
|
-
raise BaseError(f"Could not parse interval value: {s}")
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
def _make_link_value(value: XMLValue, iri_resolver: IriResolver) -> dict[str, Any]:
|
|
388
|
-
s = _assert_is_string(value.value)
|
|
389
|
-
if is_resource_iri(s):
|
|
390
|
-
iri = s
|
|
391
|
-
elif resolved_iri := iri_resolver.get(s):
|
|
392
|
-
iri = resolved_iri
|
|
393
|
-
else:
|
|
394
|
-
msg = (
|
|
395
|
-
f"Could not find the ID {s} in the id2iri mapping. "
|
|
396
|
-
f"This is probably because the resource '{s}' could not be created. "
|
|
397
|
-
f"See {WARNINGS_SAVEPATH} for more information."
|
|
398
|
-
)
|
|
399
|
-
raise BaseError(msg)
|
|
400
|
-
return {
|
|
401
|
-
"@type": "knora-api:LinkValue",
|
|
402
|
-
"knora-api:linkValueHasTargetIri": {
|
|
403
|
-
"@id": iri,
|
|
404
|
-
},
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
def _make_list_value(value: XMLValue, iri_lookup: dict[str, str]) -> dict[str, Any]:
|
|
409
|
-
s = _assert_is_string(value.value)
|
|
410
|
-
if iri := iri_lookup.get(s):
|
|
411
|
-
return {
|
|
412
|
-
"@type": "knora-api:ListValue",
|
|
413
|
-
"knora-api:listValueAsListNode": {
|
|
414
|
-
"@id": iri,
|
|
415
|
-
},
|
|
416
|
-
}
|
|
417
|
-
else:
|
|
418
|
-
msg = (
|
|
419
|
-
f"Could not resolve list node ID '{s}' to IRI. "
|
|
420
|
-
f"This is probably because the list node '{s}' does not exist on the server."
|
|
421
|
-
)
|
|
422
|
-
raise BaseError(msg)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
def _make_text_value(value: XMLValue, iri_resolver: IriResolver) -> dict[str, Any]:
|
|
426
|
-
match value.value:
|
|
427
|
-
case str() as s:
|
|
428
|
-
return {
|
|
429
|
-
"@type": "knora-api:TextValue",
|
|
430
|
-
"knora-api:valueAsString": s,
|
|
431
|
-
}
|
|
432
|
-
case FormattedTextValue() as xml:
|
|
433
|
-
xml_with_iris = xml.with_iris(iri_resolver)
|
|
434
|
-
return {
|
|
435
|
-
"@type": "knora-api:TextValue",
|
|
436
|
-
"knora-api:textValueAsXml": xml_with_iris.as_xml(),
|
|
437
|
-
"knora-api:textValueHasMapping": {
|
|
438
|
-
"@id": "http://rdfh.ch/standoff/mappings/StandardMapping",
|
|
439
|
-
},
|
|
440
|
-
}
|
|
441
|
-
case _:
|
|
442
|
-
assert_never(value.value)
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
def _make_time_value(value: XMLValue) -> dict[str, Any]:
|
|
446
|
-
return {
|
|
447
|
-
"@type": "knora-api:TimeValue",
|
|
448
|
-
"knora-api:timeValueAsTimeStamp": {
|
|
449
|
-
"@type": "xsd:dateTimeStamp",
|
|
450
|
-
"@value": value.value,
|
|
451
|
-
},
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
def _serialise_uri_prop(prop: XMLProperty, permissions_lookup: dict[str, Permissions]) -> dict[str, Any]:
|
|
456
|
-
uri_values: list[SerialiseValue] = []
|
|
457
|
-
for v in prop.values:
|
|
458
|
-
if v.permissions:
|
|
459
|
-
if not (per := permissions_lookup.get(v.permissions)):
|
|
460
|
-
raise PermissionNotExistsError(f"Could not find permissions for value: {v.permissions}")
|
|
461
|
-
permission = str(per)
|
|
462
|
-
else:
|
|
463
|
-
permission = None
|
|
464
|
-
uri = cast(str, v.value)
|
|
465
|
-
uri_values.append(
|
|
466
|
-
SerialiseURI(
|
|
467
|
-
value=uri,
|
|
468
|
-
permissions=permission,
|
|
469
|
-
comment=v.comment,
|
|
470
|
-
)
|
|
471
|
-
)
|
|
472
|
-
prop_serialise = SerialiseProperty(
|
|
473
|
-
property_name=prop.name,
|
|
474
|
-
values=uri_values,
|
|
475
|
-
)
|
|
476
|
-
return prop_serialise.serialise()
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
def _assert_is_string(value: str | FormattedTextValue) -> str:
|
|
480
|
-
match value:
|
|
481
|
-
case str() as s:
|
|
482
|
-
return s
|
|
483
|
-
case FormattedTextValue() as xml:
|
|
484
|
-
raise BaseError(f"Expected string value, but got XML value: {xml.as_xml()}")
|
|
485
|
-
case _:
|
|
486
|
-
assert_never(value)
|