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,119 @@
|
|
|
1
|
+
from http import HTTPStatus
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import rustworkx as rx
|
|
5
|
+
from loguru import logger
|
|
6
|
+
from rdflib import Literal
|
|
7
|
+
from rdflib import URIRef
|
|
8
|
+
from tqdm import tqdm
|
|
9
|
+
|
|
10
|
+
from dsp_tools.clients.ontology_clients import OntologyCreateClient
|
|
11
|
+
from dsp_tools.commands.create.create_on_server.onto_utils import get_modification_date_onto_lookup
|
|
12
|
+
from dsp_tools.commands.create.create_on_server.onto_utils import should_retry_request
|
|
13
|
+
from dsp_tools.commands.create.create_on_server.onto_utils import sort_for_upload
|
|
14
|
+
from dsp_tools.commands.create.models.create_problems import CollectedProblems
|
|
15
|
+
from dsp_tools.commands.create.models.create_problems import CreateProblem
|
|
16
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblem
|
|
17
|
+
from dsp_tools.commands.create.models.create_problems import UploadProblemType
|
|
18
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedProperty
|
|
19
|
+
from dsp_tools.commands.create.models.server_project_info import CreatedIriCollection
|
|
20
|
+
from dsp_tools.commands.create.models.server_project_info import ListNameToIriLookup
|
|
21
|
+
from dsp_tools.commands.create.models.server_project_info import OntoLastModDateLookup
|
|
22
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
23
|
+
from dsp_tools.commands.create.serialisation.ontology import serialise_property_graph_for_request
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_all_properties(
|
|
27
|
+
properties: list[ParsedProperty],
|
|
28
|
+
project_iri_lookup: ProjectIriLookup,
|
|
29
|
+
created_iris: CreatedIriCollection,
|
|
30
|
+
list_lookup: ListNameToIriLookup,
|
|
31
|
+
client: OntologyCreateClient,
|
|
32
|
+
) -> tuple[CreatedIriCollection, CollectedProblems | None]:
|
|
33
|
+
upload_order = _get_property_create_order(properties)
|
|
34
|
+
logger.debug(f"Property creation order: {upload_order}")
|
|
35
|
+
prop_lookup = {p.name: p for p in properties}
|
|
36
|
+
all_problems: list[CreateProblem] = []
|
|
37
|
+
onto_lookup = get_modification_date_onto_lookup(project_iri_lookup, client)
|
|
38
|
+
progress_bar = tqdm(upload_order, desc=" Creating properties", dynamic_ncols=True)
|
|
39
|
+
logger.debug("Starting property creation")
|
|
40
|
+
for p in progress_bar:
|
|
41
|
+
prop = prop_lookup[p]
|
|
42
|
+
if previous_blocker := _is_property_blocked(prop, created_iris):
|
|
43
|
+
all_problems.append(previous_blocker)
|
|
44
|
+
created_iris.failed_properties.add(prop.name)
|
|
45
|
+
else:
|
|
46
|
+
list_iri = None
|
|
47
|
+
if prop.node_name is not None:
|
|
48
|
+
if not (found := list_lookup.get_iri(prop.node_name)):
|
|
49
|
+
all_problems.append(UploadProblem(prop.name, UploadProblemType.PROPERTY_LIST_NOT_FOUND))
|
|
50
|
+
continue
|
|
51
|
+
else:
|
|
52
|
+
list_iri = Literal(f"hlist=<{found}>")
|
|
53
|
+
create_result = _create_one_property(prop, list_iri, onto_lookup, client)
|
|
54
|
+
if isinstance(create_result, Literal):
|
|
55
|
+
onto_lookup.update_last_mod_date(prop.onto_iri, create_result)
|
|
56
|
+
created_iris.created_properties.add(prop.name)
|
|
57
|
+
else:
|
|
58
|
+
all_problems.append(create_result)
|
|
59
|
+
created_iris.failed_properties.add(prop.name)
|
|
60
|
+
upload_problems = None
|
|
61
|
+
if all_problems:
|
|
62
|
+
upload_problems = CollectedProblems(
|
|
63
|
+
" While creating properties the following problems occurred:", all_problems
|
|
64
|
+
)
|
|
65
|
+
return created_iris, upload_problems
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _is_property_blocked(prop: ParsedProperty, created_iris: CreatedIriCollection) -> CreateProblem | None:
|
|
69
|
+
if created_iris.any_properties_failed(set(prop.supers)):
|
|
70
|
+
return UploadProblem(prop.name, UploadProblemType.PROPERTY_SUPER_FAILED)
|
|
71
|
+
if prop.object:
|
|
72
|
+
if created_iris.any_classes_failed({str(prop.object)}):
|
|
73
|
+
return UploadProblem(prop.name, UploadProblemType.PROPERTY_REFERENCES_FAILED_CLASS)
|
|
74
|
+
if prop.subject:
|
|
75
|
+
if created_iris.any_classes_failed({prop.subject}):
|
|
76
|
+
return UploadProblem(prop.name, UploadProblemType.PROPERTY_REFERENCES_FAILED_CLASS)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _get_property_create_order(properties: list[ParsedProperty]) -> list[str]:
|
|
81
|
+
logger.debug("Creating property upload order.")
|
|
82
|
+
graph, node_to_iri = _make_graph_to_sort(properties)
|
|
83
|
+
return sort_for_upload(graph, node_to_iri)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _make_graph_to_sort(properties: list[ParsedProperty]) -> tuple[rx.PyDiGraph, dict[int, str]]:
|
|
87
|
+
graph: rx.PyDiGraph[Any, Any] = rx.PyDiGraph()
|
|
88
|
+
prop_iris = [x.name for x in properties]
|
|
89
|
+
node_indices = list(graph.add_nodes_from(prop_iris))
|
|
90
|
+
iri_to_node = dict(zip(prop_iris, node_indices))
|
|
91
|
+
node_to_iri = dict(zip(node_indices, prop_iris))
|
|
92
|
+
for i, p in enumerate(properties):
|
|
93
|
+
for super_prop in p.supers:
|
|
94
|
+
if super_prop in prop_iris:
|
|
95
|
+
graph.add_edge(iri_to_node[p.name], iri_to_node[super_prop], i)
|
|
96
|
+
return graph, node_to_iri
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _create_one_property(
|
|
100
|
+
prop: ParsedProperty,
|
|
101
|
+
list_iri: Literal | None,
|
|
102
|
+
onto_lookup: OntoLastModDateLookup,
|
|
103
|
+
client: OntologyCreateClient,
|
|
104
|
+
) -> Literal | CreateProblem:
|
|
105
|
+
prop_serialised = serialise_property_graph_for_request(
|
|
106
|
+
prop, list_iri, URIRef(prop.onto_iri), onto_lookup.get_last_mod_date(prop.onto_iri)
|
|
107
|
+
)
|
|
108
|
+
request_result = client.post_new_property(prop_serialised)
|
|
109
|
+
if isinstance(request_result, Literal):
|
|
110
|
+
return request_result
|
|
111
|
+
if should_retry_request(request_result):
|
|
112
|
+
new_mod_date = client.get_last_modification_date(onto_lookup.project_iri, prop.onto_iri)
|
|
113
|
+
prop_serialised = serialise_property_graph_for_request(prop, list_iri, URIRef(prop.onto_iri), new_mod_date)
|
|
114
|
+
request_result = client.post_new_property(prop_serialised)
|
|
115
|
+
if isinstance(request_result, Literal):
|
|
116
|
+
return request_result
|
|
117
|
+
if request_result.status_code == HTTPStatus.BAD_REQUEST:
|
|
118
|
+
return UploadProblem(prop.name, request_result.text)
|
|
119
|
+
return UploadProblem(prop.name, UploadProblemType.PROPERTY_COULD_NOT_BE_CREATED)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from dsp_tools.error.exceptions import InternalError
|
|
2
|
+
from dsp_tools.error.exceptions import UserError
|
|
3
|
+
|
|
4
|
+
#######
|
|
5
|
+
# Input Validation Errors
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ProjectJsonSchemaValidationError(UserError):
|
|
9
|
+
def __init__(self, detail_msg: str) -> None:
|
|
10
|
+
super().__init__(detail_msg)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CircularOntologyDependency(UserError):
|
|
14
|
+
"""Class if a circular dependency was found in the ontology."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, dependency_location: str) -> None:
|
|
17
|
+
msg = (
|
|
18
|
+
f"A circular dependency of {dependency_location} was found in your project. "
|
|
19
|
+
f"It is not possible for an ontology to have circular dependencies."
|
|
20
|
+
)
|
|
21
|
+
super().__init__(msg)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
#######
|
|
25
|
+
# Internal Errors
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class UnableToCreateProjectError(InternalError):
|
|
29
|
+
"""Class if a project cannot be created."""
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
|
|
5
|
+
from dsp_tools.cli.args import ServerCredentials
|
|
6
|
+
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
7
|
+
from dsp_tools.clients.project_client_live import ProjectClientLive
|
|
8
|
+
from dsp_tools.commands.create.communicate_problems import print_all_problem_collections
|
|
9
|
+
from dsp_tools.commands.create.communicate_problems import print_problem_collection
|
|
10
|
+
from dsp_tools.commands.create.create_on_server.lists import create_lists
|
|
11
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedList
|
|
12
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedProject
|
|
13
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedProjectMetadata
|
|
14
|
+
from dsp_tools.commands.create.project_validate import parse_and_validate_project
|
|
15
|
+
from dsp_tools.error.exceptions import InternalError
|
|
16
|
+
from dsp_tools.error.exceptions import ProjectNotFoundError
|
|
17
|
+
from dsp_tools.utils.ansi_colors import BACKGROUND_BOLD_YELLOW
|
|
18
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def create_lists_only(project_file: Path, creds: ServerCredentials) -> bool:
|
|
22
|
+
parsing_result = parse_and_validate_project(project_file, creds.server)
|
|
23
|
+
match parsing_result:
|
|
24
|
+
case ParsedProject():
|
|
25
|
+
return _handle_parsed_project_result(parsing_result, creds)
|
|
26
|
+
case list():
|
|
27
|
+
print_all_problem_collections(parsing_result)
|
|
28
|
+
return False
|
|
29
|
+
case _:
|
|
30
|
+
raise InternalError("Unreachable result of project parsing.")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _handle_parsed_project_result(parsed_project: ParsedProject, creds: ServerCredentials) -> bool:
|
|
34
|
+
list_result = parsed_project.lists
|
|
35
|
+
match list_result:
|
|
36
|
+
case list():
|
|
37
|
+
return _execute_list_creation(parsed_project.project_metadata, list_result, creds)
|
|
38
|
+
case None:
|
|
39
|
+
msg = "Your file did not contain any lists, therefore no lists were created on the server."
|
|
40
|
+
logger.info(msg)
|
|
41
|
+
print(BACKGROUND_BOLD_YELLOW + msg + RESET_TO_DEFAULT)
|
|
42
|
+
return False
|
|
43
|
+
case _:
|
|
44
|
+
raise InternalError("Unreachable result of project parsing.")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _execute_list_creation(
|
|
48
|
+
project_metadata: ParsedProjectMetadata, parsed_lists: list[ParsedList], creds: ServerCredentials
|
|
49
|
+
) -> bool:
|
|
50
|
+
auth = AuthenticationClientLive(creds.server, creds.user, creds.password)
|
|
51
|
+
project_info = ProjectClientLive(creds.server, auth)
|
|
52
|
+
try:
|
|
53
|
+
project_iri = project_info.get_project_iri(project_metadata.shortcode)
|
|
54
|
+
except ProjectNotFoundError:
|
|
55
|
+
# we want a more precise error message
|
|
56
|
+
raise ProjectNotFoundError(
|
|
57
|
+
f"This commands adds lists to an existing project. "
|
|
58
|
+
f"The project with the shortcode {project_metadata.shortcode} does not exist on this server. "
|
|
59
|
+
f"If you wish to create an entire project, please use the `create` command without the flag."
|
|
60
|
+
) from None
|
|
61
|
+
|
|
62
|
+
_, problems = create_lists(parsed_lists, project_metadata.shortcode, auth, project_iri)
|
|
63
|
+
if problems:
|
|
64
|
+
print_problem_collection(problems)
|
|
65
|
+
return False
|
|
66
|
+
return True
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class CollectedProblems:
|
|
9
|
+
header: str
|
|
10
|
+
problems: list[CreateProblem]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class UserInformation:
|
|
15
|
+
focus_object: str
|
|
16
|
+
msg: UserInformationMessage
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class UserInformationMessage(StrEnum):
|
|
20
|
+
LIST_EXISTS_ON_SERVER = "The list already exists on the server, therefore it is skipped entirely."
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class CreateProblem:
|
|
25
|
+
problematic_object: str
|
|
26
|
+
problem: ProblemType | str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class InputProblem(CreateProblem):
|
|
31
|
+
problem: InputProblemType | str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class UploadProblem(CreateProblem):
|
|
36
|
+
problem: UploadProblemType | str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProblemType(StrEnum): ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class InputProblemType(ProblemType):
|
|
43
|
+
USER_PASSWORD_NOT_SET = (
|
|
44
|
+
"This user cannot be created as no password is specified and no default password is saved in a .env file."
|
|
45
|
+
)
|
|
46
|
+
DUPLICATE_LIST_NAME = "You have lists in your project with the same name, this is not permitted."
|
|
47
|
+
PREFIX_COULD_NOT_BE_RESOLVED = (
|
|
48
|
+
"The prefix used is not defined in the 'prefix' section of the file, "
|
|
49
|
+
"nor does it belong to one of the project ontologies."
|
|
50
|
+
)
|
|
51
|
+
INVALID_PERMISSIONS_OVERRULE = (
|
|
52
|
+
"This class cannot be used in limited_view permissions "
|
|
53
|
+
"because it is not a subclass of StillImageRepresentation."
|
|
54
|
+
)
|
|
55
|
+
UNDEFINED_REFERENCE = "Reference not defined in the project."
|
|
56
|
+
UNDEFINED_SUPER_PROPERTY = "This property is derived from an invalid super-property."
|
|
57
|
+
UNDEFINED_SUPER_CLASS = "This resource is derived from an invalid super-class."
|
|
58
|
+
UNDEFINED_PROPERTY_IN_CARDINALITY = "This cardinality references a property that does not exist."
|
|
59
|
+
DUPLICATE_CLASS_NAME = "This class name appears multiple times in the same ontology."
|
|
60
|
+
DUPLICATE_PROPERTY_NAME = "This property name appears multiple times in the same ontology."
|
|
61
|
+
MIN_CARDINALITY_ONE_WITH_CIRCLE = (
|
|
62
|
+
"This property is part of a circular reference and must have cardinality 0-1 or 0-n."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class UploadProblemType(ProblemType):
|
|
67
|
+
# Groups
|
|
68
|
+
GROUP_COULD_NOT_BE_CREATED = "The group could not be created."
|
|
69
|
+
# Users
|
|
70
|
+
USER_COULD_NOT_BE_CREATED = "The user could not be created."
|
|
71
|
+
USER_COULD_NOT_BE_ADDED_TO_GROUP = "The user could not be added to some or all of the custom groups."
|
|
72
|
+
USER_GROUPS_NOT_FOUND = "The user could not be added to the groups because they do not exist on the server."
|
|
73
|
+
PROJECT_MEMBERSHIP_COULD_NOT_BE_ADDED = "The user could not be added as project member."
|
|
74
|
+
PROJECT_ADMIN_COULD_NOT_BE_ADDED = "The user could not be added as project admin."
|
|
75
|
+
# Lists
|
|
76
|
+
LIST_COULD_NOT_BE_CREATED = "The list could not be created on the server."
|
|
77
|
+
LIST_NODE_COULD_NOT_BE_CREATED = "The list node could not be created on the server."
|
|
78
|
+
# Ontology
|
|
79
|
+
CARDINALITY_COULD_NOT_BE_ADDED = "The cardinality could not be added."
|
|
80
|
+
CARDINALITY_PROPERTY_NOT_FOUND = "The referenced property does not exist on the server."
|
|
81
|
+
PROPERTY_COULD_NOT_BE_CREATED = "The property could not be created."
|
|
82
|
+
PROPERTY_LIST_NOT_FOUND = "The property cannot be created, because the list it references does not exist."
|
|
83
|
+
PROPERTY_SUPER_FAILED = "The property cannot be created, because its super-property was not created."
|
|
84
|
+
PROPERTY_REFERENCES_FAILED_CLASS = "The property cannot be created, because a class it references was not created."
|
|
85
|
+
CLASS_COULD_NOT_BE_CREATED = "The class could not be created."
|
|
86
|
+
CLASS_SUPER_FAILED = "The class cannot be created, because its super-class was not created."
|
|
87
|
+
ONTOLOGY_COULD_NOT_BE_CREATED = "The ontology cannot be created."
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from enum import auto
|
|
7
|
+
|
|
8
|
+
from dsp_tools.utils.rdf_constants import KNORA_API_PREFIX
|
|
9
|
+
from dsp_tools.utils.rdf_constants import SALSAH_GUI_PREFIX
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class ParsedOntology:
|
|
14
|
+
name: str
|
|
15
|
+
label: str
|
|
16
|
+
comment: str | None
|
|
17
|
+
classes: list[ParsedClass]
|
|
18
|
+
properties: list[ParsedProperty]
|
|
19
|
+
cardinalities: list[ParsedClassCardinalities]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class ParsedClass:
|
|
24
|
+
name: str
|
|
25
|
+
labels: dict[str, str]
|
|
26
|
+
comments: dict[str, str] | None
|
|
27
|
+
supers: list[str]
|
|
28
|
+
onto_iri: str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class ParsedProperty:
|
|
33
|
+
name: str
|
|
34
|
+
labels: dict[str, str]
|
|
35
|
+
comments: dict[str, str] | None
|
|
36
|
+
supers: list[str]
|
|
37
|
+
object: KnoraObjectType | str
|
|
38
|
+
subject: str | None
|
|
39
|
+
gui_element: GuiElement
|
|
40
|
+
node_name: str | None
|
|
41
|
+
onto_iri: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class KnoraObjectType(StrEnum):
|
|
45
|
+
BOOLEAN = f"{KNORA_API_PREFIX}BooleanValue"
|
|
46
|
+
COLOR = f"{KNORA_API_PREFIX}ColorValue"
|
|
47
|
+
DATE = f"{KNORA_API_PREFIX}DateValue"
|
|
48
|
+
DECIMAL = f"{KNORA_API_PREFIX}DecimalValue"
|
|
49
|
+
GEONAME = f"{KNORA_API_PREFIX}GeonameValue"
|
|
50
|
+
INT = f"{KNORA_API_PREFIX}IntValue"
|
|
51
|
+
LIST = f"{KNORA_API_PREFIX}ListValue"
|
|
52
|
+
TEXT = f"{KNORA_API_PREFIX}TextValue"
|
|
53
|
+
TIME = f"{KNORA_API_PREFIX}TimeValue"
|
|
54
|
+
URI = f"{KNORA_API_PREFIX}UriValue"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class GuiElement(StrEnum):
|
|
58
|
+
CHECKBOX = f"{SALSAH_GUI_PREFIX}Checkbox"
|
|
59
|
+
COLORPICKER = f"{SALSAH_GUI_PREFIX}Colorpicker"
|
|
60
|
+
DATE = f"{SALSAH_GUI_PREFIX}Date"
|
|
61
|
+
SPINBOX = f"{SALSAH_GUI_PREFIX}Spinbox"
|
|
62
|
+
GEONAMES = f"{SALSAH_GUI_PREFIX}Geonames"
|
|
63
|
+
LIST = f"{SALSAH_GUI_PREFIX}List"
|
|
64
|
+
SIMPLETEXT = f"{SALSAH_GUI_PREFIX}SimpleText"
|
|
65
|
+
TEXTAREA = f"{SALSAH_GUI_PREFIX}Textarea"
|
|
66
|
+
RICHTEXT = f"{SALSAH_GUI_PREFIX}Richtext"
|
|
67
|
+
SEARCHBOX = f"{SALSAH_GUI_PREFIX}Searchbox"
|
|
68
|
+
TIME_STAMP = f"{SALSAH_GUI_PREFIX}TimeStamp"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class ParsedClassCardinalities:
|
|
73
|
+
class_iri: str
|
|
74
|
+
cards: list[ParsedPropertyCardinality]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class ParsedPropertyCardinality:
|
|
79
|
+
propname: str
|
|
80
|
+
cardinality: Cardinality
|
|
81
|
+
gui_order: int | None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class Cardinality(Enum):
|
|
85
|
+
C_0_1 = auto()
|
|
86
|
+
C_1 = auto()
|
|
87
|
+
C_0_N = auto()
|
|
88
|
+
C_1_N = auto()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ParsedProject:
|
|
10
|
+
prefixes: dict[str, str]
|
|
11
|
+
project_metadata: ParsedProjectMetadata
|
|
12
|
+
permissions: ParsedPermissions
|
|
13
|
+
groups: list[ParsedGroup]
|
|
14
|
+
users: list[ParsedUser]
|
|
15
|
+
user_memberships: list[ParsedUserMemberShipInfo]
|
|
16
|
+
lists: list[ParsedList]
|
|
17
|
+
ontologies: list[ParsedOntology]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ParsedProjectMetadata:
|
|
22
|
+
shortcode: str
|
|
23
|
+
shortname: str
|
|
24
|
+
longname: str
|
|
25
|
+
descriptions: dict[str, str]
|
|
26
|
+
keywords: list[str]
|
|
27
|
+
enabled_licenses: list[str]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class ParsedPermissions:
|
|
32
|
+
default_permissions: str
|
|
33
|
+
default_permissions_overrule: dict[str, str | list[str]] | None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class ParsedGroup:
|
|
38
|
+
name: str
|
|
39
|
+
descriptions: list[ParsedGroupDescription]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class ParsedGroupDescription:
|
|
44
|
+
lang: str
|
|
45
|
+
text: str
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class ParsedUser:
|
|
50
|
+
username: str
|
|
51
|
+
email: str
|
|
52
|
+
given_name: str
|
|
53
|
+
family_name: str
|
|
54
|
+
password: str
|
|
55
|
+
lang: str
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ParsedUserMemberShipInfo:
|
|
60
|
+
username: str
|
|
61
|
+
is_admin: bool
|
|
62
|
+
groups: list[str]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class ParsedList:
|
|
67
|
+
list_info: ParsedNodeInfo
|
|
68
|
+
children: list[ParsedListNode]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass
|
|
72
|
+
class ParsedNodeInfo:
|
|
73
|
+
name: str
|
|
74
|
+
labels: dict[str, str]
|
|
75
|
+
comments: dict[str, str] | None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class ParsedListNode:
|
|
80
|
+
node_info: ParsedNodeInfo
|
|
81
|
+
children: list[ParsedListNode]
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import field
|
|
3
|
+
|
|
4
|
+
from rdflib import Literal
|
|
5
|
+
from rdflib import URIRef
|
|
6
|
+
|
|
7
|
+
from dsp_tools.error.exceptions import InternalError
|
|
8
|
+
from dsp_tools.utils.rdf_constants import KNORA_API_PREFIX
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class ProjectIriLookup:
|
|
13
|
+
project_iri: str
|
|
14
|
+
onto_iris: dict[str, str] = field(default_factory=dict)
|
|
15
|
+
|
|
16
|
+
def add_onto(self, name: str, iri: str) -> None:
|
|
17
|
+
self.onto_iris[name] = iri
|
|
18
|
+
|
|
19
|
+
def does_onto_exist(self, name: str) -> bool:
|
|
20
|
+
return bool(self.onto_iris.get(name))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class OntoLastModDateLookup:
|
|
25
|
+
project_iri: str
|
|
26
|
+
onto_iris: dict[str, URIRef]
|
|
27
|
+
iri_to_last_modification_date: dict[str, Literal] = field(default_factory=dict)
|
|
28
|
+
|
|
29
|
+
def get_last_mod_date(self, iri: str) -> Literal:
|
|
30
|
+
return self.iri_to_last_modification_date[iri]
|
|
31
|
+
|
|
32
|
+
def update_last_mod_date(self, iri: str, last_modification_date: Literal) -> None:
|
|
33
|
+
self.iri_to_last_modification_date[iri] = last_modification_date
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class GroupNameToIriLookup:
|
|
38
|
+
name2iri: dict[str, str]
|
|
39
|
+
shortname: str
|
|
40
|
+
|
|
41
|
+
def check_exists(self, name: str) -> bool:
|
|
42
|
+
return name in self.name2iri.keys()
|
|
43
|
+
|
|
44
|
+
def add_iri(self, name: str, iri: str) -> None:
|
|
45
|
+
if self.check_exists(name):
|
|
46
|
+
raise InternalError(f"Group with the name '{name}' already exists in the lookup.")
|
|
47
|
+
self.name2iri[name] = iri
|
|
48
|
+
self.name2iri[f"{self.shortname}:{name}"] = iri
|
|
49
|
+
|
|
50
|
+
def get_iri(self, name: str) -> str | None:
|
|
51
|
+
return self.name2iri.get(name)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class UserNameToIriLookup:
|
|
56
|
+
name2iri: dict[str, str] = field(default_factory=dict)
|
|
57
|
+
|
|
58
|
+
def check_exists(self, name: str) -> bool:
|
|
59
|
+
return name in self.name2iri.keys()
|
|
60
|
+
|
|
61
|
+
def add_iri(self, name: str, iri: str) -> None:
|
|
62
|
+
if self.check_exists(name):
|
|
63
|
+
raise InternalError(f"User with the name '{name}' already exists in the lookup.")
|
|
64
|
+
self.name2iri[name] = iri
|
|
65
|
+
|
|
66
|
+
def get_iri(self, name: str) -> str | None:
|
|
67
|
+
return self.name2iri.get(name)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class CreatedIriCollection:
|
|
72
|
+
created_classes: set[str] = field(default_factory=set)
|
|
73
|
+
created_properties: set[str] = field(default_factory=set)
|
|
74
|
+
failed_classes: set[str] = field(default_factory=set)
|
|
75
|
+
failed_properties: set[str] = field(default_factory=set)
|
|
76
|
+
|
|
77
|
+
def __post_init__(self) -> None:
|
|
78
|
+
self.created_properties.update({f"{KNORA_API_PREFIX}seqnum", f"{KNORA_API_PREFIX}isPartOf"})
|
|
79
|
+
|
|
80
|
+
def any_properties_failed(self, props: set[str]) -> bool:
|
|
81
|
+
return bool(props.intersection(self.failed_properties))
|
|
82
|
+
|
|
83
|
+
def any_classes_failed(self, classes: set[str]) -> bool:
|
|
84
|
+
return bool(classes.intersection(self.failed_classes))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class ListNameToIriLookup:
|
|
89
|
+
name2iri: dict[str, str]
|
|
90
|
+
|
|
91
|
+
def check_list_exists(self, name: str) -> bool:
|
|
92
|
+
return name in self.name2iri.keys()
|
|
93
|
+
|
|
94
|
+
def add_iri(self, name: str, iri: str) -> None:
|
|
95
|
+
if self.check_list_exists(name):
|
|
96
|
+
raise InternalError(f"List with the name '{name}' already exists in the lookup.")
|
|
97
|
+
self.name2iri[name] = iri
|
|
98
|
+
|
|
99
|
+
def get_iri(self, name: str) -> str | None:
|
|
100
|
+
return self.name2iri.get(name)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from collections import Counter
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from dsp_tools.commands.create.models.create_problems import CollectedProblems
|
|
5
|
+
from dsp_tools.commands.create.models.create_problems import CreateProblem
|
|
6
|
+
from dsp_tools.commands.create.models.create_problems import InputProblem
|
|
7
|
+
from dsp_tools.commands.create.models.create_problems import InputProblemType
|
|
8
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedList
|
|
9
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedListNode
|
|
10
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedNodeInfo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def parse_list_section(lists: list[dict[str, Any]]) -> list[ParsedList] | CollectedProblems:
|
|
14
|
+
list_section = [_parse_one_list(one_list) for one_list in lists]
|
|
15
|
+
list_names = [parsed_list.list_info.name for parsed_list in list_section]
|
|
16
|
+
duplicates = {name for name, count in Counter(list_names).items() if count > 1}
|
|
17
|
+
if duplicates:
|
|
18
|
+
problems: list[CreateProblem] = [
|
|
19
|
+
InputProblem(problematic_object=name, problem=InputProblemType.DUPLICATE_LIST_NAME) for name in duplicates
|
|
20
|
+
]
|
|
21
|
+
return CollectedProblems(header="The following problems were found in the list section:", problems=problems)
|
|
22
|
+
return list_section
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _parse_one_list(one_list: dict[str, Any]) -> ParsedList:
|
|
26
|
+
list_info = _parse_node_info(one_list)
|
|
27
|
+
children = _parse_nodes_and_children(one_list["nodes"]) if "nodes" in one_list else []
|
|
28
|
+
return ParsedList(list_info=list_info, children=children)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _parse_node_info(one_node: dict[str, Any]) -> ParsedNodeInfo:
|
|
32
|
+
return ParsedNodeInfo(
|
|
33
|
+
name=one_node["name"],
|
|
34
|
+
labels=one_node["labels"],
|
|
35
|
+
comments=one_node.get("comments"),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _parse_nodes_and_children(list_nodes: list[dict[str, Any]]) -> list[ParsedListNode]:
|
|
40
|
+
parsed_nodes = []
|
|
41
|
+
for node in list_nodes:
|
|
42
|
+
node_info = _parse_node_info(node)
|
|
43
|
+
children = _parse_nodes_and_children(node["nodes"]) if "nodes" in node else []
|
|
44
|
+
parsed_nodes.append(ParsedListNode(node_info=node_info, children=children))
|
|
45
|
+
return parsed_nodes
|