dsp-tools 9.1.0.post11__py3-none-any.whl → 18.3.0.post13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dsp_tools/__init__.py +4 -0
- dsp_tools/cli/args.py +36 -0
- dsp_tools/cli/call_action.py +51 -231
- dsp_tools/cli/call_action_files_only.py +101 -0
- dsp_tools/cli/call_action_with_network.py +207 -0
- dsp_tools/cli/create_parsers.py +156 -58
- dsp_tools/cli/entry_point.py +56 -26
- dsp_tools/cli/utils.py +87 -0
- dsp_tools/clients/CLAUDE.md +420 -0
- dsp_tools/clients/authentication_client.py +14 -0
- dsp_tools/clients/authentication_client_live.py +66 -0
- dsp_tools/{utils → clients}/connection.py +2 -18
- dsp_tools/clients/connection_live.py +233 -0
- dsp_tools/clients/fuseki_metrics.py +60 -0
- dsp_tools/clients/group_user_clients.py +35 -0
- dsp_tools/clients/group_user_clients_live.py +181 -0
- dsp_tools/clients/legal_info_client.py +23 -0
- dsp_tools/clients/legal_info_client_live.py +132 -0
- dsp_tools/clients/list_client.py +49 -0
- dsp_tools/clients/list_client_live.py +166 -0
- dsp_tools/clients/metadata_client.py +24 -0
- dsp_tools/clients/metadata_client_live.py +47 -0
- dsp_tools/clients/ontology_clients.py +49 -0
- dsp_tools/clients/ontology_create_client_live.py +166 -0
- dsp_tools/clients/ontology_get_client_live.py +80 -0
- dsp_tools/clients/permissions_client.py +68 -0
- dsp_tools/clients/project_client.py +16 -0
- dsp_tools/clients/project_client_live.py +66 -0
- dsp_tools/commands/create/communicate_problems.py +24 -0
- dsp_tools/commands/create/create.py +134 -0
- dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
- dsp_tools/commands/create/create_on_server/classes.py +99 -0
- dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
- dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
- dsp_tools/commands/create/create_on_server/group_users.py +165 -0
- dsp_tools/commands/create/create_on_server/lists.py +163 -0
- dsp_tools/commands/create/create_on_server/mappers.py +12 -0
- dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
- dsp_tools/commands/create/create_on_server/ontology.py +52 -0
- dsp_tools/commands/create/create_on_server/project.py +68 -0
- dsp_tools/commands/create/create_on_server/properties.py +119 -0
- dsp_tools/commands/create/exceptions.py +29 -0
- dsp_tools/commands/create/lists_only.py +66 -0
- dsp_tools/commands/create/models/create_problems.py +87 -0
- dsp_tools/commands/create/models/parsed_ontology.py +88 -0
- dsp_tools/commands/create/models/parsed_project.py +81 -0
- dsp_tools/commands/create/models/rdf_ontology.py +12 -0
- dsp_tools/commands/create/models/server_project_info.py +100 -0
- dsp_tools/commands/create/parsing/parse_lists.py +45 -0
- dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
- dsp_tools/commands/create/parsing/parse_project.py +149 -0
- dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
- dsp_tools/commands/create/project_validate.py +595 -0
- dsp_tools/commands/create/serialisation/ontology.py +119 -0
- dsp_tools/commands/create/serialisation/project.py +44 -0
- dsp_tools/commands/excel2json/CLAUDE.md +101 -0
- dsp_tools/commands/excel2json/json_header.py +57 -23
- dsp_tools/commands/excel2json/{new_lists → lists}/compliance_checks.py +26 -26
- dsp_tools/commands/excel2json/{new_lists/make_new_lists.py → lists/make_lists.py} +19 -18
- dsp_tools/commands/excel2json/{new_lists → lists}/models/input_error.py +1 -12
- dsp_tools/commands/excel2json/{new_lists → lists}/models/serialise.py +9 -5
- dsp_tools/commands/excel2json/{new_lists → lists}/utils.py +4 -4
- dsp_tools/commands/excel2json/models/input_error.py +31 -11
- dsp_tools/commands/excel2json/models/json_header.py +53 -15
- dsp_tools/commands/excel2json/models/ontology.py +4 -3
- dsp_tools/commands/excel2json/{lists.py → old_lists.py} +26 -112
- dsp_tools/commands/excel2json/project.py +78 -34
- dsp_tools/commands/excel2json/properties.py +57 -36
- dsp_tools/commands/excel2json/resources.py +32 -12
- dsp_tools/commands/excel2json/utils.py +20 -1
- dsp_tools/commands/excel2xml/__init__.py +2 -2
- dsp_tools/commands/excel2xml/excel2xml_cli.py +7 -15
- dsp_tools/commands/excel2xml/excel2xml_lib.py +138 -493
- dsp_tools/commands/excel2xml/propertyelement.py +5 -5
- dsp_tools/commands/{project → get}/get.py +29 -13
- dsp_tools/commands/get/get_permissions.py +257 -0
- dsp_tools/commands/get/get_permissions_legacy.py +89 -0
- dsp_tools/commands/{project/models → get/legacy_models}/context.py +6 -6
- dsp_tools/commands/{project/models → get/legacy_models}/group.py +5 -10
- dsp_tools/commands/{project/models → get/legacy_models}/listnode.py +5 -35
- dsp_tools/commands/{project/models → get/legacy_models}/model.py +1 -1
- dsp_tools/commands/{project/models → get/legacy_models}/ontology.py +9 -14
- dsp_tools/commands/{project/models → get/legacy_models}/project.py +13 -6
- dsp_tools/commands/{project/models → get/legacy_models}/propertyclass.py +9 -16
- dsp_tools/commands/{project/models → get/legacy_models}/resourceclass.py +8 -46
- dsp_tools/commands/{project/models → get/legacy_models}/user.py +19 -60
- dsp_tools/commands/get/models/permissions_models.py +10 -0
- dsp_tools/commands/id2iri.py +20 -10
- dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +81 -56
- dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +4 -10
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +97 -37
- dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +2 -2
- dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +9 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +3 -3
- dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +2 -10
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +12 -2
- dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +8 -9
- dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +18 -18
- dsp_tools/commands/start_stack.py +126 -77
- dsp_tools/commands/update_legal/CLAUDE.md +344 -0
- dsp_tools/commands/update_legal/__init__.py +0 -0
- dsp_tools/commands/update_legal/core.py +182 -0
- dsp_tools/commands/update_legal/csv_operations.py +135 -0
- dsp_tools/commands/update_legal/models.py +87 -0
- dsp_tools/commands/update_legal/xml_operations.py +247 -0
- dsp_tools/commands/validate_data/CLAUDE.md +159 -0
- dsp_tools/commands/validate_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/constants.py +59 -0
- dsp_tools/commands/validate_data/mappers.py +143 -0
- dsp_tools/commands/validate_data/models/__init__.py +0 -0
- dsp_tools/commands/validate_data/models/api_responses.py +45 -0
- dsp_tools/commands/validate_data/models/input_problems.py +119 -0
- dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
- dsp_tools/commands/validate_data/models/validation.py +106 -0
- dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
- dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
- dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
- dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
- dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
- dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
- dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
- dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
- dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
- dsp_tools/commands/{xml_validate/sparql/resource_shacl.py → validate_data/sparql/cardinality_shacl.py} +45 -47
- dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
- dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
- dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
- dsp_tools/commands/validate_data/utils.py +59 -0
- dsp_tools/commands/validate_data/validate_data.py +283 -0
- dsp_tools/commands/validate_data/validation/__init__.py +0 -0
- dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
- dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
- dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
- dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
- dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
- dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
- dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
- dsp_tools/commands/xmlupload/models/formatted_text_value.py +0 -25
- dsp_tools/commands/xmlupload/models/ingest.py +56 -70
- dsp_tools/commands/xmlupload/models/input_problems.py +6 -14
- dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
- dsp_tools/commands/xmlupload/models/permission.py +0 -39
- dsp_tools/commands/xmlupload/models/{deserialise/xmlpermission.py → permissions_parsed.py} +2 -2
- dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
- dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
- dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
- dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
- dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
- dsp_tools/commands/xmlupload/models/upload_clients.py +3 -3
- dsp_tools/commands/xmlupload/models/upload_state.py +2 -4
- dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
- dsp_tools/commands/xmlupload/{ark2iri.py → prepare_xml_input/ark2iri.py} +1 -1
- dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
- dsp_tools/commands/xmlupload/{iiif_uri_validator.py → prepare_xml_input/iiif_uri_validator.py} +2 -14
- dsp_tools/commands/xmlupload/{list_client.py → prepare_xml_input/list_client.py} +15 -10
- dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
- dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
- dsp_tools/commands/xmlupload/resource_create_client.py +7 -468
- dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
- dsp_tools/commands/xmlupload/stash/{construct_and_analyze_graph.py → analyse_circular_reference_graph.py} +64 -157
- dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
- dsp_tools/commands/xmlupload/stash/graph_models.py +13 -8
- dsp_tools/commands/xmlupload/stash/stash_circular_references.py +48 -115
- dsp_tools/commands/xmlupload/stash/stash_models.py +4 -9
- dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +34 -40
- dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +98 -108
- dsp_tools/commands/xmlupload/upload_config.py +8 -0
- dsp_tools/commands/xmlupload/write_diagnostic_info.py +14 -9
- dsp_tools/commands/xmlupload/xmlupload.py +214 -192
- dsp_tools/config/__init__.py +0 -0
- dsp_tools/config/logger_config.py +69 -0
- dsp_tools/{utils → config}/warnings_config.py +4 -1
- dsp_tools/error/__init__.py +0 -0
- dsp_tools/error/custom_warnings.py +39 -0
- dsp_tools/error/exceptions.py +204 -0
- dsp_tools/error/problems.py +10 -0
- dsp_tools/error/xmllib_errors.py +20 -0
- dsp_tools/error/xmllib_warnings.py +54 -0
- dsp_tools/error/xmllib_warnings_util.py +159 -0
- dsp_tools/error/xsd_validation_error_msg.py +19 -0
- dsp_tools/legacy_models/__init__.py +0 -0
- dsp_tools/{models → legacy_models}/datetimestamp.py +7 -7
- dsp_tools/{models → legacy_models}/langstring.py +1 -1
- dsp_tools/{models → legacy_models}/projectContext.py +4 -4
- dsp_tools/resources/schema/data.xsd +108 -83
- dsp_tools/resources/schema/lists-only.json +4 -23
- dsp_tools/resources/schema/project.json +80 -35
- dsp_tools/resources/schema/properties-only.json +1 -4
- dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
- dsp_tools/resources/start-stack/docker-compose.yml +34 -30
- dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
- dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
- dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
- dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
- dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
- dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
- dsp_tools/utils/ansi_colors.py +32 -0
- dsp_tools/utils/data_formats/__init__.py +0 -0
- dsp_tools/utils/{date_util.py → data_formats/date_util.py} +13 -1
- dsp_tools/utils/data_formats/iri_util.py +30 -0
- dsp_tools/utils/{shared.py → data_formats/shared.py} +1 -35
- dsp_tools/utils/{uri_util.py → data_formats/uri_util.py} +12 -2
- dsp_tools/utils/fuseki_bloating.py +63 -0
- dsp_tools/utils/json_parsing.py +22 -0
- dsp_tools/utils/rdf_constants.py +42 -0
- dsp_tools/utils/rdflib_utils.py +10 -0
- dsp_tools/utils/replace_id_with_iri.py +66 -0
- dsp_tools/utils/request_utils.py +238 -0
- dsp_tools/utils/xml_parsing/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
- dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
- dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
- dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
- dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
- dsp_tools/xmllib/CLAUDE.md +302 -0
- dsp_tools/xmllib/__init__.py +49 -0
- dsp_tools/xmllib/general_functions.py +877 -0
- dsp_tools/xmllib/internal/__init__.py +0 -0
- dsp_tools/xmllib/internal/checkers.py +162 -0
- dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
- dsp_tools/xmllib/internal/constants.py +46 -0
- dsp_tools/xmllib/internal/input_converters.py +155 -0
- dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
- dsp_tools/xmllib/internal/serialise_resource.py +177 -0
- dsp_tools/xmllib/internal/serialise_values.py +152 -0
- dsp_tools/xmllib/internal/type_aliases.py +11 -0
- dsp_tools/xmllib/models/config_options.py +28 -0
- dsp_tools/xmllib/models/date_formats.py +48 -0
- dsp_tools/xmllib/models/dsp_base_resources.py +1380 -400
- dsp_tools/xmllib/models/internal/__init__.py +0 -0
- dsp_tools/xmllib/models/internal/file_values.py +172 -0
- dsp_tools/xmllib/models/internal/geometry.py +162 -0
- dsp_tools/xmllib/models/{migration_metadata.py → internal/migration_metadata.py} +14 -10
- dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
- dsp_tools/xmllib/models/internal/values.py +342 -0
- dsp_tools/xmllib/models/licenses/__init__.py +0 -0
- dsp_tools/xmllib/models/licenses/other.py +59 -0
- dsp_tools/xmllib/models/licenses/recommended.py +107 -0
- dsp_tools/xmllib/models/permissions.py +41 -0
- dsp_tools/xmllib/models/res.py +1782 -0
- dsp_tools/xmllib/models/root.py +313 -26
- dsp_tools/xmllib/value_checkers.py +310 -47
- dsp_tools/xmllib/value_converters.py +765 -8
- dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
- dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
- dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
- {dsp_tools-9.1.0.post11.dist-info → dsp_tools-18.3.0.post13.dist-info}/entry_points.txt +1 -0
- dsp_tools/commands/project/create/project_create.py +0 -1107
- dsp_tools/commands/project/create/project_create_lists.py +0 -204
- dsp_tools/commands/project/create/project_validate.py +0 -453
- dsp_tools/commands/project/models/project_definition.py +0 -12
- dsp_tools/commands/rosetta.py +0 -124
- dsp_tools/commands/template.py +0 -30
- dsp_tools/commands/xml_validate/api_connection.py +0 -122
- dsp_tools/commands/xml_validate/deserialise_input.py +0 -135
- dsp_tools/commands/xml_validate/make_data_rdf.py +0 -193
- dsp_tools/commands/xml_validate/models/data_deserialised.py +0 -108
- dsp_tools/commands/xml_validate/models/data_rdf.py +0 -214
- dsp_tools/commands/xml_validate/models/input_problems.py +0 -191
- dsp_tools/commands/xml_validate/models/validation.py +0 -29
- dsp_tools/commands/xml_validate/reformat_validaton_result.py +0 -89
- dsp_tools/commands/xml_validate/sparql/construct_shapes.py +0 -16
- dsp_tools/commands/xml_validate/xml_validate.py +0 -151
- dsp_tools/commands/xmlupload/check_consistency_with_ontology.py +0 -253
- dsp_tools/commands/xmlupload/models/deserialise/deserialise_value.py +0 -236
- dsp_tools/commands/xmlupload/models/deserialise/xmlresource.py +0 -171
- dsp_tools/commands/xmlupload/models/namespace_context.py +0 -39
- dsp_tools/commands/xmlupload/models/ontology_lookup_models.py +0 -161
- dsp_tools/commands/xmlupload/models/ontology_problem_models.py +0 -178
- dsp_tools/commands/xmlupload/models/serialise/jsonld_serialiser.py +0 -40
- dsp_tools/commands/xmlupload/models/serialise/serialise_value.py +0 -51
- dsp_tools/commands/xmlupload/ontology_client.py +0 -92
- dsp_tools/commands/xmlupload/project_client.py +0 -91
- dsp_tools/commands/xmlupload/read_validate_xml_file.py +0 -99
- dsp_tools/models/custom_warnings.py +0 -31
- dsp_tools/models/exceptions.py +0 -90
- dsp_tools/resources/0100-template-repo/template.json +0 -45
- dsp_tools/resources/0100-template-repo/template.xml +0 -27
- dsp_tools/resources/start-stack/docker-compose-validation.yml +0 -5
- dsp_tools/resources/start-stack/start-stack-config.yml +0 -4
- dsp_tools/resources/xml_validate/api-shapes.ttl +0 -411
- dsp_tools/resources/xml_validate/replace_namespace.xslt +0 -61
- dsp_tools/utils/connection_live.py +0 -383
- dsp_tools/utils/iri_util.py +0 -14
- dsp_tools/utils/logger_config.py +0 -41
- dsp_tools/utils/set_encoder.py +0 -20
- dsp_tools/utils/xml_utils.py +0 -145
- dsp_tools/utils/xml_validation.py +0 -197
- dsp_tools/utils/xml_validation_models.py +0 -68
- dsp_tools/xmllib/models/file_values.py +0 -78
- dsp_tools/xmllib/models/resource.py +0 -415
- dsp_tools/xmllib/models/values.py +0 -428
- dsp_tools-9.1.0.post11.dist-info/METADATA +0 -130
- dsp_tools-9.1.0.post11.dist-info/RECORD +0 -167
- dsp_tools-9.1.0.post11.dist-info/WHEEL +0 -4
- dsp_tools-9.1.0.post11.dist-info/licenses/LICENSE +0 -674
- /dsp_tools/{commands/excel2json/new_lists → clients}/__init__.py +0 -0
- /dsp_tools/commands/{excel2json/new_lists/models → create}/__init__.py +0 -0
- /dsp_tools/commands/{project → create/create_on_server}/__init__.py +0 -0
- /dsp_tools/commands/{project/create → create/models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → create/parsing}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate → create/serialisation}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/models → excel2json/lists}/__init__.py +0 -0
- /dsp_tools/commands/{xml_validate/sparql → excel2json/lists/models}/__init__.py +0 -0
- /dsp_tools/commands/excel2json/{new_lists → lists}/models/deserialise.py +0 -0
- /dsp_tools/commands/{xmlupload/models/deserialise → get}/__init__.py +0 -0
- /dsp_tools/commands/{xmlupload/models/serialise → get/legacy_models}/__init__.py +0 -0
- /dsp_tools/commands/{project/models → get/legacy_models}/helpers.py +0 -0
- /dsp_tools/{models → commands/get/models}/__init__.py +0 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
# Client Pattern Documentation
|
|
2
|
+
|
|
3
|
+
This document describes the architectural pattern used for client classes in DSP-TOOLS.
|
|
4
|
+
These clients provide interfaces to interact with the DSP-API endpoints.
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
The client architecture follows a **Protocol-based dependency injection pattern** that separates interface definitions
|
|
9
|
+
from concrete implementations. This design enables testability, modularity, and clear contracts between components.
|
|
10
|
+
The clients should be as simple to initiate as possible and be stateless, if possible.
|
|
11
|
+
|
|
12
|
+
## Core Components
|
|
13
|
+
|
|
14
|
+
### 1. Protocol Classes (Abstract Interfaces)
|
|
15
|
+
|
|
16
|
+
Protocol classes define the contract that implementations must follow:
|
|
17
|
+
|
|
18
|
+
- **Location**: `src/dsp_tools/clients/`
|
|
19
|
+
- **Naming**: `<Domain>Client` (e.g., `AuthenticationClient`, `LegalInfoClient`)
|
|
20
|
+
- **Implementation**: Use `typing.Protocol` for structural subtyping
|
|
21
|
+
- **Purpose**: Define required attributes and method signatures without implementation
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from typing import Protocol
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AuthenticationClient(Protocol):
|
|
30
|
+
server: str
|
|
31
|
+
email: str
|
|
32
|
+
password: str
|
|
33
|
+
|
|
34
|
+
def get_token(self) -> str:
|
|
35
|
+
pass
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Live Implementations
|
|
39
|
+
|
|
40
|
+
Live implementations are concrete classes that interact with real DSP API endpoints:
|
|
41
|
+
|
|
42
|
+
- **Location**: `src/dsp_tools/clients/`
|
|
43
|
+
- **Naming**: `<Domain>ClientLive` (e.g., `AuthenticationClientLive`, `LegalInfoClientLive`)
|
|
44
|
+
- **Decorator**: Always use `@dataclass` decorator
|
|
45
|
+
- **Inheritance**: Inherit from corresponding Protocol class
|
|
46
|
+
- **Purpose**: Implement actual HTTP communication with the DSP-API
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from dataclasses import dataclass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class AuthenticationClientLive(AuthenticationClient):
|
|
56
|
+
server: str
|
|
57
|
+
email: str
|
|
58
|
+
password: str
|
|
59
|
+
_token: str | None = None
|
|
60
|
+
|
|
61
|
+
def get_token(self) -> str:
|
|
62
|
+
# Implementation here
|
|
63
|
+
pass
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Implementation Pattern
|
|
67
|
+
|
|
68
|
+
### Required Attributes
|
|
69
|
+
|
|
70
|
+
Live clients typically include:
|
|
71
|
+
|
|
72
|
+
- **Server identification**: `api_url`
|
|
73
|
+
- **Project identification**: `shortcode`, `project_shortcode`, `project_iri`
|
|
74
|
+
- **Authentication**: `auth: AuthenticationClient` (for endpoints requiring auth)
|
|
75
|
+
- **Private state**: Optional private attributes (e.g., `_token`)
|
|
76
|
+
|
|
77
|
+
### Request Workflow
|
|
78
|
+
|
|
79
|
+
There are two main patterns, in some cases the code cannot continue if a request is not successful, see pattern 1.
|
|
80
|
+
If the code may continue even if the request is not successful, then `None` will be returned, see pattern 2.
|
|
81
|
+
|
|
82
|
+
In most cases `HTTPStatus.FORBIDDEN` will mean that a `BadCredentialsError` will be raised
|
|
83
|
+
|
|
84
|
+
Pattern 1: If the request is not successfully, then an error is raised.
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
def _make_request(self, url: str, data: dict[str, Any] | None = None) -> Response:
|
|
88
|
+
# 1. Prepare request parameters
|
|
89
|
+
headers = {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
"Authorization": f"Bearer {self.auth.get_token()}",
|
|
92
|
+
}
|
|
93
|
+
params = RequestParameters("POST", url, TIMEOUT, data, headers)
|
|
94
|
+
|
|
95
|
+
# 2. Log the request
|
|
96
|
+
log_request(params)
|
|
97
|
+
|
|
98
|
+
# 3. Execute request with exception handling
|
|
99
|
+
try:
|
|
100
|
+
response = requests.post(
|
|
101
|
+
url=params.url,
|
|
102
|
+
headers=params.headers,
|
|
103
|
+
data=params.data_serialized,
|
|
104
|
+
timeout=params.timeout,
|
|
105
|
+
)
|
|
106
|
+
except RequestException as err:
|
|
107
|
+
log_and_raise_request_exception(err)
|
|
108
|
+
|
|
109
|
+
# 4. Log the response
|
|
110
|
+
log_response(response)
|
|
111
|
+
|
|
112
|
+
# 5. Handle response status
|
|
113
|
+
if response.ok:
|
|
114
|
+
return response
|
|
115
|
+
|
|
116
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
117
|
+
raise BadCredentialsError(
|
|
118
|
+
"Only a SystemAdmin or ProjectAdmin can do ... "
|
|
119
|
+
"Your permissions are insufficient for this action.."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Pattern 2: If the request is not successful, then the user is warned and `None` is returned
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def create_resource(self, resource_data: dict[str, Any]) -> str | None:
|
|
129
|
+
# 1. Prepare request parameters
|
|
130
|
+
url = f"{self.api_url}/v2/resources"
|
|
131
|
+
headers = {
|
|
132
|
+
"Content-Type": "application/json",
|
|
133
|
+
"Authorization": f"Bearer {self.auth.get_token()}",
|
|
134
|
+
}
|
|
135
|
+
params = RequestParameters("POST", url, TIMEOUT, resource_data, headers)
|
|
136
|
+
|
|
137
|
+
# 2. Log the request
|
|
138
|
+
log_request(params)
|
|
139
|
+
|
|
140
|
+
# 3. Execute request with exception handling
|
|
141
|
+
try:
|
|
142
|
+
response = requests.post(
|
|
143
|
+
url=params.url,
|
|
144
|
+
headers=params.headers,
|
|
145
|
+
data=params.data_serialized,
|
|
146
|
+
timeout=params.timeout,
|
|
147
|
+
)
|
|
148
|
+
except RequestException as err:
|
|
149
|
+
log_and_raise_request_exception(err)
|
|
150
|
+
|
|
151
|
+
# 4. Log the response
|
|
152
|
+
log_response(response)
|
|
153
|
+
|
|
154
|
+
# 5. Handle response status
|
|
155
|
+
if response.ok:
|
|
156
|
+
result = response.json()
|
|
157
|
+
resource_iri = cast(str, result["@id"])
|
|
158
|
+
return resource_iri
|
|
159
|
+
|
|
160
|
+
# 6. Handle specific known error cases
|
|
161
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
162
|
+
raise BadCredentialsError("You don't have permission to create resources in this project.")
|
|
163
|
+
|
|
164
|
+
# 7. Handle unexpected errors non-fatally
|
|
165
|
+
log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
|
|
166
|
+
return None
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Key Steps
|
|
170
|
+
|
|
171
|
+
1. **Prepare Request Parameters**: Create `RequestParameters` object with method, URL, timeout, data, and headers
|
|
172
|
+
2. **Log Request**: Call `log_request(params)` before making the request
|
|
173
|
+
3. **Execute Request**: Use `requests.<method>()` with explicit parameters wrapped in try/except
|
|
174
|
+
4. **Log Response**: Call `log_response(response)` after receiving response
|
|
175
|
+
5. **Handle Status**: Check response status and raise appropriate exceptions
|
|
176
|
+
|
|
177
|
+
### Error Handling Strategy
|
|
178
|
+
|
|
179
|
+
- **Network errors**: Catch `RequestException` and call `log_and_raise_request_exception(err)`
|
|
180
|
+
- **Authentication/Authorization (401/403)**: Raise `BadCredentialsError` with context-specific message
|
|
181
|
+
- **Other API errors**: Raise `FatalNonOkApiResponseCode` with URL, status code, and response text
|
|
182
|
+
- **Expected failures**: Use `log_and_warn_unexpected_non_ok_response()` when failure is non-fatal
|
|
183
|
+
|
|
184
|
+
### 401 vs 403: Authentication vs Authorization
|
|
185
|
+
|
|
186
|
+
It's crucial to distinguish between authentication failures (401) and authorization failures (403):
|
|
187
|
+
|
|
188
|
+
#### 401 Unauthorized - Authentication Failure
|
|
189
|
+
|
|
190
|
+
- **Meaning**: "Who are you?" - The request lacks credentials, or the credentials are invalid/expired
|
|
191
|
+
- **Example error message**: "Please ensure that an account for this email exists and that the password is correct."
|
|
192
|
+
- **Where to handle this**: Only in the authentication client. All other clients depend on the authentication client,
|
|
193
|
+
so it's pointless to handle 401 there.
|
|
194
|
+
|
|
195
|
+
#### 403 Forbidden - Authorization Failure
|
|
196
|
+
|
|
197
|
+
- **Meaning**: "I know who you are, but you can't do that" - The user is authenticated but lacks sufficient permissions
|
|
198
|
+
- **When to use**: Insufficient role/permissions, project membership required, admin-only actions
|
|
199
|
+
- **Example error message**: "Only a SystemAdmin or ProjectAdmin can create new copyright holders."
|
|
200
|
+
- **Where to handle this**: In all clients except the authentication client,
|
|
201
|
+
and except the clients that only access public endpoints.
|
|
202
|
+
|
|
203
|
+
#### Code Examples
|
|
204
|
+
|
|
205
|
+
Correct 401 handling (authentication):
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
if response.status_code == HTTPStatus.UNAUTHORIZED:
|
|
209
|
+
raise BadCredentialsError("Authentication failed. Please check your credentials.")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Correct 403 handling (authorization):
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
216
|
+
raise BadCredentialsError(
|
|
217
|
+
"Only a SystemAdmin or ProjectAdmin can create new copyright holders. "
|
|
218
|
+
"Your permissions are insufficient for this action."
|
|
219
|
+
)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Common Imports
|
|
223
|
+
|
|
224
|
+
All live clients typically import:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from dataclasses import dataclass
|
|
228
|
+
from http import HTTPStatus
|
|
229
|
+
from typing import Any, cast
|
|
230
|
+
|
|
231
|
+
import requests
|
|
232
|
+
from loguru import logger
|
|
233
|
+
from requests import RequestException, Response
|
|
234
|
+
|
|
235
|
+
from dsp_tools.clients. < protocol_file >
|
|
236
|
+
import < ProtocolClass >
|
|
237
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
238
|
+
from dsp_tools.error.exceptions import BadCredentialsError, FatalNonOkApiResponseCode
|
|
239
|
+
from dsp_tools.utils.request_utils import (
|
|
240
|
+
RequestParameters,
|
|
241
|
+
log_and_raise_request_exception,
|
|
242
|
+
log_request,
|
|
243
|
+
log_response,
|
|
244
|
+
)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Constants
|
|
248
|
+
|
|
249
|
+
- **Timeout values**: Define module-level constants for timeouts (e.g., `TIMEOUT = 60`)
|
|
250
|
+
- **Default values**: Use module-level constants for commonly used values
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
TIMEOUT = 60
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Type Safety
|
|
257
|
+
|
|
258
|
+
- **Type hints**: All parameters, return types, and attributes must have type hints
|
|
259
|
+
- **JSON responses**: Use `cast()` when extracting values from JSON responses
|
|
260
|
+
- **Optional returns**: Use `| None` for methods that may return None
|
|
261
|
+
|
|
262
|
+
Example:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
def get_token(self) -> str:
|
|
266
|
+
res_json: dict[str, Any] = response.json()
|
|
267
|
+
tkn = cast(str, res_json["token"])
|
|
268
|
+
return tkn
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Testing Strategy
|
|
272
|
+
|
|
273
|
+
- **Mock implementations**: Create mock/fake clients implementing the Protocol for testing
|
|
274
|
+
- **Dependency injection**: Pass Protocol types to consumers, not concrete implementations
|
|
275
|
+
- **Unittesting**: Test live clients with mocked `requests` library
|
|
276
|
+
- **End-to-end testing**: Test against DSP-API in a test container
|
|
277
|
+
|
|
278
|
+
## Client Dependencies
|
|
279
|
+
|
|
280
|
+
Clients can depend on other clients (via their Protocol):
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
@dataclass
|
|
284
|
+
class LegalInfoClientLive(LegalInfoClient):
|
|
285
|
+
server: str
|
|
286
|
+
project_shortcode: str
|
|
287
|
+
auth: AuthenticationClient # Protocol type, not concrete
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
This enables:
|
|
291
|
+
|
|
292
|
+
- Testing with mock authentication clients
|
|
293
|
+
- Flexibility in authentication strategy
|
|
294
|
+
- Clear dependency contracts
|
|
295
|
+
|
|
296
|
+
## Authentication Pattern
|
|
297
|
+
|
|
298
|
+
Clients requiring authentication:
|
|
299
|
+
|
|
300
|
+
1. Accept `auth: AuthenticationClient` as an attribute
|
|
301
|
+
2. Call `self.auth.get_token()` to get bearer token
|
|
302
|
+
3. Include token in `Authorization` header: `f"Bearer {self.auth.get_token()}"`
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
headers = {
|
|
308
|
+
"Content-Type": "application/json",
|
|
309
|
+
"Authorization": f"Bearer {self.auth.get_token()}",
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Best Practices
|
|
314
|
+
|
|
315
|
+
### DO
|
|
316
|
+
|
|
317
|
+
- Use `@dataclass` decorator for all live implementations
|
|
318
|
+
- Log all requests and responses using provided utilities
|
|
319
|
+
- Provide descriptive, actionable error messages
|
|
320
|
+
- Create custom Error Classes if it makes sense
|
|
321
|
+
- Use module-level constants for timeouts
|
|
322
|
+
- Handle specific HTTP status codes with appropriate exceptions
|
|
323
|
+
- Type hint all parameters and return values
|
|
324
|
+
- Use private methods (prefix with `_`) for internal helpers
|
|
325
|
+
- Follow the standardized request workflow
|
|
326
|
+
|
|
327
|
+
### DON'T
|
|
328
|
+
|
|
329
|
+
- Skip request/response logging
|
|
330
|
+
- Use generic error messages
|
|
331
|
+
- Hardcode timeout values in method calls
|
|
332
|
+
- Catch exceptions without re-raising or logging
|
|
333
|
+
- Return raw response objects from public methods
|
|
334
|
+
- Mix business logic with HTTP communication
|
|
335
|
+
|
|
336
|
+
## Naming Conventions
|
|
337
|
+
|
|
338
|
+
- **Protocol files**: `<domain>_client.py`
|
|
339
|
+
- **Protocol classes**: `<Domain>Client`
|
|
340
|
+
- **Implementation files**: `<domain>_client_live.py`
|
|
341
|
+
- **Implementation classes**: `<Domain>ClientLive`
|
|
342
|
+
- **Private methods**: `_<method_name>`
|
|
343
|
+
- **Helper methods**: `_<verb>_and_log_request` for HTTP helpers
|
|
344
|
+
|
|
345
|
+
## Example: Creating a New Client
|
|
346
|
+
|
|
347
|
+
First: Define the Protocol in `src/dsp_tools/clients/<domain>_client.py`:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from typing import Protocol
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class UserClient(Protocol):
|
|
354
|
+
server: str
|
|
355
|
+
auth: AuthenticationClient
|
|
356
|
+
|
|
357
|
+
def get_user(self, user_iri: str) -> dict[str, Any]:
|
|
358
|
+
"""Get user information by IRI"""
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Second: Implement the live client in `src/dsp_tools/clients/<domain>_client_live.py`:
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
from dataclasses import dataclass
|
|
365
|
+
from http import HTTPStatus
|
|
366
|
+
from typing import Any
|
|
367
|
+
|
|
368
|
+
import requests
|
|
369
|
+
from requests import RequestException
|
|
370
|
+
|
|
371
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
372
|
+
from dsp_tools.clients.user_client import UserClient
|
|
373
|
+
from dsp_tools.error.exceptions import BadCredentialsError, FatalNonOkApiResponseCode
|
|
374
|
+
from dsp_tools.utils.request_utils import (
|
|
375
|
+
RequestParameters,
|
|
376
|
+
log_and_raise_request_exception,
|
|
377
|
+
log_request,
|
|
378
|
+
log_response,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
TIMEOUT = 60
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@dataclass
|
|
385
|
+
class UserClientLive(UserClient):
|
|
386
|
+
server: str
|
|
387
|
+
auth: AuthenticationClient
|
|
388
|
+
|
|
389
|
+
def get_user(self, user_iri: str) -> dict[str, Any]:
|
|
390
|
+
url = f"{self.server}/admin/users/{user_iri}"
|
|
391
|
+
headers = {
|
|
392
|
+
"Authorization": f"Bearer {self.auth.get_token()}",
|
|
393
|
+
}
|
|
394
|
+
params = RequestParameters("GET", url, TIMEOUT, headers=headers)
|
|
395
|
+
log_request(params)
|
|
396
|
+
|
|
397
|
+
try:
|
|
398
|
+
response = requests.get(
|
|
399
|
+
url=params.url,
|
|
400
|
+
headers=params.headers,
|
|
401
|
+
timeout=params.timeout,
|
|
402
|
+
)
|
|
403
|
+
except RequestException as err:
|
|
404
|
+
log_and_raise_request_exception(err)
|
|
405
|
+
|
|
406
|
+
log_response(response)
|
|
407
|
+
|
|
408
|
+
if response.ok:
|
|
409
|
+
return response.json()
|
|
410
|
+
|
|
411
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
412
|
+
raise BadCredentialsError("You don't have permission to access user information.")
|
|
413
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Related Documentation
|
|
417
|
+
|
|
418
|
+
- Request utilities: `src/dsp_tools/utils/request_utils.py`
|
|
419
|
+
- Exception definitions: `src/dsp_tools/error/exceptions.py`
|
|
420
|
+
- Main project documentation: `/CLAUDE.md`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Protocol
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AuthenticationClient(Protocol):
|
|
5
|
+
"""
|
|
6
|
+
Protocol for a client that can authenticate with a DSP server and returns a token.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
server: str
|
|
10
|
+
email: str
|
|
11
|
+
password: str
|
|
12
|
+
|
|
13
|
+
def get_token(self) -> str:
|
|
14
|
+
pass
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
from importlib.metadata import version
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
from requests import RequestException
|
|
9
|
+
|
|
10
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
11
|
+
from dsp_tools.error.exceptions import BadCredentialsError
|
|
12
|
+
from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
|
|
13
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
14
|
+
from dsp_tools.utils.request_utils import log_and_raise_request_exception
|
|
15
|
+
from dsp_tools.utils.request_utils import log_request
|
|
16
|
+
from dsp_tools.utils.request_utils import log_response
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class AuthenticationClientLive(AuthenticationClient):
|
|
21
|
+
"""
|
|
22
|
+
Client that can authenticate with a DSP server and return a token.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
server: str
|
|
26
|
+
email: str
|
|
27
|
+
password: str
|
|
28
|
+
_token: str | None = None
|
|
29
|
+
|
|
30
|
+
def get_token(self) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Returns a token. If no token is available, it will get one from the server.
|
|
33
|
+
"""
|
|
34
|
+
if self._token:
|
|
35
|
+
return self._token
|
|
36
|
+
return self._get_token()
|
|
37
|
+
|
|
38
|
+
def _get_token(self) -> str:
|
|
39
|
+
timeout = 10
|
|
40
|
+
url = f"{self.server}/v2/authentication"
|
|
41
|
+
payload = {"email": self.email, "password": self.password}
|
|
42
|
+
headers = {"User-Agent": f"DSP-TOOLS/{version('dsp-tools')}"}
|
|
43
|
+
request_params = RequestParameters("POST", url, data=payload, timeout=timeout, headers=headers)
|
|
44
|
+
log_request(request_params)
|
|
45
|
+
try:
|
|
46
|
+
response = requests.post(
|
|
47
|
+
request_params.url,
|
|
48
|
+
json=request_params.data,
|
|
49
|
+
headers=request_params.headers,
|
|
50
|
+
timeout=request_params.timeout,
|
|
51
|
+
)
|
|
52
|
+
log_response(response)
|
|
53
|
+
except RequestException as err:
|
|
54
|
+
log_and_raise_request_exception(err)
|
|
55
|
+
|
|
56
|
+
if response.ok:
|
|
57
|
+
res_json: dict[str, Any] = response.json()
|
|
58
|
+
tkn = cast(str, res_json["token"])
|
|
59
|
+
self._token = tkn
|
|
60
|
+
return tkn
|
|
61
|
+
if response.status_code == HTTPStatus.UNAUTHORIZED:
|
|
62
|
+
raise BadCredentialsError(
|
|
63
|
+
f"Login to the API with the email '{self.email}' was not successful. "
|
|
64
|
+
f"Please ensure that an account for this email exists and that the password is correct."
|
|
65
|
+
)
|
|
66
|
+
raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from typing import Protocol
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
from dsp_tools.utils.request_utils import PostFiles
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Connection(Protocol):
|
|
@@ -28,24 +28,8 @@ class Connection(Protocol):
|
|
|
28
28
|
self,
|
|
29
29
|
route: str,
|
|
30
30
|
data: dict[str, Any] | None = None,
|
|
31
|
-
files:
|
|
31
|
+
files: PostFiles | None = None,
|
|
32
32
|
headers: dict[str, str] | None = None,
|
|
33
33
|
timeout: int | None = None,
|
|
34
34
|
) -> dict[str, Any]:
|
|
35
35
|
pass
|
|
36
|
-
|
|
37
|
-
def delete(
|
|
38
|
-
self,
|
|
39
|
-
route: str,
|
|
40
|
-
headers: dict[str, str] | None = None,
|
|
41
|
-
) -> dict[str, Any]:
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
def get_token(self) -> str:
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
def login(self, email: str, password: str) -> None:
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
def logout(self) -> None:
|
|
51
|
-
pass
|