dsp-tools 0.9.13__py3-none-any.whl → 18.3.0.post13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dsp_tools/__init__.py +5 -0
- dsp_tools/cli/args.py +47 -0
- dsp_tools/cli/call_action.py +85 -0
- dsp_tools/cli/call_action_files_only.py +101 -0
- dsp_tools/cli/call_action_with_network.py +207 -0
- dsp_tools/cli/create_parsers.py +479 -0
- dsp_tools/cli/entry_point.py +322 -0
- dsp_tools/cli/utils.py +87 -0
- dsp_tools/clients/CLAUDE.md +420 -0
- dsp_tools/clients/authentication_client.py +14 -0
- dsp_tools/clients/authentication_client_live.py +66 -0
- dsp_tools/clients/connection.py +35 -0
- dsp_tools/clients/connection_live.py +233 -0
- dsp_tools/clients/fuseki_metrics.py +60 -0
- dsp_tools/clients/group_user_clients.py +35 -0
- dsp_tools/clients/group_user_clients_live.py +181 -0
- dsp_tools/clients/legal_info_client.py +23 -0
- dsp_tools/clients/legal_info_client_live.py +132 -0
- dsp_tools/clients/list_client.py +49 -0
- dsp_tools/clients/list_client_live.py +166 -0
- dsp_tools/clients/metadata_client.py +24 -0
- dsp_tools/clients/metadata_client_live.py +47 -0
- dsp_tools/clients/ontology_clients.py +49 -0
- dsp_tools/clients/ontology_create_client_live.py +166 -0
- dsp_tools/clients/ontology_get_client_live.py +80 -0
- dsp_tools/clients/permissions_client.py +68 -0
- dsp_tools/clients/project_client.py +16 -0
- dsp_tools/clients/project_client_live.py +66 -0
- dsp_tools/commands/create/communicate_problems.py +24 -0
- dsp_tools/commands/create/create.py +134 -0
- dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
- dsp_tools/commands/create/create_on_server/classes.py +99 -0
- dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
- dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
- dsp_tools/commands/create/create_on_server/group_users.py +165 -0
- dsp_tools/commands/create/create_on_server/lists.py +163 -0
- dsp_tools/commands/create/create_on_server/mappers.py +12 -0
- dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
- dsp_tools/commands/create/create_on_server/ontology.py +52 -0
- dsp_tools/commands/create/create_on_server/project.py +68 -0
- dsp_tools/commands/create/create_on_server/properties.py +119 -0
- dsp_tools/commands/create/exceptions.py +29 -0
- dsp_tools/commands/create/lists_only.py +66 -0
- dsp_tools/commands/create/models/create_problems.py +87 -0
- dsp_tools/commands/create/models/parsed_ontology.py +88 -0
- dsp_tools/commands/create/models/parsed_project.py +81 -0
- dsp_tools/commands/create/models/rdf_ontology.py +12 -0
- dsp_tools/commands/create/models/server_project_info.py +100 -0
- dsp_tools/commands/create/parsing/parse_lists.py +45 -0
- dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
- dsp_tools/commands/create/parsing/parse_project.py +149 -0
- dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
- dsp_tools/commands/create/project_validate.py +595 -0
- dsp_tools/commands/create/serialisation/ontology.py +119 -0
- dsp_tools/commands/create/serialisation/project.py +44 -0
- dsp_tools/commands/excel2json/CLAUDE.md +101 -0
- dsp_tools/commands/excel2json/json_header.py +321 -0
- dsp_tools/commands/excel2json/lists/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/compliance_checks.py +292 -0
- dsp_tools/commands/excel2json/lists/make_lists.py +247 -0
- dsp_tools/commands/excel2json/lists/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/lists/models/deserialise.py +30 -0
- dsp_tools/commands/excel2json/lists/models/input_error.py +216 -0
- dsp_tools/commands/excel2json/lists/models/serialise.py +57 -0
- dsp_tools/commands/excel2json/lists/utils.py +81 -0
- dsp_tools/commands/excel2json/models/__init__.py +0 -0
- dsp_tools/commands/excel2json/models/input_error.py +416 -0
- dsp_tools/commands/excel2json/models/json_header.py +175 -0
- dsp_tools/commands/excel2json/models/list_node_name.py +16 -0
- dsp_tools/commands/excel2json/models/ontology.py +76 -0
- dsp_tools/commands/excel2json/old_lists.py +328 -0
- dsp_tools/commands/excel2json/project.py +280 -0
- dsp_tools/commands/excel2json/properties.py +370 -0
- dsp_tools/commands/excel2json/resources.py +336 -0
- dsp_tools/commands/excel2json/utils.py +352 -0
- dsp_tools/commands/excel2xml/__init__.py +7 -0
- dsp_tools/commands/excel2xml/excel2xml_cli.py +523 -0
- dsp_tools/commands/excel2xml/excel2xml_lib.py +1953 -0
- dsp_tools/commands/excel2xml/propertyelement.py +47 -0
- dsp_tools/commands/get/__init__.py +0 -0
- dsp_tools/commands/get/get.py +166 -0
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/get/legacy_models/__init__.py +0 -0
- dsp_tools/commands/get/legacy_models/context.py +318 -0
- dsp_tools/commands/get/legacy_models/group.py +241 -0
- dsp_tools/commands/get/legacy_models/helpers.py +47 -0
- dsp_tools/commands/get/legacy_models/listnode.py +390 -0
- dsp_tools/commands/get/legacy_models/model.py +12 -0
- dsp_tools/commands/get/legacy_models/ontology.py +324 -0
- dsp_tools/commands/get/legacy_models/project.py +366 -0
- dsp_tools/commands/get/legacy_models/propertyclass.py +417 -0
- dsp_tools/commands/get/legacy_models/resourceclass.py +676 -0
- dsp_tools/commands/get/legacy_models/user.py +438 -0
- dsp_tools/commands/get/models/__init__.py +0 -0
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +258 -0
- dsp_tools/commands/ingest_xmlupload/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +178 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +69 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +166 -0
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +121 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +64 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/__init__.py +0 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +20 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +57 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +66 -0
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +67 -0
- dsp_tools/commands/resume_xmlupload/__init__.py +0 -0
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +96 -0
- dsp_tools/commands/start_stack.py +428 -0
- dsp_tools/commands/update_legal/CLAUDE.md +344 -0
- dsp_tools/commands/update_legal/__init__.py +0 -0
- dsp_tools/commands/update_legal/core.py +182 -0
- dsp_tools/commands/update_legal/csv_operations.py +135 -0
- dsp_tools/commands/update_legal/models.py +87 -0
- dsp_tools/commands/update_legal/xml_operations.py +247 -0
- dsp_tools/commands/validate_data/CLAUDE.md +159 -0
- dsp_tools/commands/validate_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/constants.py +59 -0
- dsp_tools/commands/validate_data/mappers.py +143 -0
- dsp_tools/commands/validate_data/models/__init__.py +0 -0
- dsp_tools/commands/validate_data/models/api_responses.py +45 -0
- dsp_tools/commands/validate_data/models/input_problems.py +119 -0
- dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
- dsp_tools/commands/validate_data/models/validation.py +106 -0
- dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
- dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
- dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
- dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
- dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
- dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
- dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
- dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
- dsp_tools/commands/validate_data/sparql/cardinality_shacl.py +209 -0
- dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
- dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
- dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
- dsp_tools/commands/validate_data/utils.py +59 -0
- dsp_tools/commands/validate_data/validate_data.py +283 -0
- dsp_tools/commands/validate_data/validation/__init__.py +0 -0
- dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
- dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
- dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
- dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
- dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
- dsp_tools/commands/xmlupload/__init__.py +0 -0
- dsp_tools/commands/xmlupload/iri_resolver.py +21 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
- dsp_tools/commands/xmlupload/models/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +10 -0
- dsp_tools/commands/xmlupload/models/ingest.py +143 -0
- dsp_tools/commands/xmlupload/models/input_problems.py +58 -0
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +45 -0
- dsp_tools/commands/xmlupload/models/permissions_parsed.py +93 -0
- dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
- dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
- dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
- dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
- dsp_tools/commands/xmlupload/models/upload_clients.py +14 -0
- dsp_tools/commands/xmlupload/models/upload_state.py +20 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/ark2iri.py +55 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/iiif_uri_validator.py +50 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/list_client.py +120 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
- dsp_tools/commands/xmlupload/resource_create_client.py +25 -0
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/__init__.py +0 -0
- dsp_tools/commands/xmlupload/stash/analyse_circular_reference_graph.py +236 -0
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +87 -0
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +68 -0
- dsp_tools/commands/xmlupload/stash/stash_models.py +109 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +106 -0
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +196 -0
- dsp_tools/commands/xmlupload/upload_config.py +76 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +27 -0
- dsp_tools/commands/xmlupload/xmlupload.py +516 -0
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/config/warnings_config.py +32 -0
- dsp_tools/error/__init__.py +0 -0
- dsp_tools/error/custom_warnings.py +39 -0
- dsp_tools/error/exceptions.py +204 -0
- dsp_tools/error/problems.py +10 -0
- dsp_tools/error/xmllib_errors.py +20 -0
- dsp_tools/error/xmllib_warnings.py +54 -0
- dsp_tools/error/xmllib_warnings_util.py +159 -0
- dsp_tools/error/xsd_validation_error_msg.py +19 -0
- dsp_tools/legacy_models/__init__.py +0 -0
- dsp_tools/legacy_models/datetimestamp.py +81 -0
- dsp_tools/legacy_models/langstring.py +253 -0
- dsp_tools/legacy_models/projectContext.py +49 -0
- dsp_tools/py.typed +0 -0
- dsp_tools/resources/schema/data.xsd +648 -0
- dsp_tools/resources/schema/lists-only.json +72 -0
- dsp_tools/resources/schema/project.json +1258 -0
- dsp_tools/resources/schema/properties-only.json +874 -0
- dsp_tools/resources/schema/resources-only.json +140 -0
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.override.yml +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +88 -0
- dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
- dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
- dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
- dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
- dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
- dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
- dsp_tools/utils/__init__.py +0 -0
- dsp_tools/utils/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/data_formats/date_util.py +166 -0
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/data_formats/shared.py +81 -0
- dsp_tools/utils/data_formats/uri_util.py +76 -0
- dsp_tools/utils/fuseki_bloating.py +63 -0
- dsp_tools/utils/json_parsing.py +22 -0
- dsp_tools/utils/rdf_constants.py +42 -0
- dsp_tools/utils/rdflib_utils.py +10 -0
- dsp_tools/utils/replace_id_with_iri.py +66 -0
- dsp_tools/utils/request_utils.py +238 -0
- dsp_tools/utils/xml_parsing/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
- dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
- dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
- dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
- dsp_tools/xmllib/CLAUDE.md +302 -0
- dsp_tools/xmllib/__init__.py +49 -0
- dsp_tools/xmllib/general_functions.py +877 -0
- dsp_tools/xmllib/internal/__init__.py +0 -0
- dsp_tools/xmllib/internal/checkers.py +162 -0
- dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
- dsp_tools/xmllib/internal/constants.py +46 -0
- dsp_tools/xmllib/internal/input_converters.py +155 -0
- dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
- dsp_tools/xmllib/internal/serialise_resource.py +177 -0
- dsp_tools/xmllib/internal/serialise_values.py +152 -0
- dsp_tools/xmllib/internal/type_aliases.py +11 -0
- dsp_tools/xmllib/models/__init__.py +0 -0
- dsp_tools/xmllib/models/config_options.py +28 -0
- dsp_tools/xmllib/models/date_formats.py +48 -0
- dsp_tools/xmllib/models/dsp_base_resources.py +1542 -0
- dsp_tools/xmllib/models/internal/__init__.py +0 -0
- dsp_tools/xmllib/models/internal/file_values.py +172 -0
- dsp_tools/xmllib/models/internal/geometry.py +162 -0
- dsp_tools/xmllib/models/internal/migration_metadata.py +55 -0
- dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
- dsp_tools/xmllib/models/internal/values.py +342 -0
- dsp_tools/xmllib/models/licenses/__init__.py +0 -0
- dsp_tools/xmllib/models/licenses/other.py +59 -0
- dsp_tools/xmllib/models/licenses/recommended.py +107 -0
- dsp_tools/xmllib/models/permissions.py +41 -0
- dsp_tools/xmllib/models/res.py +1782 -0
- dsp_tools/xmllib/models/root.py +348 -0
- dsp_tools/xmllib/value_checkers.py +434 -0
- dsp_tools/xmllib/value_converters.py +777 -0
- dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
- dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
- dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
- dsp_tools-18.3.0.post13.dist-info/entry_points.txt +3 -0
- dsp_tools-0.9.13.dist-info/LICENSE +0 -674
- dsp_tools-0.9.13.dist-info/METADATA +0 -144
- dsp_tools-0.9.13.dist-info/RECORD +0 -71
- dsp_tools-0.9.13.dist-info/WHEEL +0 -5
- dsp_tools-0.9.13.dist-info/entry_points.txt +0 -3
- dsp_tools-0.9.13.dist-info/top_level.txt +0 -1
- dsplib/models/connection.py +0 -272
- dsplib/models/group.py +0 -296
- dsplib/models/helpers.py +0 -505
- dsplib/models/langstring.py +0 -277
- dsplib/models/listnode.py +0 -578
- dsplib/models/model.py +0 -20
- dsplib/models/ontology.py +0 -448
- dsplib/models/permission.py +0 -112
- dsplib/models/project.py +0 -547
- dsplib/models/propertyclass.py +0 -505
- dsplib/models/resource.py +0 -366
- dsplib/models/resourceclass.py +0 -810
- dsplib/models/sipi.py +0 -30
- dsplib/models/user.py +0 -731
- dsplib/models/value.py +0 -1000
- dsplib/utils/knora-data-schema.xsd +0 -454
- dsplib/utils/knora-schema-lists.json +0 -83
- dsplib/utils/knora-schema.json +0 -434
- dsplib/utils/onto_commons.py +0 -24
- dsplib/utils/onto_create_lists.py +0 -73
- dsplib/utils/onto_create_ontology.py +0 -442
- dsplib/utils/onto_get.py +0 -58
- dsplib/utils/onto_validate.py +0 -33
- dsplib/utils/xml_upload.py +0 -539
- dsplib/widgets/doublepassword.py +0 -80
- knora/MLS-import-libraries.py +0 -84
- knora/dsp_tools.py +0 -96
- knora/dsplib/models/connection.py +0 -272
- knora/dsplib/models/group.py +0 -296
- knora/dsplib/models/helpers.py +0 -506
- knora/dsplib/models/langstring.py +0 -277
- knora/dsplib/models/listnode.py +0 -578
- knora/dsplib/models/model.py +0 -20
- knora/dsplib/models/ontology.py +0 -448
- knora/dsplib/models/permission.py +0 -112
- knora/dsplib/models/project.py +0 -583
- knora/dsplib/models/propertyclass.py +0 -505
- knora/dsplib/models/resource.py +0 -416
- knora/dsplib/models/resourceclass.py +0 -811
- knora/dsplib/models/sipi.py +0 -35
- knora/dsplib/models/user.py +0 -731
- knora/dsplib/models/value.py +0 -1000
- knora/dsplib/utils/knora-data-schema.xsd +0 -464
- knora/dsplib/utils/knora-schema-lists.json +0 -83
- knora/dsplib/utils/knora-schema.json +0 -444
- knora/dsplib/utils/onto_commons.py +0 -24
- knora/dsplib/utils/onto_create_lists.py +0 -73
- knora/dsplib/utils/onto_create_ontology.py +0 -451
- knora/dsplib/utils/onto_get.py +0 -58
- knora/dsplib/utils/onto_validate.py +0 -33
- knora/dsplib/utils/xml_upload.py +0 -540
- knora/dsplib/widgets/doublepassword.py +0 -80
- knora/knora.py +0 -2108
- knora/test.py +0 -99
- knora/testit.py +0 -76
- knora/xml2knora.py +0 -633
- {dsplib → dsp_tools/cli}/__init__.py +0 -0
- {dsplib/models → dsp_tools/clients}/__init__.py +0 -0
- {dsplib/utils → dsp_tools/commands}/__init__.py +0 -0
- {dsplib/widgets → dsp_tools/commands/create}/__init__.py +0 -0
- {knora → dsp_tools/commands/create/create_on_server}/__init__.py +0 -0
- {knora/dsplib → dsp_tools/commands/create/models}/__init__.py +0 -0
- {knora/dsplib/models → dsp_tools/commands/create/parsing}/__init__.py +0 -0
- {knora/dsplib/utils → dsp_tools/commands/create/serialisation}/__init__.py +0 -0
- {knora/dsplib/widgets → dsp_tools/commands/excel2json}/__init__.py +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from dsp_tools.config.logger_config import LOGGER_SAVEPATH
|
|
5
|
+
from dsp_tools.utils.ansi_colors import BOLD_RED
|
|
6
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class BaseError(Exception):
|
|
11
|
+
"""
|
|
12
|
+
A basic error class for DSP-TOOLS.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
message: A message that describes the error
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
message: str = ""
|
|
19
|
+
|
|
20
|
+
def __str__(self) -> str:
|
|
21
|
+
return self.message
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class InternalError(BaseError):
|
|
25
|
+
"""
|
|
26
|
+
Class for errors that are raised if the user cannot solve the problem themselves.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, custom_msg: str | None = None, keep_default_msg: bool = True) -> None:
|
|
30
|
+
default_msg = (
|
|
31
|
+
f"\n\n{BOLD_RED}An internal error occurred.{RESET_TO_DEFAULT}\n"
|
|
32
|
+
"Please contact the dsp-tools development team (at support@dasch.swiss) with the following information:\n"
|
|
33
|
+
" - Which command was used.\n"
|
|
34
|
+
" - If applicable, any files that were used in conjunction with the command.\n"
|
|
35
|
+
" - A text file with the terminal output copied into.\n"
|
|
36
|
+
f" - The log file at {LOGGER_SAVEPATH}.\n"
|
|
37
|
+
)
|
|
38
|
+
match keep_default_msg, custom_msg:
|
|
39
|
+
case False, str():
|
|
40
|
+
super().__init__(custom_msg)
|
|
41
|
+
case True, str():
|
|
42
|
+
default_msg = f"\n\n{custom_msg}\n--------------------------{default_msg}"
|
|
43
|
+
super().__init__(default_msg)
|
|
44
|
+
case _:
|
|
45
|
+
super().__init__(default_msg)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class DockerNotReachableError(BaseError):
|
|
49
|
+
"""This error is raised when docker is not running."""
|
|
50
|
+
|
|
51
|
+
def __init__(self) -> None:
|
|
52
|
+
msg = "Docker is not running properly. Please start Docker and try again."
|
|
53
|
+
super().__init__(msg)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class DspApiNotReachableError(BaseError):
|
|
57
|
+
"""This error is raised when the DSP-API could not be reached on localhost."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class DspToolsRequestException(BaseError):
|
|
61
|
+
"""Class for errors that are raised if any request exceptions happens."""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class InputError(BaseError):
|
|
65
|
+
"""This error is raised when the user input is invalid. The message should be as user-friendly as possible."""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class UserError(BaseError):
|
|
69
|
+
"""
|
|
70
|
+
This is a base class for all the errors that are raised when the user input is invalid.
|
|
71
|
+
The message should be as user-friendly as possible.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class InvalidGuiAttributeError(BaseError):
|
|
76
|
+
"""This error is raised when a invalid gui-attribute is used."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FatalNonOkApiResponseCode(BaseError):
|
|
80
|
+
"""This error is raised when the API gives an unexpected response, that we cannot anticipate and handle cleanly."""
|
|
81
|
+
|
|
82
|
+
def __init__(self, request_url: str, status_code: int, response_text: str) -> None:
|
|
83
|
+
resp_txt = response_text[:200] if len(response_text) > 200 else response_text
|
|
84
|
+
msg = (
|
|
85
|
+
f"We currently do not support the following API response code for this request.\n"
|
|
86
|
+
f"Status code: {status_code}\n"
|
|
87
|
+
f"Request URL: {request_url}\n"
|
|
88
|
+
f"Original Response: {resp_txt}\n"
|
|
89
|
+
f"Please contact support@dasch.swiss with the log file at {LOGGER_SAVEPATH}."
|
|
90
|
+
)
|
|
91
|
+
super().__init__(msg)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class UserFilepathNotFoundError(InputError):
|
|
95
|
+
"""This error is raised if a filepath from the user does not exist."""
|
|
96
|
+
|
|
97
|
+
def __init__(self, filepath: str | Path) -> None:
|
|
98
|
+
msg = f"The provided filepath does not exist: {filepath}"
|
|
99
|
+
super().__init__(msg)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class UserDirectoryNotFoundError(InputError):
|
|
103
|
+
"""This error is raised if a directory from the user does not exist."""
|
|
104
|
+
|
|
105
|
+
def __init__(self, directory: str | Path) -> None:
|
|
106
|
+
msg = f"The provided directory does not exist: {directory}"
|
|
107
|
+
super().__init__(msg)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class JSONFileParsingError(InputError):
|
|
111
|
+
"""This error should be raised if the user provided input file cannot be parsed."""
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class PermanentConnectionError(BaseError):
|
|
115
|
+
"""This error is raised when all attempts to reconnect to DSP have failed."""
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class InvalidInputError(BaseError):
|
|
119
|
+
"""This error is raised if the API responds with a permanent error because of invalid input data"""
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class ShaclValidationCliError(BaseError):
|
|
123
|
+
"""This error is raised when the validate data docker command has problems"""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class ShaclValidationError(BaseError):
|
|
127
|
+
"""This error is raised when an unexpected error occurs during the validation"""
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class InvalidIngestFileNameError(InvalidInputError):
|
|
131
|
+
"""This error is raised if INGEST rejects a file due to its name."""
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class PermanentTimeOutError(BaseError):
|
|
135
|
+
"""This error is raised when python throws a timeout due to no response from the DSP-API."""
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class BadCredentialsError(PermanentConnectionError):
|
|
139
|
+
"""This error is raised when DSP-API doesn't accept the prodived credentials."""
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class XmlUploadError(BaseError):
|
|
143
|
+
"""Represents an error raised in the context of the xmlupload."""
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class XmlInputConversionError(BaseError):
|
|
147
|
+
"""Represents an error raised in the context of the xmlupload."""
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class Id2IriReplacementError(BaseError):
|
|
151
|
+
"""Represents an error raised if an internal ID could not be found in the Id2Iri mapping."""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class DuplicateIdsInXmlAndId2IriMapping(InputError):
|
|
155
|
+
"""
|
|
156
|
+
Represents an error raised if a resource ID that is in the Id2Iri mapping
|
|
157
|
+
is also used as a resource id in the new data.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class XmlUploadInterruptedError(XmlUploadError):
|
|
162
|
+
"""Represents an error raised when the xmlupload was interrupted."""
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class XmlUploadPermissionsNotFoundError(BaseError):
|
|
166
|
+
"""Class for errors that are raised when a permission does not exist."""
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class XmlUploadAuthorshipsNotFoundError(BaseError):
|
|
170
|
+
"""Class for errors that are raised when an authorship id does not exist."""
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class XmlUploadListNodeNotFoundError(BaseError):
|
|
174
|
+
"""Class for errors that are raised when a list node does not exist."""
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class UnknownDOAPException(BaseError):
|
|
178
|
+
"""Class for errors that are raised if a DOAP cannot be parsed"""
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ProjectOntologyNotFound(BaseError):
|
|
182
|
+
"""Class for errors that are raised if a project is expected to have 1 or more ontologies, but none were found."""
|
|
183
|
+
|
|
184
|
+
def __init__(self, shortcode: str) -> None:
|
|
185
|
+
msg = f"The project with the shortcode '{shortcode}' does not have any ontologies."
|
|
186
|
+
super().__init__(msg)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class ProjectNotFoundError(InputError):
|
|
190
|
+
"""Class if a project is expected to exist but could not be found."""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class InvalidLicenseError(InputError):
|
|
194
|
+
"""This error is raised when a license string cannot be parsed."""
|
|
195
|
+
|
|
196
|
+
license_str: str
|
|
197
|
+
|
|
198
|
+
def __init__(self, license_str: str) -> None:
|
|
199
|
+
msg = (
|
|
200
|
+
f"The provided license string is invalid and cannot be parsed: '{license_str}'"
|
|
201
|
+
"You must provide a license that can be parsed by xmllib.find_license_in_string(). "
|
|
202
|
+
"See https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/general-functions/#xmllib.general_functions.find_license_in_string"
|
|
203
|
+
)
|
|
204
|
+
super().__init__(msg)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from dsp_tools.error.exceptions import BaseError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class XmllibInputError(BaseError):
|
|
5
|
+
"""
|
|
6
|
+
This error is raised if a user provided invalid input.
|
|
7
|
+
It should never be raised plain, but with the dedicated util function.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class XmllibFileNotFoundError(BaseError):
|
|
12
|
+
"""
|
|
13
|
+
This error is raised if a user provided a filepath that does not exist.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class XmllibInternalError(BaseError):
|
|
18
|
+
"""
|
|
19
|
+
This error is raised if an internal error, i.e. an error on which the user has no influence, is found in the xmllib.
|
|
20
|
+
"""
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
|
|
6
|
+
from dsp_tools.utils.ansi_colors import BOLD_RED
|
|
7
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
8
|
+
from dsp_tools.utils.ansi_colors import YELLOW
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UserMessageSeverity(StrEnum):
|
|
12
|
+
INFO = "INFO"
|
|
13
|
+
WARNING = "WARNING"
|
|
14
|
+
ERROR = "ERROR"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class MessageInfo:
|
|
19
|
+
"""
|
|
20
|
+
message: message about what went wrong
|
|
21
|
+
resource_id: ID of the affected resource
|
|
22
|
+
prop_name: property name of the affected property (if applicable)
|
|
23
|
+
field: information about which field of the resource is affected (if not the property), e.g. "resource id", "label"
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
message: str
|
|
27
|
+
resource_id: str | None = None
|
|
28
|
+
prop_name: str | None = None
|
|
29
|
+
field: str | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class XmllibUserInfoBase(Warning, ABC):
|
|
33
|
+
"""Base class for warnings that implement a custom showwarnings() function"""
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def showwarning(cls, message: str) -> None:
|
|
38
|
+
"""Functionality that should be executed when a warning of this class is emitted"""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class XmllibInputInfo(XmllibUserInfoBase):
|
|
42
|
+
"""If the xmllib input may be problematic"""
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def showwarning(cls, message: str) -> None:
|
|
46
|
+
print(YELLOW + f"INFO | {message}" + RESET_TO_DEFAULT)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class XmllibInputWarning(XmllibUserInfoBase):
|
|
50
|
+
"""If the xmllib input is problematic"""
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def showwarning(cls, message: str) -> None:
|
|
54
|
+
print(BOLD_RED + f"WARNING | {message}" + RESET_TO_DEFAULT)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
import warnings
|
|
5
|
+
from typing import Any
|
|
6
|
+
from typing import Never
|
|
7
|
+
|
|
8
|
+
import regex
|
|
9
|
+
from dotenv import find_dotenv
|
|
10
|
+
from dotenv import load_dotenv
|
|
11
|
+
|
|
12
|
+
from dsp_tools.error.xmllib_errors import XmllibFileNotFoundError
|
|
13
|
+
from dsp_tools.error.xmllib_errors import XmllibInputError
|
|
14
|
+
from dsp_tools.error.xmllib_warnings import MessageInfo
|
|
15
|
+
from dsp_tools.error.xmllib_warnings import UserMessageSeverity
|
|
16
|
+
from dsp_tools.error.xmllib_warnings import XmllibInputInfo
|
|
17
|
+
from dsp_tools.error.xmllib_warnings import XmllibInputWarning
|
|
18
|
+
from dsp_tools.utils.ansi_colors import BOLD_YELLOW
|
|
19
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
20
|
+
|
|
21
|
+
load_dotenv(dotenv_path=find_dotenv(usecwd=True))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def initialise_warning_file() -> None:
|
|
25
|
+
if file_path := os.getenv("XMLLIB_WARNINGS_CSV_SAVEPATH"):
|
|
26
|
+
try:
|
|
27
|
+
new_row = ["File", "Severity", "Message", "Resource ID", "Property", "Field"]
|
|
28
|
+
with open(file_path, "w", newline="") as file:
|
|
29
|
+
print(
|
|
30
|
+
BOLD_YELLOW,
|
|
31
|
+
f"Warnings generated by the xmllib "
|
|
32
|
+
f"will be saved to '{file_path}' and will not be printed in the terminal.",
|
|
33
|
+
RESET_TO_DEFAULT,
|
|
34
|
+
)
|
|
35
|
+
writer = csv.writer(file)
|
|
36
|
+
writer.writerow(new_row)
|
|
37
|
+
except FileNotFoundError:
|
|
38
|
+
raise XmllibFileNotFoundError(
|
|
39
|
+
f"The filepath '{file_path}' you entered in your .env file does not exist. "
|
|
40
|
+
f"Please ensure that the folder you named exists."
|
|
41
|
+
) from None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def write_message_to_csv(
|
|
45
|
+
file_path: str, msg: MessageInfo, function_trace: str | None, severity: UserMessageSeverity
|
|
46
|
+
) -> None:
|
|
47
|
+
new_row = [
|
|
48
|
+
function_trace if function_trace else "",
|
|
49
|
+
str(severity),
|
|
50
|
+
msg.message if msg.message else "",
|
|
51
|
+
msg.resource_id if msg.resource_id else "",
|
|
52
|
+
msg.prop_name if msg.prop_name else "",
|
|
53
|
+
msg.field if msg.field else "",
|
|
54
|
+
]
|
|
55
|
+
with open(file_path, "a", newline="") as file:
|
|
56
|
+
writer = csv.writer(file)
|
|
57
|
+
writer.writerow(new_row)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_user_message_string(msg: MessageInfo, function_trace: str | None) -> str:
|
|
61
|
+
str_list = [f"File '{function_trace}'"] if function_trace else []
|
|
62
|
+
if msg.resource_id:
|
|
63
|
+
str_list.append(f"Resource ID '{msg.resource_id}'")
|
|
64
|
+
if msg.prop_name:
|
|
65
|
+
str_list.append(f"Property '{msg.prop_name}'")
|
|
66
|
+
if msg.field:
|
|
67
|
+
str_list.append(f"Field '{msg.field}'")
|
|
68
|
+
str_list.append(msg.message)
|
|
69
|
+
return " | ".join(str_list)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _get_calling_code_context() -> str | None:
|
|
73
|
+
"""
|
|
74
|
+
Find file name and line number of the file that was written by the user.
|
|
75
|
+
"""
|
|
76
|
+
all_stack_frames = inspect.stack()
|
|
77
|
+
frame_files = [x.filename for x in all_stack_frames]
|
|
78
|
+
calling_func_index = _get_stack_frame_number(frame_files)
|
|
79
|
+
if calling_func_index == 0:
|
|
80
|
+
return None
|
|
81
|
+
user_frame_info = all_stack_frames.pop(calling_func_index)
|
|
82
|
+
file_name = user_frame_info.filename.rsplit("/", 1)[1]
|
|
83
|
+
return f"{file_name}:{user_frame_info.lineno}"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _get_stack_frame_number(file_names: list[str]) -> int:
|
|
87
|
+
"""
|
|
88
|
+
Get index number of first python file of the stack trace which is not any more in the dsp-tools code.
|
|
89
|
+
This is the index of the first user python file.
|
|
90
|
+
"""
|
|
91
|
+
calling_func_index = -1
|
|
92
|
+
for file in file_names:
|
|
93
|
+
if _filter_stack_frames(file):
|
|
94
|
+
calling_func_index += 1
|
|
95
|
+
else:
|
|
96
|
+
calling_func_index += 1
|
|
97
|
+
break
|
|
98
|
+
return calling_func_index
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _filter_stack_frames(file_path: str) -> bool:
|
|
102
|
+
dsp_tools_path = r"\/dsp[-_]tools\/(xmllib|error)\/"
|
|
103
|
+
if regex.search(dsp_tools_path, file_path):
|
|
104
|
+
return True
|
|
105
|
+
elif regex.search(r"^<[a-zA-Z]+>$", file_path):
|
|
106
|
+
# This is for functions like str(), which appear in the stack trace as filename "<string>"
|
|
107
|
+
return True
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def raise_xmllib_input_error(msg: MessageInfo) -> Never:
|
|
112
|
+
"""These are to be used if the error is caused by user input."""
|
|
113
|
+
function_trace = _get_calling_code_context()
|
|
114
|
+
if file_path := os.getenv("XMLLIB_WARNINGS_CSV_SAVEPATH"):
|
|
115
|
+
write_message_to_csv(file_path, msg, function_trace, UserMessageSeverity.ERROR)
|
|
116
|
+
msg_str = get_user_message_string(msg, function_trace)
|
|
117
|
+
raise XmllibInputError(msg_str)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def emit_xmllib_input_warning(msg: MessageInfo) -> None:
|
|
121
|
+
"""These are to be used if the error is caused by user input."""
|
|
122
|
+
if str(os.getenv("XMLLIB_IGNORE_USER_WARNING")).lower() == "true":
|
|
123
|
+
return
|
|
124
|
+
function_trace = _get_calling_code_context()
|
|
125
|
+
if file_path := os.getenv("XMLLIB_WARNINGS_CSV_SAVEPATH"):
|
|
126
|
+
write_message_to_csv(file_path, msg, function_trace, UserMessageSeverity.WARNING)
|
|
127
|
+
else:
|
|
128
|
+
msg_str = get_user_message_string(msg, function_trace)
|
|
129
|
+
warnings.warn(XmllibInputWarning(msg_str))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def emit_xmllib_input_info(msg: MessageInfo) -> None:
|
|
133
|
+
"""These are to be used if the error is caused by user input."""
|
|
134
|
+
if str(os.getenv("XMLLIB_IGNORE_USER_INFO")).lower() == "true":
|
|
135
|
+
return
|
|
136
|
+
function_trace = _get_calling_code_context()
|
|
137
|
+
if file_path := os.getenv("XMLLIB_WARNINGS_CSV_SAVEPATH"):
|
|
138
|
+
write_message_to_csv(file_path, msg, function_trace, UserMessageSeverity.INFO)
|
|
139
|
+
else:
|
|
140
|
+
msg_str = get_user_message_string(msg, function_trace)
|
|
141
|
+
warnings.warn(XmllibInputInfo(msg_str))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def emit_xmllib_input_type_mismatch_warning(
|
|
145
|
+
*,
|
|
146
|
+
expected_type: str,
|
|
147
|
+
value: Any,
|
|
148
|
+
res_id: str | None,
|
|
149
|
+
value_field: str | None = None,
|
|
150
|
+
prop_name: str | None = None,
|
|
151
|
+
) -> None:
|
|
152
|
+
"""These are to be used if the error is caused by user input."""
|
|
153
|
+
msg_info = MessageInfo(
|
|
154
|
+
message=f"The input should be a valid {expected_type}, your input '{value}' does not match the type.",
|
|
155
|
+
resource_id=res_id,
|
|
156
|
+
prop_name=prop_name,
|
|
157
|
+
field=value_field,
|
|
158
|
+
)
|
|
159
|
+
emit_xmllib_input_warning(msg_info)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclass
|
|
5
|
+
class XSDValidationMessage:
|
|
6
|
+
line_number: int
|
|
7
|
+
element: str | None
|
|
8
|
+
attribute: str | None
|
|
9
|
+
message: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_xsd_validation_message_str(msg: XSDValidationMessage) -> str:
|
|
13
|
+
msg_list = [f"Line Number {msg.line_number}"]
|
|
14
|
+
if msg.element:
|
|
15
|
+
msg_list.append(f"Element '{msg.element}'")
|
|
16
|
+
if msg.attribute:
|
|
17
|
+
msg_list.append(f"Attribute '{msg.attribute}'")
|
|
18
|
+
msg_list.append(msg.message)
|
|
19
|
+
return " | ".join(msg_list)
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from typing import Union
|
|
5
|
+
|
|
6
|
+
import regex
|
|
7
|
+
|
|
8
|
+
from dsp_tools.error.exceptions import BaseError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DateTimeStamp:
|
|
12
|
+
"""
|
|
13
|
+
Class to hold and process an xsd:dateTimeStamp
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
_dateTimeStamp: str
|
|
17
|
+
_validation_regex = (
|
|
18
|
+
r"^-?([1-9][0-9]{3,}|0[0-9]{3})"
|
|
19
|
+
r"-(0[1-9]|1[0-2])"
|
|
20
|
+
r"-(0[1-9]|[12][0-9]|3[01])"
|
|
21
|
+
r"T(([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]+)?|(24:00:00(\.0+)?))"
|
|
22
|
+
r"(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))$"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def __init__(self, val: Any):
|
|
26
|
+
"""
|
|
27
|
+
The constructor works for different inputs: a string, an instance of "DateTimeStamp",
|
|
28
|
+
or a JSON-LD construct of the form { "@type": "xsd:dateTimeStamp", "@value": "date-str" }
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
val: xsd:dateTimeStamp as string, instance of "DateTimeStamp" or json-ld construct
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
BaseError: if the JSON-LD construct is not correct
|
|
35
|
+
"""
|
|
36
|
+
if isinstance(val, str):
|
|
37
|
+
if not regex.search(self._validation_regex, val):
|
|
38
|
+
raise BaseError(f"Invalid xsd:dateTimeStamp: '{val}'")
|
|
39
|
+
self._dateTimeStamp = val
|
|
40
|
+
elif isinstance(val, DateTimeStamp):
|
|
41
|
+
self._dateTimeStamp = str(val)
|
|
42
|
+
elif val.get("@type") == "xsd:dateTimeStamp" and regex.search(self._validation_regex, str(val.get("@value"))):
|
|
43
|
+
self._dateTimeStamp = val["@value"]
|
|
44
|
+
else:
|
|
45
|
+
raise BaseError(f"Invalid xsd:dateTimeStamp: '{val}'")
|
|
46
|
+
|
|
47
|
+
def __eq__(self, other: Union[str, DateTimeStamp]) -> bool:
|
|
48
|
+
if isinstance(other, str):
|
|
49
|
+
other = DateTimeStamp(other)
|
|
50
|
+
return self._dateTimeStamp == other._dateTimeStamp
|
|
51
|
+
|
|
52
|
+
def __lt__(self, other: DateTimeStamp) -> bool:
|
|
53
|
+
if isinstance(other, str):
|
|
54
|
+
other = DateTimeStamp(other)
|
|
55
|
+
return self._dateTimeStamp < other._dateTimeStamp
|
|
56
|
+
|
|
57
|
+
def __le__(self, other: DateTimeStamp) -> bool:
|
|
58
|
+
if isinstance(other, str):
|
|
59
|
+
other = DateTimeStamp(other)
|
|
60
|
+
return self._dateTimeStamp <= other._dateTimeStamp
|
|
61
|
+
|
|
62
|
+
def __gt__(self, other: DateTimeStamp) -> bool:
|
|
63
|
+
if isinstance(other, str):
|
|
64
|
+
other = DateTimeStamp(other)
|
|
65
|
+
return self._dateTimeStamp > other._dateTimeStamp
|
|
66
|
+
|
|
67
|
+
def __ge__(self, other: DateTimeStamp) -> bool:
|
|
68
|
+
if isinstance(other, str):
|
|
69
|
+
other = DateTimeStamp(other)
|
|
70
|
+
return self._dateTimeStamp >= other._dateTimeStamp
|
|
71
|
+
|
|
72
|
+
def __ne__(self, other: DateTimeStamp) -> bool:
|
|
73
|
+
if isinstance(other, str):
|
|
74
|
+
other = DateTimeStamp(other)
|
|
75
|
+
return self._dateTimeStamp != other._dateTimeStamp
|
|
76
|
+
|
|
77
|
+
def __str__(self: DateTimeStamp) -> str:
|
|
78
|
+
return self._dateTimeStamp
|
|
79
|
+
|
|
80
|
+
def toJsonObj(self) -> dict[str, str]:
|
|
81
|
+
return {"@type": "xsd:dateTimeStamp", "@value": self._dateTimeStamp}
|