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
dsp_tools/xmllib/models/root.py
CHANGED
|
@@ -1,26 +1,304 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
import warnings
|
|
5
|
+
from collections.abc import Collection
|
|
3
6
|
from dataclasses import dataclass
|
|
4
7
|
from dataclasses import field
|
|
5
8
|
from pathlib import Path
|
|
9
|
+
from typing import Union
|
|
10
|
+
from uuid import uuid4
|
|
6
11
|
|
|
12
|
+
import pandas as pd
|
|
13
|
+
from dotenv import find_dotenv
|
|
14
|
+
from dotenv import load_dotenv
|
|
15
|
+
from loguru import logger
|
|
7
16
|
from lxml import etree
|
|
8
17
|
|
|
9
|
-
from dsp_tools.
|
|
10
|
-
from dsp_tools.
|
|
11
|
-
from dsp_tools.
|
|
18
|
+
from dsp_tools.error.custom_warnings import DspToolsFutureWarning
|
|
19
|
+
from dsp_tools.error.xmllib_warnings import MessageInfo
|
|
20
|
+
from dsp_tools.error.xmllib_warnings_util import emit_xmllib_input_warning
|
|
21
|
+
from dsp_tools.utils.ansi_colors import BOLD_GREEN
|
|
22
|
+
from dsp_tools.utils.ansi_colors import BOLD_RED
|
|
23
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
24
|
+
from dsp_tools.utils.xml_parsing.parse_clean_validate_xml import validate_root_emit_user_message
|
|
25
|
+
from dsp_tools.xmllib.internal.constants import DASCH_SCHEMA
|
|
26
|
+
from dsp_tools.xmllib.internal.constants import XML_NAMESPACE_MAP
|
|
27
|
+
from dsp_tools.xmllib.internal.serialise_resource import serialise_resources
|
|
28
|
+
from dsp_tools.xmllib.models.dsp_base_resources import AudioSegmentResource
|
|
29
|
+
from dsp_tools.xmllib.models.dsp_base_resources import LinkResource
|
|
30
|
+
from dsp_tools.xmllib.models.dsp_base_resources import RegionResource
|
|
31
|
+
from dsp_tools.xmllib.models.dsp_base_resources import VideoSegmentResource
|
|
32
|
+
from dsp_tools.xmllib.models.internal.file_values import AuthorshipLookup
|
|
33
|
+
from dsp_tools.xmllib.models.internal.serialise_permissions import XMLPermissions
|
|
34
|
+
from dsp_tools.xmllib.models.permissions import Permissions
|
|
35
|
+
from dsp_tools.xmllib.models.res import Resource
|
|
12
36
|
|
|
13
|
-
|
|
14
|
-
|
|
37
|
+
type AnyResource = Union[Resource, RegionResource, LinkResource, VideoSegmentResource, AudioSegmentResource]
|
|
38
|
+
|
|
39
|
+
load_dotenv(dotenv_path=find_dotenv(usecwd=True))
|
|
15
40
|
|
|
16
41
|
|
|
17
42
|
@dataclass
|
|
18
43
|
class XMLRoot:
|
|
19
44
|
shortcode: str
|
|
20
45
|
default_ontology: str
|
|
21
|
-
resources: list[
|
|
46
|
+
resources: list[AnyResource] = field(default_factory=list)
|
|
47
|
+
_res_id_to_type_lookup: dict[str, list[str]] = field(default_factory=dict)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def create_new(shortcode: str, default_ontology: str) -> XMLRoot:
|
|
51
|
+
"""
|
|
52
|
+
Create a new XML root, for one file.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
shortcode: project shortcode
|
|
56
|
+
default_ontology: name of the default ontology
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Instance of `XMLRoot`
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
```python
|
|
63
|
+
root = xmllib.XMLRoot.create_new(
|
|
64
|
+
shortcode="0000",
|
|
65
|
+
default_ontology="onto"
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
"""
|
|
69
|
+
return XMLRoot(shortcode=shortcode, default_ontology=default_ontology)
|
|
70
|
+
|
|
71
|
+
def add_resource(self, resource: AnyResource) -> XMLRoot:
|
|
72
|
+
"""
|
|
73
|
+
Add one resource to the root.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
resource: any one of:
|
|
77
|
+
`Resource`,
|
|
78
|
+
`RegionResource`,
|
|
79
|
+
`LinkResource`,
|
|
80
|
+
`VideoSegmentResource`,
|
|
81
|
+
`AudioSegmentResource`
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The original XMLRoot, with the added resource
|
|
85
|
+
|
|
86
|
+
Warning:
|
|
87
|
+
If the ID of the new resource is already used.
|
|
88
|
+
|
|
89
|
+
Examples:
|
|
90
|
+
```python
|
|
91
|
+
resource = xmllib.Resource.create_new(
|
|
92
|
+
res_id="ID", restype=":ResourceType", label="label"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
root = root.add_resource(resource)
|
|
96
|
+
```
|
|
97
|
+
"""
|
|
98
|
+
if isinstance(resource, Resource):
|
|
99
|
+
res_type = resource.restype
|
|
100
|
+
else:
|
|
101
|
+
res_type = resource.__class__.__name__
|
|
102
|
+
if types_used := self._res_id_to_type_lookup.get(resource.res_id):
|
|
103
|
+
existing_types = [f"'{x}'" for x in types_used]
|
|
104
|
+
msg = (
|
|
105
|
+
f"The ID for this resource of type '{res_type}' "
|
|
106
|
+
f"is already used by resource(s) of the following type(s): {', '.join(existing_types)}."
|
|
107
|
+
)
|
|
108
|
+
info_msg = MessageInfo(
|
|
109
|
+
message=msg,
|
|
110
|
+
resource_id=resource.res_id,
|
|
111
|
+
field="Resource ID",
|
|
112
|
+
)
|
|
113
|
+
emit_xmllib_input_warning(info_msg)
|
|
114
|
+
self._res_id_to_type_lookup[resource.res_id].append(res_type)
|
|
115
|
+
else:
|
|
116
|
+
self._res_id_to_type_lookup[resource.res_id] = [res_type]
|
|
117
|
+
self.resources.append(resource)
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
def add_resource_multiple(self, resources: Collection[AnyResource]) -> XMLRoot:
|
|
121
|
+
"""
|
|
122
|
+
Add a list of resources to the root.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
resources: a list of:
|
|
126
|
+
`Resource`,
|
|
127
|
+
`RegionResource`,
|
|
128
|
+
`LinkResource`,
|
|
129
|
+
`VideoSegmentResource`,
|
|
130
|
+
`AudioSegmentResource`
|
|
131
|
+
The types of the resources may be mixed.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
The original XMLRoot, with the added resource
|
|
135
|
+
|
|
136
|
+
Warning:
|
|
137
|
+
If the ID of the new resource is already used.
|
|
138
|
+
|
|
139
|
+
Examples:
|
|
140
|
+
```python
|
|
141
|
+
resource_1 = xmllib.Resource.create_new(
|
|
142
|
+
res_id="ID_1", restype=":ResourceType", label="label 1"
|
|
143
|
+
)
|
|
144
|
+
resource_2 = xmllib.Resource.create_new(
|
|
145
|
+
res_id="ID_2", restype=":ResourceType", label="label 2"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
root = root.add_resource_multiple([resource_1, resource_2])
|
|
149
|
+
```
|
|
150
|
+
"""
|
|
151
|
+
for res in resources:
|
|
152
|
+
self.add_resource(res)
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
def add_resource_optional(self, resource: AnyResource | None) -> XMLRoot:
|
|
156
|
+
"""
|
|
157
|
+
If the resource is not None, add it to the XMLRoot, otherwise return the XMLRoot unchanged.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
resource: any one of:
|
|
161
|
+
`Resource`,
|
|
162
|
+
`RegionResource`,
|
|
163
|
+
`LinkResource`,
|
|
164
|
+
`VideoSegmentResource`,
|
|
165
|
+
`AudioSegmentResource`
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
The original XMLRoot, with the added value if it was not empty. Else the unchanged original XMLRoot.
|
|
169
|
+
|
|
170
|
+
Warning:
|
|
171
|
+
If the ID of the new resource is already used.
|
|
172
|
+
|
|
173
|
+
Examples:
|
|
174
|
+
```python
|
|
175
|
+
resource = xmllib.Resource.create_new(
|
|
176
|
+
res_id="ID", restype=":ResourceType", label="label"
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
root = root.add_resource_optional(resource)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
root = root.add_resource_optional(None)
|
|
184
|
+
```
|
|
185
|
+
"""
|
|
186
|
+
if resource:
|
|
187
|
+
self.add_resource(resource)
|
|
188
|
+
return self
|
|
189
|
+
|
|
190
|
+
def write_file(self, filepath: str | Path, default_permissions: Permissions | None = None) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Write the finished XML to a file.
|
|
22
193
|
|
|
23
|
-
|
|
194
|
+
Args:
|
|
195
|
+
filepath: where to save the file
|
|
196
|
+
default_permissions: This parameter is deprecated and has no effect.
|
|
197
|
+
Default permissions can be set in the JSON project file.
|
|
198
|
+
|
|
199
|
+
Warning:
|
|
200
|
+
if the XML is not valid according to the schema
|
|
201
|
+
|
|
202
|
+
Examples:
|
|
203
|
+
```python
|
|
204
|
+
root.write_file("xml_file_name.xml")
|
|
205
|
+
```
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
if default_permissions:
|
|
209
|
+
msg = (
|
|
210
|
+
"You added a default permission. This has no effect. This functionality is deprecated, "
|
|
211
|
+
"because project wide default permissions are set in the JSON project file. "
|
|
212
|
+
"This parameter will be removed soon."
|
|
213
|
+
)
|
|
214
|
+
warnings.warn(DspToolsFutureWarning(msg))
|
|
215
|
+
|
|
216
|
+
root = self.serialise()
|
|
217
|
+
|
|
218
|
+
# The logging is only configured when using the CLI entry point.
|
|
219
|
+
# If this is not disabled, then the statements will also be printed out on the terminal.
|
|
220
|
+
logger.disable("dsp_tools")
|
|
221
|
+
validate_root_emit_user_message(root, Path(filepath).parent)
|
|
222
|
+
|
|
223
|
+
etree.indent(root, space=" ")
|
|
224
|
+
xml_string = etree.tostring(
|
|
225
|
+
root,
|
|
226
|
+
encoding="unicode",
|
|
227
|
+
pretty_print=True,
|
|
228
|
+
doctype='<?xml version="1.0" encoding="UTF-8"?>',
|
|
229
|
+
)
|
|
230
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
231
|
+
f.write(xml_string)
|
|
232
|
+
print(f"The XML file was successfully saved to {filepath}.")
|
|
233
|
+
if file_path := os.getenv("XMLLIB_WARNINGS_CSV_SAVEPATH"):
|
|
234
|
+
df = pd.read_csv(file_path)
|
|
235
|
+
if len(df) > 0:
|
|
236
|
+
msg = f"{len(df)} warnings occurred, please consult '{file_path}' for details."
|
|
237
|
+
print(BOLD_RED, msg, RESET_TO_DEFAULT)
|
|
238
|
+
else:
|
|
239
|
+
msg = "No warnings occurred during the runtime."
|
|
240
|
+
print(BOLD_GREEN, msg, RESET_TO_DEFAULT)
|
|
241
|
+
|
|
242
|
+
def serialise(self) -> etree._Element:
|
|
243
|
+
"""
|
|
244
|
+
Create an `lxml.etree._Element` with the information in the root.
|
|
245
|
+
If you wish to create a file, we recommend using the `write_file` method instead.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
The `XMLRoot` serialised as XML
|
|
249
|
+
"""
|
|
250
|
+
root = self._make_root()
|
|
251
|
+
root.extend(self._get_permissions())
|
|
252
|
+
author_lookup = _make_authorship_lookup(self.resources)
|
|
253
|
+
authorship = _serialise_authorship(author_lookup.lookup)
|
|
254
|
+
root.extend(authorship)
|
|
255
|
+
serialised_resources = serialise_resources(self.resources, author_lookup)
|
|
256
|
+
root.extend(serialised_resources)
|
|
257
|
+
return root
|
|
258
|
+
|
|
259
|
+
def _get_permissions(self) -> list[etree._Element]:
|
|
260
|
+
contains_old_permissions, contains_new_permissions = self._find_permission_types()
|
|
261
|
+
if contains_old_permissions:
|
|
262
|
+
msg = (
|
|
263
|
+
"Your data contains old permissions. Please migrate to the new ones:\n"
|
|
264
|
+
" - Permissions.OPEN -> use Permissions.PUBLIC instead\n"
|
|
265
|
+
" - Permissions.RESTRICTED -> use Permissions.PRIVATE instead\n"
|
|
266
|
+
" - Permissions.RESTRICTED_VIEW -> use Permissions.LIMITED_VIEW instead\n"
|
|
267
|
+
)
|
|
268
|
+
warnings.warn(msg, category=DspToolsFutureWarning)
|
|
269
|
+
return XMLPermissions().serialise(contains_old_permissions, contains_new_permissions)
|
|
270
|
+
|
|
271
|
+
def _find_permission_types(self) -> tuple[bool, bool]:
|
|
272
|
+
contains_old_permissions = False
|
|
273
|
+
contains_new_permissions = False
|
|
274
|
+
for res in self.resources:
|
|
275
|
+
if self._is_old(res.permissions):
|
|
276
|
+
contains_old_permissions = True
|
|
277
|
+
elif self._is_new(res.permissions):
|
|
278
|
+
contains_new_permissions = True
|
|
279
|
+
for val in res.values:
|
|
280
|
+
if self._is_old(val.permissions):
|
|
281
|
+
contains_old_permissions = True
|
|
282
|
+
elif self._is_new(val.permissions):
|
|
283
|
+
contains_new_permissions = True
|
|
284
|
+
if isinstance(res, Resource):
|
|
285
|
+
if res.file_value:
|
|
286
|
+
if self._is_old(res.file_value.metadata.permissions):
|
|
287
|
+
contains_old_permissions = True
|
|
288
|
+
elif self._is_new(res.file_value.metadata.permissions):
|
|
289
|
+
contains_new_permissions = True
|
|
290
|
+
if contains_old_permissions and contains_new_permissions:
|
|
291
|
+
# no need to continue, the end result won't change any more
|
|
292
|
+
return True, True
|
|
293
|
+
return contains_old_permissions, contains_new_permissions
|
|
294
|
+
|
|
295
|
+
def _is_old(self, perm: Permissions) -> bool:
|
|
296
|
+
return perm in [Permissions.OPEN, Permissions.RESTRICTED_VIEW, Permissions.RESTRICTED]
|
|
297
|
+
|
|
298
|
+
def _is_new(self, perm: Permissions) -> bool:
|
|
299
|
+
return perm in [Permissions.PUBLIC, Permissions.LIMITED_VIEW, Permissions.PRIVATE]
|
|
300
|
+
|
|
301
|
+
def _make_root(self) -> etree._Element:
|
|
24
302
|
schema_url = (
|
|
25
303
|
"https://raw.githubusercontent.com/dasch-swiss/dsp-tools/main/src/dsp_tools/resources/schema/data.xsd"
|
|
26
304
|
)
|
|
@@ -36,26 +314,35 @@ class XMLRoot:
|
|
|
36
314
|
nsmap=XML_NAMESPACE_MAP,
|
|
37
315
|
)
|
|
38
316
|
|
|
39
|
-
def add_resource(self, resource: Resource) -> XMLRoot:
|
|
40
|
-
self.resources.append(resource)
|
|
41
|
-
return self
|
|
42
317
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
318
|
+
def _make_authorship_lookup(resources: list[AnyResource]) -> AuthorshipLookup:
|
|
319
|
+
filtered_resources = [x for x in resources if isinstance(x, Resource)]
|
|
320
|
+
file_vals = [x.file_value for x in filtered_resources if x.file_value]
|
|
321
|
+
authors = {x.metadata.authorship for x in file_vals if x.metadata.authorship}
|
|
322
|
+
sorted_authors = sorted(authors)
|
|
323
|
+
env_var = str(os.getenv("XMLLIB_AUTHORSHIP_ID_WITH_INTEGERS")).lower()
|
|
324
|
+
if env_var == "true":
|
|
325
|
+
auth_nums: list[int | str] = list(range(1, len(sorted_authors) + 1))
|
|
326
|
+
else:
|
|
327
|
+
auth_nums = [str(uuid4()) for _ in range(len(sorted_authors))]
|
|
328
|
+
auth_ids = [f"authorship_{x}" for x in auth_nums]
|
|
329
|
+
lookup = dict(zip(sorted_authors, auth_ids))
|
|
330
|
+
return AuthorshipLookup(lookup)
|
|
46
331
|
|
|
47
|
-
def add_resource_optional(self, resource: Resource | None) -> XMLRoot:
|
|
48
|
-
if resource:
|
|
49
|
-
self.resources.append(resource)
|
|
50
|
-
return self
|
|
51
332
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
root.extend(serialised_resources)
|
|
57
|
-
return root
|
|
333
|
+
def _serialise_authorship(authorship_lookup: dict[tuple[str, ...], str]) -> list[etree._Element]:
|
|
334
|
+
to_serialise = [(auth, id_) for auth, id_ in authorship_lookup.items()]
|
|
335
|
+
to_serialise = sorted(to_serialise, key=lambda x: x[0])
|
|
336
|
+
return [_make_one_authorship_element(auth, id_) for auth, id_ in to_serialise]
|
|
58
337
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
338
|
+
|
|
339
|
+
def _make_one_authorship_element(authors: tuple[str, ...], author_id: str) -> etree._Element:
|
|
340
|
+
def _make_one_author(author: str) -> etree._Element:
|
|
341
|
+
ele = etree.Element(f"{DASCH_SCHEMA}author", nsmap=XML_NAMESPACE_MAP)
|
|
342
|
+
ele.text = author
|
|
343
|
+
return ele
|
|
344
|
+
|
|
345
|
+
authorship_ele = etree.Element(f"{DASCH_SCHEMA}authorship", attrib={"id": author_id}, nsmap=XML_NAMESPACE_MAP)
|
|
346
|
+
all_authors = [_make_one_author(x) for x in authors]
|
|
347
|
+
authorship_ele.extend(all_authors)
|
|
348
|
+
return authorship_ele
|