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,121 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import field
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
separator = "\n "
|
|
8
|
+
list_separator = "\n - "
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class IngestInformation:
|
|
13
|
+
"""
|
|
14
|
+
This class stores the information about the mapping of ids provided by the dsp-ingest service
|
|
15
|
+
and the filepaths used in the XML file.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
unused_mediafiles: list[str]
|
|
19
|
+
mediafiles_no_id: list[tuple[str, str]]
|
|
20
|
+
maximum_prints: int = 20
|
|
21
|
+
csv_directory_path: Path = field(default=Path.cwd())
|
|
22
|
+
unused_mediafiles_csv: str = "UnusedMediaUploaded.csv"
|
|
23
|
+
mediafiles_no_id_csv: str = "FilesNotUploaded.csv"
|
|
24
|
+
|
|
25
|
+
def ok_msg(self) -> str | None:
|
|
26
|
+
"""
|
|
27
|
+
This function checks if no media was unused or not uploaded.
|
|
28
|
+
If that is the case it returns the message,
|
|
29
|
+
if not, it ends without an effect.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Message if all went well.
|
|
33
|
+
"""
|
|
34
|
+
if not self.unused_mediafiles and not self.mediafiles_no_id:
|
|
35
|
+
return (
|
|
36
|
+
"All multimedia files referenced in the XML file were uploaded through dsp-ingest.\n"
|
|
37
|
+
"All multimedia files uploaded through dsp-ingest were referenced in the XML file."
|
|
38
|
+
)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
def execute_error_protocol(self) -> str:
|
|
42
|
+
"""
|
|
43
|
+
This function generates the user message and saves a file with the information
|
|
44
|
+
if a lot of resources are affected.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
User message
|
|
48
|
+
"""
|
|
49
|
+
self._save_csv_if_applicable()
|
|
50
|
+
return self._get_error_msg()
|
|
51
|
+
|
|
52
|
+
def _get_error_msg(self) -> str:
|
|
53
|
+
msg_list = [
|
|
54
|
+
"The upload cannot continue as there are problems with the multimedia files referenced in the XML.",
|
|
55
|
+
]
|
|
56
|
+
if has_msg := self._get_unused_mediafiles_msg():
|
|
57
|
+
msg_list.append(has_msg)
|
|
58
|
+
if has_msg := self._get_mediafiles_no_id_msg():
|
|
59
|
+
msg_list.append(has_msg)
|
|
60
|
+
return separator.join(msg_list)
|
|
61
|
+
|
|
62
|
+
def _get_mediafiles_no_id_msg(self) -> str | None:
|
|
63
|
+
if 0 < len(self.mediafiles_no_id) <= self.maximum_prints:
|
|
64
|
+
return (
|
|
65
|
+
"The data XML file contains references to the following multimedia files "
|
|
66
|
+
"which were not previously uploaded through dsp-ingest:"
|
|
67
|
+
+ list_separator
|
|
68
|
+
+ list_separator.join([f"Resource ID: '{x[0]}' | Filepath: '{x[1]}'" for x in self.mediafiles_no_id])
|
|
69
|
+
)
|
|
70
|
+
elif len(self.mediafiles_no_id) > self.maximum_prints:
|
|
71
|
+
return (
|
|
72
|
+
"The data XML file contains references to multimedia files "
|
|
73
|
+
"which were not previously uploaded through dsp-ingest:\n"
|
|
74
|
+
f" The file with the resource IDs and problematic filenames was saved at "
|
|
75
|
+
f"'{Path(self.csv_directory_path / self.mediafiles_no_id_csv)}'."
|
|
76
|
+
)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
def _get_unused_mediafiles_msg(self) -> str | None:
|
|
80
|
+
if 0 < len(self.unused_mediafiles) <= self.maximum_prints:
|
|
81
|
+
return (
|
|
82
|
+
"The data XML file does not reference the following multimedia files which were previously "
|
|
83
|
+
"uploaded through dsp-ingest:" + list_separator + list_separator.join(self.unused_mediafiles)
|
|
84
|
+
)
|
|
85
|
+
elif len(self.unused_mediafiles) > self.maximum_prints:
|
|
86
|
+
return (
|
|
87
|
+
"The data XML file does not reference all the multimedia files which were previously "
|
|
88
|
+
"uploaded through dsp-ingest.\n"
|
|
89
|
+
f" The file with the unused filenames was saved at "
|
|
90
|
+
f"'{Path(self.csv_directory_path / self.unused_mediafiles_csv)}'."
|
|
91
|
+
)
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
def _save_csv_if_applicable(self) -> None:
|
|
95
|
+
if (unused_mediafiles_df := self._unused_mediafiles_to_df()) is not None:
|
|
96
|
+
_save_as_csv(unused_mediafiles_df, self.csv_directory_path, self.unused_mediafiles_csv)
|
|
97
|
+
if (no_id_df := self._mediafiles_no_id_to_df()) is not None:
|
|
98
|
+
_save_as_csv(no_id_df, self.csv_directory_path, self.mediafiles_no_id_csv)
|
|
99
|
+
|
|
100
|
+
def _unused_mediafiles_to_df(self) -> pd.DataFrame | None:
|
|
101
|
+
return (
|
|
102
|
+
pd.DataFrame({"Multimedia Filenames": self.unused_mediafiles})
|
|
103
|
+
if len(self.unused_mediafiles) > self.maximum_prints
|
|
104
|
+
else None
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def _mediafiles_no_id_to_df(self) -> pd.DataFrame | None:
|
|
108
|
+
return (
|
|
109
|
+
pd.DataFrame(
|
|
110
|
+
{
|
|
111
|
+
"Resource ID": [x[0] for x in self.mediafiles_no_id],
|
|
112
|
+
"Filepath": [x[1] for x in self.mediafiles_no_id],
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
if len(self.mediafiles_no_id) > self.maximum_prints
|
|
116
|
+
else None
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _save_as_csv(df: pd.DataFrame, directory_path: Path, filename: str) -> None:
|
|
121
|
+
df.to_csv(Path(directory_path, filename), index=False)
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from time import sleep
|
|
3
|
+
from typing import cast
|
|
4
|
+
|
|
5
|
+
from loguru import logger
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
|
|
8
|
+
from dsp_tools.cli.args import ServerCredentials
|
|
9
|
+
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
10
|
+
from dsp_tools.commands.ingest_xmlupload.bulk_ingest_client import BulkIngestClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def ingest_files(creds: ServerCredentials, shortcode: str) -> bool:
|
|
14
|
+
"""
|
|
15
|
+
Kick off the ingest process on the server, and wait until it has finished.
|
|
16
|
+
Then, retrieve the mapping CSV from the server and save it in the CWD.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
creds: credentials to log in on the server
|
|
20
|
+
shortcode: shortcode of the project
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
success status
|
|
24
|
+
"""
|
|
25
|
+
auth = AuthenticationClientLive(creds.server, creds.user, creds.password)
|
|
26
|
+
bulk_ingest_client = BulkIngestClient(creds.dsp_ingest_url, auth, shortcode)
|
|
27
|
+
bulk_ingest_client.trigger_ingest_process()
|
|
28
|
+
sleep(5)
|
|
29
|
+
mapping = _retrieve_mapping(bulk_ingest_client)
|
|
30
|
+
_save_mapping(mapping, shortcode)
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _retrieve_mapping(bulk_ingest_client: BulkIngestClient) -> str:
|
|
35
|
+
sleeping_time = 60
|
|
36
|
+
desc = f"Wait until mapping CSV is ready. Ask server every {sleeping_time} seconds "
|
|
37
|
+
progress_bar = tqdm(
|
|
38
|
+
bulk_ingest_client.retrieve_mapping_generator(), desc=desc, bar_format="{desc}{elapsed}", dynamic_ncols=True
|
|
39
|
+
)
|
|
40
|
+
num_of_attempts = 0
|
|
41
|
+
num_of_server_errors = 0
|
|
42
|
+
for result in progress_bar:
|
|
43
|
+
if result is False:
|
|
44
|
+
num_of_attempts += 1
|
|
45
|
+
num_of_server_errors += 1
|
|
46
|
+
elif result is True:
|
|
47
|
+
num_of_attempts += 1
|
|
48
|
+
elif isinstance(result, str):
|
|
49
|
+
break
|
|
50
|
+
progress_bar.set_description(f"{desc}(attempts: {num_of_attempts}, server errors: {num_of_server_errors})")
|
|
51
|
+
sleep(sleeping_time)
|
|
52
|
+
return cast(str, result)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _save_mapping(mapping: str, shortcode: str) -> None:
|
|
56
|
+
filepath = Path(f"mapping-{shortcode}.csv")
|
|
57
|
+
if filepath.exists():
|
|
58
|
+
i = 1
|
|
59
|
+
while (new_name_for_existing := Path(f"mapping-{shortcode}-{i}.csv")).exists():
|
|
60
|
+
i += 1
|
|
61
|
+
filepath.rename(new_name_for_existing)
|
|
62
|
+
filepath.write_text(mapping, encoding="utf-8")
|
|
63
|
+
print(f"Saved mapping CSV to '{filepath}'")
|
|
64
|
+
logger.info(f"Saved mapping CSV to '{filepath}'")
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Iterable
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from dsp_tools.commands.ingest_xmlupload.upload_files.input_error import FileProblems
|
|
7
|
+
|
|
8
|
+
SUPPORTED_EXTENSIONS = (
|
|
9
|
+
"zip,tar,gz,z,tgz,gzip,7z,mp3,wav,pdf,doc,docx,xls,xlsx,ppt,pptx,epub,"
|
|
10
|
+
"mp4,jpg,jpeg,jp2,json,png,tif,tiff,odd,rng,txt,xml,htm,html,xsd,xsl,csv"
|
|
11
|
+
).split(",")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def check_files(files: Iterable[Path]) -> FileProblems | None:
|
|
15
|
+
"""Check if the files exist and have supported extensions."""
|
|
16
|
+
unsupported_files = [file for file in files if file.suffix[1:].casefold() not in SUPPORTED_EXTENSIONS]
|
|
17
|
+
non_existing_files = [file for file in files if not file.exists() and file not in unsupported_files]
|
|
18
|
+
if non_existing_files or unsupported_files:
|
|
19
|
+
return FileProblems(non_existing_files, unsupported_files)
|
|
20
|
+
return None
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from dsp_tools.error.problems import Problem
|
|
7
|
+
|
|
8
|
+
separator = "\n\n"
|
|
9
|
+
list_separator = "\n - "
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class FileProblems(Problem):
|
|
14
|
+
"""Handle the error communication to the user in case that some files don't exist or are unsupported."""
|
|
15
|
+
|
|
16
|
+
non_existing_files: list[Path]
|
|
17
|
+
unsupported_files: list[Path]
|
|
18
|
+
maximum_prints: int = 50
|
|
19
|
+
|
|
20
|
+
def __post_init__(self) -> None:
|
|
21
|
+
if not self.non_existing_files and not self.unsupported_files:
|
|
22
|
+
raise ValueError("It's not possible to create a FileProblems object without any problems.")
|
|
23
|
+
|
|
24
|
+
def execute_error_protocol(self) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Generate the error message to communicate the problems to the user.
|
|
27
|
+
If there are too many problems, save them to a file.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
error message
|
|
31
|
+
"""
|
|
32
|
+
msg = "Some files referenced in the <bitstream> tags of your XML file cannot be uploaded to the server."
|
|
33
|
+
if len(self.non_existing_files) + len(self.unsupported_files) > self.maximum_prints:
|
|
34
|
+
output_file = Path("file_problems.csv")
|
|
35
|
+
self._save_to_csv(output_file)
|
|
36
|
+
msg += f" The full list of files with problems has been saved to '{output_file}'."
|
|
37
|
+
return msg
|
|
38
|
+
if self.non_existing_files:
|
|
39
|
+
msg += separator
|
|
40
|
+
msg += "The following files don't exist on your computer:"
|
|
41
|
+
msg += list_separator + list_separator.join([str(file) for file in self.non_existing_files])
|
|
42
|
+
if self.unsupported_files:
|
|
43
|
+
msg += separator
|
|
44
|
+
msg += "The following files have unsupported extensions:"
|
|
45
|
+
msg += list_separator + list_separator.join([str(file) for file in self.unsupported_files])
|
|
46
|
+
return msg
|
|
47
|
+
|
|
48
|
+
def _save_to_csv(self, output_file: Path) -> None:
|
|
49
|
+
problems = ["File doesn't exist"] * len(self.non_existing_files) + ["Extension not supported"] * len(
|
|
50
|
+
self.unsupported_files
|
|
51
|
+
)
|
|
52
|
+
data = {
|
|
53
|
+
"File": self.non_existing_files + self.unsupported_files,
|
|
54
|
+
"Problem": problems,
|
|
55
|
+
}
|
|
56
|
+
df = pd.DataFrame(data)
|
|
57
|
+
df.to_csv(output_file, index=False)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import regex
|
|
6
|
+
|
|
7
|
+
separator = "\n\n"
|
|
8
|
+
list_separator = "\n- "
|
|
9
|
+
list_separator_indented = "\n - "
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class UploadFailure:
|
|
14
|
+
"""Information on why the upload of a file to the ingest server failed."""
|
|
15
|
+
|
|
16
|
+
filepath: Path
|
|
17
|
+
reason: str
|
|
18
|
+
status_code: int | None = None
|
|
19
|
+
response_text: str | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class UploadFailures:
|
|
24
|
+
"""Aggregated information of all failed uploads."""
|
|
25
|
+
|
|
26
|
+
failures: list[UploadFailure]
|
|
27
|
+
num_of_initial_files: int
|
|
28
|
+
shortcode: str
|
|
29
|
+
dsp_ingest_url: str
|
|
30
|
+
maximum_prints: int = 50
|
|
31
|
+
|
|
32
|
+
def execute_error_protocol(self) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Generate the error message to communicate the problems to the user.
|
|
35
|
+
If there are too many problems, save them to a file.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
error message
|
|
39
|
+
"""
|
|
40
|
+
ratio = f"{self.num_of_initial_files - len(self.failures)}/{self.num_of_initial_files}"
|
|
41
|
+
msg = f"Uploaded {ratio} files onto server {self.dsp_ingest_url}. "
|
|
42
|
+
if len(self.failures) > self.maximum_prints:
|
|
43
|
+
url = regex.sub(r"https?://", "", self.dsp_ingest_url)
|
|
44
|
+
output_file = Path(f"upload_failures_{self.shortcode}_{url}.csv")
|
|
45
|
+
self._save_to_csv(output_file)
|
|
46
|
+
msg += f"Failed to upload {len(self.failures)} files. "
|
|
47
|
+
msg += f"The full list of failed files has been saved to '{output_file}'."
|
|
48
|
+
else:
|
|
49
|
+
msg += f"Failed to upload the following {len(self.failures)} files:"
|
|
50
|
+
for f in self.failures:
|
|
51
|
+
msg += list_separator + f"{f.filepath}: {f.reason}"
|
|
52
|
+
if f.status_code:
|
|
53
|
+
msg += list_separator_indented + f"Status code: {f.status_code}"
|
|
54
|
+
if f.response_text:
|
|
55
|
+
msg += list_separator_indented + f"Response text: {f.response_text}"
|
|
56
|
+
return msg
|
|
57
|
+
|
|
58
|
+
def _save_to_csv(self, output_file: Path) -> None:
|
|
59
|
+
data = {
|
|
60
|
+
"Filepath": [failure.filepath for failure in self.failures],
|
|
61
|
+
"Reason": [failure.reason for failure in self.failures],
|
|
62
|
+
"Status code": [failure.status_code for failure in self.failures],
|
|
63
|
+
"Response text": [failure.response_text for failure in self.failures],
|
|
64
|
+
}
|
|
65
|
+
df = pd.DataFrame(data)
|
|
66
|
+
df.to_csv(output_file, index=False)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from lxml import etree
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
|
|
7
|
+
from dsp_tools.cli.args import ServerCredentials
|
|
8
|
+
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
9
|
+
from dsp_tools.commands.ingest_xmlupload.bulk_ingest_client import BulkIngestClient
|
|
10
|
+
from dsp_tools.commands.ingest_xmlupload.upload_files.filechecker import check_files
|
|
11
|
+
from dsp_tools.commands.ingest_xmlupload.upload_files.upload_failures import UploadFailure
|
|
12
|
+
from dsp_tools.commands.ingest_xmlupload.upload_files.upload_failures import UploadFailures
|
|
13
|
+
from dsp_tools.error.exceptions import InputError
|
|
14
|
+
from dsp_tools.utils.xml_parsing.parse_clean_validate_xml import parse_and_clean_xml_file
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def upload_files(
|
|
18
|
+
xml_file: Path,
|
|
19
|
+
creds: ServerCredentials,
|
|
20
|
+
imgdir: Path = Path.cwd(),
|
|
21
|
+
) -> bool:
|
|
22
|
+
"""
|
|
23
|
+
Upload all files referenced in an XML file to the ingest server.
|
|
24
|
+
This involves no processing/ingesting of the files, just uploading them.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
xml_file: XML file containing the resources and the references to the files to upload
|
|
28
|
+
creds: credentials to connect to the ingest server
|
|
29
|
+
imgdir: the bitstreams in the XML file are relative to this directory
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
success status
|
|
33
|
+
"""
|
|
34
|
+
root = parse_and_clean_xml_file(xml_file)
|
|
35
|
+
shortcode = root.attrib["shortcode"]
|
|
36
|
+
paths = _get_validated_paths(root)
|
|
37
|
+
print(f"Found {len(paths)} files to upload onto server {creds.dsp_ingest_url}.")
|
|
38
|
+
logger.info(f"Found {len(paths)} files to upload onto server {creds.dsp_ingest_url}.")
|
|
39
|
+
|
|
40
|
+
auth = AuthenticationClientLive(creds.server, creds.user, creds.password)
|
|
41
|
+
ingest_client = BulkIngestClient(creds.dsp_ingest_url, auth, shortcode, imgdir)
|
|
42
|
+
|
|
43
|
+
failures: list[UploadFailure] = []
|
|
44
|
+
progress_bar = tqdm(paths, desc="Uploading files", unit="file(s)", dynamic_ncols=True)
|
|
45
|
+
for path in progress_bar:
|
|
46
|
+
if res := ingest_client.upload_file(path):
|
|
47
|
+
failures.append(res)
|
|
48
|
+
progress_bar.set_description(f"Uploading files (failed: {len(failures)})")
|
|
49
|
+
if failures:
|
|
50
|
+
aggregated_failures = UploadFailures(failures, len(paths), shortcode, creds.dsp_ingest_url)
|
|
51
|
+
msg = aggregated_failures.execute_error_protocol()
|
|
52
|
+
logger.error(msg)
|
|
53
|
+
print(msg)
|
|
54
|
+
return False
|
|
55
|
+
else:
|
|
56
|
+
msg = f"Uploaded all {len(paths)} files onto server {creds.dsp_ingest_url}."
|
|
57
|
+
logger.info(msg)
|
|
58
|
+
print(msg)
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _get_validated_paths(root: etree._Element) -> set[Path]:
|
|
63
|
+
paths = {Path(x.text.strip()) for x in root.xpath("//bitstream")}
|
|
64
|
+
if problems := check_files(paths):
|
|
65
|
+
msg = problems.execute_error_protocol()
|
|
66
|
+
raise InputError(msg)
|
|
67
|
+
return paths
|
|
File without changes
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
from dsp_tools.cli.args import ServerCredentials
|
|
7
|
+
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
8
|
+
from dsp_tools.clients.connection_live import ConnectionLive
|
|
9
|
+
from dsp_tools.clients.legal_info_client import LegalInfoClient
|
|
10
|
+
from dsp_tools.clients.legal_info_client_live import LegalInfoClientLive
|
|
11
|
+
from dsp_tools.clients.project_client import ProjectClient
|
|
12
|
+
from dsp_tools.clients.project_client_live import ProjectClientLive
|
|
13
|
+
from dsp_tools.commands.xmlupload.models.ingest import AssetClient
|
|
14
|
+
from dsp_tools.commands.xmlupload.models.ingest import BulkIngestedAssetClient
|
|
15
|
+
from dsp_tools.commands.xmlupload.models.ingest import DspIngestClientLive
|
|
16
|
+
from dsp_tools.commands.xmlupload.models.upload_clients import UploadClients
|
|
17
|
+
from dsp_tools.commands.xmlupload.models.upload_state import UploadState
|
|
18
|
+
from dsp_tools.commands.xmlupload.prepare_xml_input.list_client import ListClient
|
|
19
|
+
from dsp_tools.commands.xmlupload.prepare_xml_input.list_client import ListClientLive
|
|
20
|
+
from dsp_tools.commands.xmlupload.upload_config import UploadConfig
|
|
21
|
+
from dsp_tools.commands.xmlupload.xmlupload import execute_upload
|
|
22
|
+
from dsp_tools.utils.ansi_colors import RED
|
|
23
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def resume_xmlupload(creds: ServerCredentials, skip_first_resource: bool = False) -> bool:
|
|
27
|
+
"""
|
|
28
|
+
Resume an interrupted xmlupload.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
creds: credentials to access the DSP server
|
|
32
|
+
skip_first_resource: if this flag is set, the first resource of the pending resources is removed
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
True if all resources could be uploaded without errors; False if one of the resources could not be
|
|
36
|
+
uploaded because there is an error in it
|
|
37
|
+
"""
|
|
38
|
+
server = creds.server
|
|
39
|
+
upload_state = _read_upload_state_from_disk(server)
|
|
40
|
+
if skip_first_resource:
|
|
41
|
+
_skip_first_resource(upload_state)
|
|
42
|
+
|
|
43
|
+
_print_and_log(upload_state, server)
|
|
44
|
+
|
|
45
|
+
auth = AuthenticationClientLive(server, creds.user, creds.password)
|
|
46
|
+
con = ConnectionLive(server, auth)
|
|
47
|
+
|
|
48
|
+
ingest_client: AssetClient
|
|
49
|
+
if upload_state.config.media_previously_uploaded:
|
|
50
|
+
ingest_client = BulkIngestedAssetClient()
|
|
51
|
+
else:
|
|
52
|
+
ingest_client = DspIngestClientLive(creds.dsp_ingest_url, auth, upload_state.config.shortcode, ".")
|
|
53
|
+
|
|
54
|
+
project_client: ProjectClient = ProjectClientLive(auth.server, auth)
|
|
55
|
+
list_client: ListClient = ListClientLive(con, project_client.get_project_iri(upload_state.config.shortcode))
|
|
56
|
+
legal_info_client: LegalInfoClient = LegalInfoClientLive(server, upload_state.config.shortcode, auth)
|
|
57
|
+
clients = UploadClients(ingest_client, list_client, legal_info_client)
|
|
58
|
+
|
|
59
|
+
return execute_upload(clients, upload_state)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _read_upload_state_from_disk(server: str) -> UploadState:
|
|
63
|
+
save_location = UploadConfig().with_server_info(server, "foo").diagnostics.save_location
|
|
64
|
+
with open(save_location, "rb") as f:
|
|
65
|
+
saved_state: UploadState = pickle.load(f) # noqa: S301 (deserialization of untrusted data)
|
|
66
|
+
return saved_state
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _skip_first_resource(upload_state: UploadState) -> None:
|
|
70
|
+
if len(upload_state.pending_resources) > 0:
|
|
71
|
+
upload_state.pending_resources.pop(0)
|
|
72
|
+
else:
|
|
73
|
+
msg = (
|
|
74
|
+
"The list of pending resources is empty.\n"
|
|
75
|
+
"It is not yet possible to skip the first item of the stashed properties.\n"
|
|
76
|
+
"Do you want to continue with the upload of the stashed properties anyway? [y/n]"
|
|
77
|
+
)
|
|
78
|
+
resp = None
|
|
79
|
+
while resp not in ["y", "n"]:
|
|
80
|
+
resp = input(RED + msg + RESET_TO_DEFAULT)
|
|
81
|
+
if resp == "n":
|
|
82
|
+
sys.exit(1)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _print_and_log(upload_state: UploadState, server: str) -> None:
|
|
86
|
+
previous_successful = len(upload_state.iri_resolver.lookup)
|
|
87
|
+
previous_failed = len(upload_state.failed_uploads)
|
|
88
|
+
previous_total = previous_successful + previous_failed
|
|
89
|
+
msg = (
|
|
90
|
+
f"Resuming upload for project {upload_state.config.shortcode} on server {server}. "
|
|
91
|
+
f"Number of resources uploaded until now: {previous_total}"
|
|
92
|
+
)
|
|
93
|
+
if previous_failed:
|
|
94
|
+
msg += f" ({previous_failed} of them failed)"
|
|
95
|
+
logger.info(msg)
|
|
96
|
+
print("\n==========================\n" + msg + "\n==========================\n")
|