dsp-tools 18.0.0__py3-none-any.whl → 18.0.0.post3__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.

Potentially problematic release.


This version of dsp-tools might be problematic. Click here for more details.

@@ -6,7 +6,6 @@ from dsp_tools.cli.args import PathDependencies
6
6
  from dsp_tools.cli.args import ValidationSeverity
7
7
  from dsp_tools.cli.utils import check_docker_health
8
8
  from dsp_tools.cli.utils import check_input_dependencies
9
- from dsp_tools.cli.utils import check_network_health
10
9
  from dsp_tools.cli.utils import get_creds
11
10
  from dsp_tools.commands.create.lists_only import create_lists_only
12
11
  from dsp_tools.commands.excel2json.old_lists import validate_lists_section_with_schema
@@ -62,14 +61,14 @@ def call_upload_files(args: argparse.Namespace) -> bool:
62
61
 
63
62
 
64
63
  def call_ingest_files(args: argparse.Namespace) -> bool:
65
- check_network_health(NetworkRequirements(api_url=args.server))
64
+ check_input_dependencies(network_dependencies=NetworkRequirements(api_url=args.server))
66
65
  return ingest_files(creds=get_creds(args), shortcode=args.shortcode)
67
66
 
68
67
 
69
68
  def call_ingest_xmlupload(args: argparse.Namespace) -> bool:
70
69
  xml_path = Path(args.xml_file)
71
70
  required_files = [xml_path]
72
- id2iri_file = args.id2iri_replacement_with_file
71
+ id2iri_file = args.id2iri_file
73
72
  if id2iri_file:
74
73
  required_files.append(Path(id2iri_file))
75
74
  network_requirements = NetworkRequirements(args.server, always_requires_docker=True)
@@ -83,7 +82,7 @@ def call_ingest_xmlupload(args: argparse.Namespace) -> bool:
83
82
  interrupt_after=interrupt_after,
84
83
  skip_validation=args.skip_validation,
85
84
  skip_ontology_validation=args.skip_ontology_validation,
86
- id2iri_replacement_file=id2iri_file,
85
+ id2iri_file=id2iri_file,
87
86
  do_not_request_resource_metadata_from_db=args.do_not_request_resource_metadata_from_db,
88
87
  )
89
88
 
@@ -91,7 +90,7 @@ def call_ingest_xmlupload(args: argparse.Namespace) -> bool:
91
90
  def call_xmlupload(args: argparse.Namespace) -> bool:
92
91
  xml_path = Path(args.xmlfile)
93
92
  required_files = [xml_path]
94
- id2iri_file = args.id2iri_replacement_with_file
93
+ id2iri_file = args.id2iri_file
95
94
  if id2iri_file:
96
95
  required_files.append(Path(id2iri_file))
97
96
  network_requirements = NetworkRequirements(args.server, always_requires_docker=True)
@@ -128,7 +127,7 @@ def call_xmlupload(args: argparse.Namespace) -> bool:
128
127
  validation_severity=severity,
129
128
  skip_ontology_validation=args.skip_ontology_validation,
130
129
  do_not_request_resource_metadata_from_db=args.do_not_request_resource_metadata_from_db,
131
- id2iri_replacement_file=id2iri_file,
130
+ id2iri_file=id2iri_file,
132
131
  ),
133
132
  )
134
133
 
@@ -136,7 +135,7 @@ def call_xmlupload(args: argparse.Namespace) -> bool:
136
135
  def call_validate_data(args: argparse.Namespace) -> bool:
137
136
  xml_path = Path(args.xmlfile)
138
137
  required_files = [xml_path]
139
- id2iri_file = args.id2iri_replacement_with_file
138
+ id2iri_file = args.id2iri_file
140
139
  if id2iri_file:
141
140
  required_files.append(Path(id2iri_file))
142
141
  network_requirements = NetworkRequirements(args.server, always_requires_docker=True)
@@ -149,14 +148,14 @@ def call_validate_data(args: argparse.Namespace) -> bool:
149
148
  save_graphs=args.save_graphs,
150
149
  ignore_duplicate_files_warning=args.ignore_duplicate_files_warning,
151
150
  skip_ontology_validation=args.skip_ontology_validation,
152
- id2iri_replacement_file=id2iri_file,
151
+ id2iri_file=id2iri_file,
153
152
  do_not_request_resource_metadata_from_db=args.do_not_request_resource_metadata_from_db,
154
153
  )
155
154
 
156
155
 
157
156
  def call_resume_xmlupload(args: argparse.Namespace) -> bool:
158
157
  # this does not need docker if not on localhost, as does not need to validate
159
- check_network_health(NetworkRequirements(args.server))
158
+ check_input_dependencies(network_dependencies=NetworkRequirements(args.server))
160
159
  return resume_xmlupload(
161
160
  creds=get_creds(args),
162
161
  skip_first_resource=args.skip_first_resource,
@@ -246,7 +246,7 @@ def _add_ingest_xmlupload(
246
246
  ),
247
247
  )
248
248
  subparser.add_argument(
249
- "--id2iri-replacement-with-file",
249
+ "--id2iri-file",
250
250
  help=(
251
251
  "replaces internal IDs of an XML file (links and stand-off links inside richtext) "
252
252
  "by IRIs provided in this mapping file"
@@ -318,7 +318,7 @@ def _add_xmlupload(
318
318
  ),
319
319
  )
320
320
  subparser.add_argument(
321
- "--id2iri-replacement-with-file",
321
+ "--id2iri-file",
322
322
  help=(
323
323
  "replaces internal IDs of an XML file (links and stand-off links inside richtext) "
324
324
  "by IRIs provided in this mapping file"
@@ -354,7 +354,7 @@ def _add_validate_data(
354
354
  "-s", "--server", default=default_dsp_api_url, help="URL of the DSP server where DSP-TOOLS sends the data to"
355
355
  )
356
356
  subparser.add_argument(
357
- "--id2iri-replacement-with-file",
357
+ "--id2iri-file",
358
358
  help=(
359
359
  "replaces internal IDs of an XML file (links and stand-off links inside richtext) "
360
360
  "by IRIs provided in this mapping file"
dsp_tools/cli/utils.py CHANGED
@@ -31,7 +31,7 @@ def check_input_dependencies(
31
31
  if paths:
32
32
  check_path_dependencies(paths)
33
33
  if network_dependencies:
34
- check_network_health(network_dependencies)
34
+ _check_network_health(network_dependencies)
35
35
 
36
36
 
37
37
  def check_path_dependencies(paths: PathDependencies) -> None:
@@ -51,7 +51,7 @@ def _check_directory_exists(dir_path: Path) -> None:
51
51
  raise UserDirectoryNotFoundError(dir_path)
52
52
 
53
53
 
54
- def check_network_health(network_requirements: NetworkRequirements) -> None:
54
+ def _check_network_health(network_requirements: NetworkRequirements) -> None:
55
55
  if network_requirements.api_url == LOCALHOST_API or network_requirements.always_requires_docker:
56
56
  check_docker_health()
57
57
  _check_api_health(network_requirements.api_url)
@@ -5,7 +5,6 @@ from typing import cast
5
5
  from urllib.parse import quote_plus
6
6
 
7
7
  import requests
8
- from loguru import logger
9
8
  from requests import RequestException
10
9
  from requests import Response
11
10
 
@@ -15,8 +14,10 @@ from dsp_tools.clients.list_client import ListGetClient
15
14
  from dsp_tools.clients.list_client import OneList
16
15
  from dsp_tools.clients.list_client import OneNode
17
16
  from dsp_tools.error.exceptions import BadCredentialsError
18
- from dsp_tools.error.exceptions import InternalError
17
+ from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
19
18
  from dsp_tools.utils.request_utils import RequestParameters
19
+ from dsp_tools.utils.request_utils import log_and_raise_request_exception
20
+ from dsp_tools.utils.request_utils import log_and_warn_unexpected_non_ok_response
20
21
  from dsp_tools.utils.request_utils import log_request
21
22
  from dsp_tools.utils.request_utils import log_response
22
23
 
@@ -46,12 +47,16 @@ class ListGetClientLive(ListGetClient):
46
47
  url = f"{self.api_url}/admin/lists?projectShortcode={self.shortcode}"
47
48
  timeout = 10
48
49
  log_request(RequestParameters("GET", url, timeout))
49
- response = requests.get(url=url, timeout=timeout)
50
+ try:
51
+ response = requests.get(url=url, timeout=timeout)
52
+ except RequestException as err:
53
+ log_and_raise_request_exception(err)
54
+
50
55
  log_response(response)
51
- if not response.ok:
52
- raise InternalError(f"Failed Request: {response.status_code} {response.text}")
53
- json_response = cast(dict[str, Any], response.json())
54
- return json_response
56
+ if response.ok:
57
+ json_response = cast(dict[str, Any], response.json())
58
+ return json_response
59
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
55
60
 
56
61
  def _extract_list_iris(self, response_json: dict[str, Any]) -> list[str]:
57
62
  return [x["id"] for x in response_json["lists"]]
@@ -61,12 +66,16 @@ class ListGetClientLive(ListGetClient):
61
66
  url = f"{self.api_url}/admin/lists/{encoded_list_iri}"
62
67
  timeout = 30
63
68
  log_request(RequestParameters("GET", url, timeout))
64
- response = requests.get(url=url, timeout=timeout)
69
+ try:
70
+ response = requests.get(url=url, timeout=timeout)
71
+ except RequestException as err:
72
+ log_and_raise_request_exception(err)
73
+
65
74
  log_response(response, include_response_content=False)
66
- if not response.ok:
67
- raise InternalError(f"Failed Request: {response.status_code} {response.text}")
68
- response_json = cast(dict[str, Any], response.json())
69
- return response_json
75
+ if response.ok:
76
+ response_json = cast(dict[str, Any], response.json())
77
+ return response_json
78
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
70
79
 
71
80
  def _reformat_one_list(self, response_json: dict[str, Any]) -> OneList:
72
81
  list_name = response_json["list"]["listinfo"]["name"]
@@ -94,12 +103,12 @@ class ListCreateClientLive(ListCreateClient):
94
103
 
95
104
  def create_new_list(self, list_info: dict[str, Any]) -> str | None:
96
105
  url = f"{self.api_url}/admin/lists"
106
+ headers = self._get_request_header()
97
107
  try:
98
- headers = self._get_request_header()
99
108
  response = _post_and_log_request(url, list_info, headers)
100
109
  except RequestException as err:
101
- logger.exception(err)
102
- return None
110
+ log_and_raise_request_exception(err)
111
+
103
112
  if response.ok:
104
113
  result = response.json()
105
114
  list_iri = cast(str, result["list"]["listinfo"]["id"])
@@ -109,18 +118,18 @@ class ListCreateClientLive(ListCreateClient):
109
118
  "Only a project or system administrator can create lists. "
110
119
  "Your permissions are insufficient for this action."
111
120
  )
112
- logger.exception(f"Failed to create list: '{list_info['name']}'")
121
+ log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
113
122
  return None
114
123
 
115
124
  def add_list_node(self, node_info: dict[str, Any], parent_iri: str) -> str | None:
116
125
  encoded_parent_iri = quote_plus(parent_iri)
117
126
  url = f"{self.api_url}/admin/lists/{encoded_parent_iri}"
127
+ headers = self._get_request_header()
118
128
  try:
119
- headers = self._get_request_header()
120
129
  response = _post_and_log_request(url, node_info, headers)
121
130
  except RequestException as err:
122
- logger.error(err)
123
- return None
131
+ log_and_raise_request_exception(err)
132
+
124
133
  if response.ok:
125
134
  result = response.json()
126
135
  node_iri = cast(str, result["nodeinfo"]["id"])
@@ -130,7 +139,7 @@ class ListCreateClientLive(ListCreateClient):
130
139
  "Only a project or system administrator can add nodes to lists. "
131
140
  "Your permissions are insufficient for this action."
132
141
  )
133
- logger.error(f"Failed to add node: '{node_info['name']}'")
142
+ log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
134
143
  return None
135
144
 
136
145
  def _get_request_header(self) -> dict[str, str]:
@@ -1,22 +1,24 @@
1
1
  from dataclasses import dataclass
2
2
  from http import HTTPStatus
3
3
  from typing import Any
4
+ from typing import cast
4
5
 
5
6
  import requests
6
7
  from loguru import logger
7
8
  from rdflib import Graph
8
9
  from rdflib import Literal
9
10
  from rdflib import URIRef
10
- from requests import ReadTimeout
11
+ from requests import RequestException
11
12
  from requests import Response
12
13
 
13
14
  from dsp_tools.clients.authentication_client import AuthenticationClient
14
15
  from dsp_tools.clients.ontology_clients import OntologyCreateClient
15
16
  from dsp_tools.error.exceptions import BadCredentialsError
16
- from dsp_tools.error.exceptions import UnexpectedApiResponseError
17
+ from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
17
18
  from dsp_tools.utils.rdflib_constants import KNORA_API
18
19
  from dsp_tools.utils.request_utils import RequestParameters
19
- from dsp_tools.utils.request_utils import log_and_raise_timeouts
20
+ from dsp_tools.utils.request_utils import log_and_raise_request_exception
21
+ from dsp_tools.utils.request_utils import log_and_warn_unexpected_non_ok_response
20
22
  from dsp_tools.utils.request_utils import log_request
21
23
  from dsp_tools.utils.request_utils import log_response
22
24
 
@@ -38,23 +40,12 @@ class OntologyCreateClientLive(OntologyCreateClient):
38
40
  logger.debug("GET ontology metadata")
39
41
  try:
40
42
  response = self._get_and_log_request(url, header)
41
- except (TimeoutError, ReadTimeout) as err:
42
- log_and_raise_timeouts(err)
43
+ except RequestException as err:
44
+ log_and_raise_request_exception(err)
45
+
43
46
  if response.ok:
44
- date = _parse_last_modification_date(response.text, URIRef(onto_iri))
45
- if not date:
46
- raise UnexpectedApiResponseError(
47
- f"Could not find the last modification date of the ontology '{onto_iri}' "
48
- f"in the response: {response.text}"
49
- )
50
- return date
51
- if response.status_code == HTTPStatus.FORBIDDEN:
52
- raise BadCredentialsError("You do not have sufficient credentials to retrieve ontology metadata.")
53
- else:
54
- raise UnexpectedApiResponseError(
55
- f"An unexpected response with the status code {response.status_code} was received from the API. "
56
- f"Please consult 'warnings.log' for details."
57
- )
47
+ return _parse_last_modification_date(response.text, URIRef(onto_iri))
48
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
58
49
 
59
50
  def post_resource_cardinalities(self, cardinality_graph: dict[str, Any]) -> Literal | None:
60
51
  url = f"{self.server}/v2/ontologies/cardinalities"
@@ -62,26 +53,18 @@ class OntologyCreateClientLive(OntologyCreateClient):
62
53
  logger.debug("POST resource cardinalities to ontology")
63
54
  try:
64
55
  response = self._post_and_log_request(url, cardinality_graph)
65
- except (TimeoutError, ReadTimeout) as err:
66
- log_and_raise_timeouts(err)
56
+ except RequestException as err:
57
+ log_and_raise_request_exception(err)
58
+
67
59
  if response.ok:
68
- date = _parse_last_modification_date(response.text)
69
- if not date:
70
- raise UnexpectedApiResponseError(
71
- f"Could not find the last modification date in the response: {response.text}"
72
- )
73
- return date
60
+ return _parse_last_modification_date(response.text)
74
61
  if response.status_code == HTTPStatus.FORBIDDEN:
75
62
  raise BadCredentialsError(
76
63
  "Only a project or system administrator can add cardinalities to resource classes. "
77
64
  "Your permissions are insufficient for this action."
78
65
  )
79
- else:
80
- logger.error(
81
- f"During cardinality creation an unexpected response with the status code {response.status_code} "
82
- f"was received from the API."
83
- )
84
- return None
66
+ log_and_warn_unexpected_non_ok_response(response.status_code, response.text)
67
+ return None
85
68
 
86
69
  def _post_and_log_request(
87
70
  self,
@@ -130,10 +113,8 @@ class OntologyCreateClientLive(OntologyCreateClient):
130
113
  return data_dict, generic_headers
131
114
 
132
115
 
133
- def _parse_last_modification_date(response_text: str, onto_iri: URIRef | None = None) -> Literal | None:
116
+ def _parse_last_modification_date(response_text: str, onto_iri: URIRef | None = None) -> Literal:
134
117
  g = Graph()
135
118
  g.parse(data=response_text, format="json-ld")
136
- result = next(g.objects(subject=onto_iri, predicate=KNORA_API.lastModificationDate), None)
137
- if isinstance(result, Literal):
138
- return result
139
- return None
119
+ date = next(g.objects(subject=onto_iri, predicate=KNORA_API.lastModificationDate))
120
+ return cast(Literal, date)
@@ -5,6 +5,7 @@ from typing import cast
5
5
  import requests
6
6
 
7
7
  from dsp_tools.clients.ontology_clients import OntologyGetClient
8
+ from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
8
9
  from dsp_tools.error.exceptions import InternalError
9
10
  from dsp_tools.utils.request_utils import RequestParameters
10
11
  from dsp_tools.utils.request_utils import log_request
@@ -23,9 +24,9 @@ class OntologyGetClientLive(OntologyGetClient):
23
24
  log_request(RequestParameters("GET", url, timeout=timeout, headers=headers))
24
25
  response = requests.get(url=url, headers=headers, timeout=timeout)
25
26
  log_response(response, include_response_content=False)
26
- if not response.ok:
27
- raise InternalError(f"Failed Request: {response.status_code} {response.text}")
28
- return response.text
27
+ if response.ok:
28
+ return response.text
29
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
29
30
 
30
31
  def get_ontologies(self) -> tuple[list[str], list[str]]:
31
32
  """
@@ -49,7 +50,7 @@ class OntologyGetClientLive(OntologyGetClient):
49
50
  raise InternalError(f"Failed Request: {response.status_code} {response.text}")
50
51
  response_json = cast(dict[str, Any], response.json())
51
52
  if not (ontos := response_json.get("project", {}).get("ontologies")):
52
- raise InternalError(f"The response from the API does not contain any ontologies.\nResponse:{response.text}")
53
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
53
54
  output = cast(list[str], ontos)
54
55
  return output
55
56
 
@@ -60,6 +61,6 @@ class OntologyGetClientLive(OntologyGetClient):
60
61
  log_request(RequestParameters("GET", url, timeout=timeout, headers=headers))
61
62
  response = requests.get(url=url, headers=headers, timeout=timeout)
62
63
  log_response(response, include_response_content=False)
63
- if not response.ok:
64
- raise InternalError(f"Failed Request: {response.status_code} {response.text}")
65
- return response.text
64
+ if response.ok:
65
+ return response.text
66
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
@@ -3,10 +3,12 @@ from http import HTTPStatus
3
3
  from typing import cast
4
4
 
5
5
  import requests
6
+ from requests import RequestException
6
7
 
7
8
  from dsp_tools.clients.project_client import ProjectInfoClient
8
- from dsp_tools.error.exceptions import UnexpectedApiResponseError
9
+ from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
9
10
  from dsp_tools.utils.request_utils import RequestParameters
11
+ from dsp_tools.utils.request_utils import log_and_raise_request_exception
10
12
  from dsp_tools.utils.request_utils import log_request
11
13
  from dsp_tools.utils.request_utils import log_response
12
14
 
@@ -20,11 +22,15 @@ class ProjectInfoClientLive(ProjectInfoClient):
20
22
  timeout = 30
21
23
  params = RequestParameters("GET", url, timeout)
22
24
  log_request(params)
23
- response = requests.get(url, timeout=timeout)
25
+ try:
26
+ response = requests.get(url, timeout=timeout)
27
+ except RequestException as err:
28
+ log_and_raise_request_exception(err)
29
+
24
30
  log_response(response)
25
31
  if response.ok:
26
32
  result = response.json()
27
33
  return cast(str, result["project"]["id"])
28
34
  if response.status_code == HTTPStatus.NOT_FOUND:
29
35
  return None
30
- raise UnexpectedApiResponseError(f"Encountered unexpected API response with the code {response.status_code}")
36
+ raise FatalNonOkApiResponseCode(url, response.status_code, response.text)
@@ -1,3 +1,4 @@
1
+ import warnings
1
2
  from typing import Any
2
3
 
3
4
  from loguru import logger
@@ -17,6 +18,8 @@ from dsp_tools.commands.create.models.parsed_project import ParsedList
17
18
  from dsp_tools.commands.create.models.parsed_project import ParsedListNode
18
19
  from dsp_tools.commands.create.models.parsed_project import ParsedNodeInfo
19
20
  from dsp_tools.commands.create.models.server_project_info import ListNameToIriLookup
21
+ from dsp_tools.error.custom_warnings import DspToolsUnexpectedStatusCodeWarning
22
+ from dsp_tools.error.exceptions import FatalNonOkApiResponseCode
20
23
  from dsp_tools.utils.ansi_colors import BOLD
21
24
  from dsp_tools.utils.ansi_colors import BOLD_CYAN
22
25
  from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
@@ -64,8 +67,18 @@ def _print_existing_list_info(existing_lists: list[UserInformation]) -> None:
64
67
 
65
68
  def get_existing_lists_on_server(shortcode: str, auth: AuthenticationClient) -> ListNameToIriLookup:
66
69
  client = ListGetClientLive(auth.server, shortcode)
67
- name2iri_dict = client.get_all_list_iris_and_names()
68
- return ListNameToIriLookup(name2iri_dict)
70
+ try:
71
+ name2iri_dict = client.get_all_list_iris_and_names()
72
+ return ListNameToIriLookup(name2iri_dict)
73
+ except FatalNonOkApiResponseCode as e:
74
+ logger.exception(e)
75
+ warnings.warn(
76
+ DspToolsUnexpectedStatusCodeWarning(
77
+ "Could not retrieve existing lists on server. "
78
+ "We will not be able to create any properties that require a list that is not defined in the JSON."
79
+ )
80
+ )
81
+ return ListNameToIriLookup({})
69
82
 
70
83
 
71
84
  def _filter_out_existing_lists(
@@ -42,7 +42,7 @@ def ingest_xmlupload(
42
42
  interrupt_after: int | None = None,
43
43
  skip_validation: bool = False,
44
44
  skip_ontology_validation: bool = False,
45
- id2iri_replacement_file: str | None = None,
45
+ id2iri_file: str | None = None,
46
46
  do_not_request_resource_metadata_from_db: bool = False,
47
47
  ) -> bool:
48
48
  """
@@ -59,7 +59,7 @@ def ingest_xmlupload(
59
59
  interrupt_after: if set, the upload will be interrupted after this number of resources
60
60
  skip_validation: skip the SHACL validation
61
61
  skip_ontology_validation: skip the ontology validation
62
- id2iri_replacement_file: to replace internal IDs of an XML file by IRIs provided in this mapping file
62
+ id2iri_file: to replace internal IDs of an XML file by IRIs provided in this mapping file
63
63
  do_not_request_resource_metadata_from_db: if true do not request metadata information from the api
64
64
  for existing resources
65
65
 
@@ -86,8 +86,8 @@ def ingest_xmlupload(
86
86
  clients = _get_live_clients(con, config, auth)
87
87
 
88
88
  parsed_resources, lookups = get_parsed_resources_and_mappers(root, clients)
89
- if id2iri_replacement_file:
90
- parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(id2iri_replacement_file))
89
+ if id2iri_file:
90
+ parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(id2iri_file))
91
91
 
92
92
  validation_should_be_skipped = skip_validation
93
93
  is_on_prod_like_server = is_prod_like_server(creds.server)
@@ -30,15 +30,15 @@ from dsp_tools.utils.xml_parsing.parse_clean_validate_xml import parse_and_clean
30
30
 
31
31
 
32
32
  def get_info_and_parsed_resources_from_file(
33
- file: Path, api_url: str, id2iri_replacement_file: str | None
33
+ file: Path, api_url: str, id2iri_file: str | None
34
34
  ) -> tuple[list[ParsedResource], str, dict[str, list[str]], list[str]]:
35
35
  root = parse_and_clean_xml_file(file)
36
36
  shortcode = root.attrib["shortcode"]
37
37
  authorship_lookup = get_authorship_lookup(root)
38
38
  permission_ids = [perm.attrib["id"] for perm in root.findall("permissions")]
39
39
  parsed_resources = get_parsed_resources(root, api_url)
40
- if id2iri_replacement_file:
41
- parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(id2iri_replacement_file))
40
+ if id2iri_file:
41
+ parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(id2iri_file))
42
42
  return parsed_resources, shortcode, authorship_lookup, permission_ids
43
43
 
44
44
 
@@ -9,6 +9,7 @@ from rdflib import Graph
9
9
 
10
10
  from dsp_tools.commands.validate_data.models.api_responses import SHACLValidationReport
11
11
  from dsp_tools.commands.validate_data.models.validation import ValidationFilePaths
12
+ from dsp_tools.config.logger_config import LOGGER_SAVEPATH
12
13
  from dsp_tools.error.exceptions import InternalError
13
14
  from dsp_tools.error.exceptions import ShaclValidationCliError
14
15
 
@@ -21,7 +22,8 @@ class ShaclCliValidator:
21
22
  logger.error(e)
22
23
  msg = (
23
24
  "Data validation requires Docker. Is your Docker Desktop Application open? "
24
- "If it is, please contact the DSP-TOOLS development team with your log file."
25
+ "If it is, please contact the DSP-TOOLS development team (at info@dasch.swiss) "
26
+ f"with the log file at {LOGGER_SAVEPATH}."
25
27
  )
26
28
  logger.error(msg)
27
29
  raise ShaclValidationCliError(msg) from None
@@ -51,7 +51,7 @@ def validate_data(
51
51
  ignore_duplicate_files_warning: bool,
52
52
  save_graphs: bool,
53
53
  skip_ontology_validation: bool,
54
- id2iri_replacement_file: str | None,
54
+ id2iri_file: str | None,
55
55
  do_not_request_resource_metadata_from_db: bool,
56
56
  ) -> bool:
57
57
  """
@@ -63,7 +63,7 @@ def validate_data(
63
63
  ignore_duplicate_files_warning: ignore the shape that checks for duplicate files
64
64
  save_graphs: if this flag is set, all the graphs will be saved in a folder
65
65
  skip_ontology_validation: skip the ontology validation
66
- id2iri_replacement_file: to replace internal IDs of an XML file by IRIs provided in this mapping file
66
+ id2iri_file: to replace internal IDs of an XML file by IRIs provided in this mapping file
67
67
  do_not_request_resource_metadata_from_db: true if no metadata for existing resources should be requested
68
68
 
69
69
  Returns:
@@ -88,7 +88,7 @@ def validate_data(
88
88
  parsed_resources, shortcode, authorship_lookup, permission_ids = get_info_and_parsed_resources_from_file(
89
89
  file=filepath,
90
90
  api_url=auth.server,
91
- id2iri_replacement_file=id2iri_replacement_file,
91
+ id2iri_file=id2iri_file,
92
92
  )
93
93
  return validate_parsed_resources(
94
94
  parsed_resources=parsed_resources,
@@ -32,7 +32,7 @@ def get_validation_report(
32
32
  dir_to_save_graphs = tmp_path.parent / "validation-graphs"
33
33
  msg = (
34
34
  f"An error occurred during the data validation. "
35
- f"Please contact the dsp-tools development team "
35
+ f"Please contact the dsp-tools development team (at info@dasch.swiss) "
36
36
  f"with your log files and the files in the directory: {dir_to_save_graphs}"
37
37
  )
38
38
  raise ShaclValidationError(msg) from None
@@ -52,7 +52,7 @@ def validate_ontology(
52
52
  save_graph_dir = tmp_path.parent / "validation-graphs"
53
53
  msg = (
54
54
  f"An error occurred during the ontology validation. "
55
- f"Please contact the dsp-tools development team "
55
+ f"Please contact the dsp-tools development team (at info@dasch.swiss) "
56
56
  f"with your log files and the files in the directory: {save_graph_dir}"
57
57
  )
58
58
  raise ShaclValidationError(msg) from None
@@ -54,5 +54,5 @@ class IIIFUriProblem:
54
54
  def _good_status_code_bad_regex_msg(self) -> list[str]:
55
55
  return [
56
56
  "Although the IIIF-server responded as expected, this URI did not pass validation.",
57
- "Please contact the dsp-tools development team with this information.",
57
+ "Please contact the dsp-tools development team (at info@dasch.swiss) with this information.",
58
58
  ]
@@ -55,7 +55,7 @@ class UploadConfig:
55
55
  skip_ontology_validation: bool = False
56
56
  ignore_duplicate_files_warning: bool = False
57
57
  validation_severity: ValidationSeverity = field(default_factory=lambda: ValidationSeverity.INFO)
58
- id2iri_replacement_file: str | None = None
58
+ id2iri_file: str | None = None
59
59
  do_not_request_resource_metadata_from_db: bool = False
60
60
 
61
61
  def with_server_info(
@@ -94,8 +94,8 @@ def xmlupload(
94
94
  clients = _get_live_clients(con, auth, creds, shortcode, imgdir)
95
95
 
96
96
  parsed_resources, lookups = get_parsed_resources_and_mappers(root, clients)
97
- if config.id2iri_replacement_file:
98
- parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(config.id2iri_replacement_file))
97
+ if config.id2iri_file:
98
+ parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(config.id2iri_file))
99
99
 
100
100
  is_on_prod_like_server = is_prod_like_server(creds.server)
101
101
 
@@ -30,3 +30,10 @@ class DspToolsFutureWarning(DspToolsWarning, FutureWarning):
30
30
  def showwarning(cls, message: str) -> None:
31
31
  """Print the warning, without context"""
32
32
  print(BOLD_RED + f"DEPRECATION WARNING: {message}" + RESET_TO_DEFAULT)
33
+
34
+
35
+ class DspToolsUnexpectedStatusCodeWarning(DspToolsWarning):
36
+ @classmethod
37
+ def showwarning(cls, message: str) -> None:
38
+ """Print the warning, without context"""
39
+ print(BOLD_RED + f"ERROR: {message}" + RESET_TO_DEFAULT)
@@ -29,7 +29,7 @@ class InternalError(BaseError):
29
29
  def __init__(self, custom_msg: str | None = None, keep_default_msg: bool = True) -> None:
30
30
  default_msg = (
31
31
  f"\n\n{BOLD_RED}An internal error occurred.{RESET_TO_DEFAULT}\n"
32
- "Please contact the dsp-tools development team with the following information:\n"
32
+ "Please contact the dsp-tools development team (at info@dasch.swiss) with the following information:\n"
33
33
  " - Which command was used.\n"
34
34
  " - If applicable, any files that were used in conjunction with the command.\n"
35
35
  " - A text file with the terminal output copied into.\n"
@@ -57,6 +57,10 @@ class DspApiNotReachableError(BaseError):
57
57
  """This error is raised when the DSP-API could not be reached on localhost."""
58
58
 
59
59
 
60
+ class DspToolsRequestException(BaseError):
61
+ """Class for errors that are raised if any request exceptions happens."""
62
+
63
+
60
64
  class InputError(BaseError):
61
65
  """This error is raised when the user input is invalid. The message should be as user-friendly as possible."""
62
66
 
@@ -65,9 +69,20 @@ class InvalidGuiAttributeError(BaseError):
65
69
  """This error is raised when a invalid gui-attribute is used."""
66
70
 
67
71
 
68
- class UnexpectedApiResponseError(BaseError):
72
+ class FatalNonOkApiResponseCode(BaseError):
69
73
  """This error is raised when the API gives an unexpected response, that we cannot anticipate and handle cleanly."""
70
74
 
75
+ def __init__(self, request_url: str, status_code: int, response_text: str) -> None:
76
+ resp_txt = response_text[:200] if len(response_text) > 200 else response_text
77
+ msg = (
78
+ f"We currently do not support the following API response code for this request.\n"
79
+ f"Status code: {status_code}\n"
80
+ f"Request URL: {request_url}\n"
81
+ f"Original Response: {resp_txt}\n"
82
+ f"Please contact info@dasch.swiss with the log file at {LOGGER_SAVEPATH}."
83
+ )
84
+ super().__init__(msg)
85
+
71
86
 
72
87
  class UserFilepathNotFoundError(InputError):
73
88
  """This error is raised if a filepath from the user does not exist."""
@@ -4,6 +4,7 @@ from loguru import logger
4
4
 
5
5
  from dsp_tools.clients.fuseki_metrics import FusekiBloatingLevel
6
6
  from dsp_tools.clients.fuseki_metrics import FusekiMetrics
7
+ from dsp_tools.config.logger_config import LOGGER_SAVEPATH
7
8
  from dsp_tools.utils.ansi_colors import BACKGROUND_BOLD_RED
8
9
  from dsp_tools.utils.ansi_colors import BOLD_YELLOW
9
10
  from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
@@ -23,7 +24,7 @@ def communicate_fuseki_bloating(fuseki_metrics: FusekiMetrics) -> None:
23
24
  msg = (
24
25
  f"The xmlupload caused the database to use {rounded} GB disk space. "
25
26
  f"Please check that your test server has enough disk space for an upload. "
26
- f"If you have any questions contact the dsp-tools developers."
27
+ f"If you have any questions contact the dsp-tools developers at info@dasch.swiss."
27
28
  )
28
29
  match bloating_level:
29
30
  case FusekiBloatingLevel.OK:
@@ -37,7 +38,8 @@ def communicate_fuseki_bloating(fuseki_metrics: FusekiMetrics) -> None:
37
38
  case FusekiBloatingLevel.CALCULATION_FAILURE:
38
39
  msg = (
39
40
  "The database bloating size could not be calculated. "
40
- "Please contact the dsp-tools developers with your logs."
41
+ f"Please contact the dsp-tools developers (at info@dasch.swiss) "
42
+ f"with your logs saved at {LOGGER_SAVEPATH}."
41
43
  )
42
44
  print(f"{BACKGROUND_BOLD_RED}{msg}{RESET_TO_DEFAULT}")
43
45
  logger.error(msg)
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  import os
5
5
  import time
6
+ import warnings
6
7
  from dataclasses import dataclass
7
8
  from dataclasses import field
8
9
  from datetime import datetime
@@ -14,10 +15,14 @@ from typing import Union
14
15
  from loguru import logger
15
16
  from requests import JSONDecodeError
16
17
  from requests import ReadTimeout
18
+ from requests import RequestException
17
19
  from requests import Response
18
20
 
19
21
  from dsp_tools.commands.project.legacy_models.context import Context
20
22
  from dsp_tools.commands.project.legacy_models.helpers import OntoIri
23
+ from dsp_tools.config.logger_config import LOGGER_SAVEPATH
24
+ from dsp_tools.error.custom_warnings import DspToolsUnexpectedStatusCodeWarning
25
+ from dsp_tools.error.exceptions import DspToolsRequestException
21
26
  from dsp_tools.error.exceptions import PermanentTimeOutError
22
27
 
23
28
 
@@ -192,3 +197,29 @@ def should_retry(response: Response) -> bool:
192
197
  try_again_later = "try again later" in response.text.lower()
193
198
  in_testing_env = os.getenv("DSP_TOOLS_TESTING") == "true" # set in .github/workflows/tests-on-push.yml
194
199
  return (try_again_later or in_500_range) and not in_testing_env
200
+
201
+
202
+ def log_and_raise_request_exception(error: RequestException) -> Never:
203
+ msg = (
204
+ f"During an API call the following exception occurred. "
205
+ f"Please contact info@dasch.swiss with the log file at {LOGGER_SAVEPATH} "
206
+ f"if you required help resolving the issue.\n"
207
+ f"Original exception name: {error.__class__.__name__}\n"
208
+ )
209
+ if error.request:
210
+ msg += f"Original request: {error.request.method} {error.request.url}"
211
+ logger.exception(msg)
212
+ raise DspToolsRequestException(msg) from None
213
+
214
+
215
+ def log_and_warn_unexpected_non_ok_response(status_code: int, response_text: str) -> None:
216
+ resp_txt = response_text[:200] if len(response_text) > 200 else response_text
217
+ msg = (
218
+ "We got an unexpected API response during the following request. "
219
+ "Please contact the dsp-tools development team (at info@dasch.swiss) with your log file "
220
+ "so that we can handle this more gracefully in the future.\n"
221
+ f"Response status code: {status_code}\n"
222
+ f"Original Message: {resp_txt}"
223
+ )
224
+ logger.warning(msg)
225
+ warnings.warn(DspToolsUnexpectedStatusCodeWarning(msg))
@@ -91,10 +91,12 @@ class Resource:
91
91
  ```
92
92
  """
93
93
  if not is_valid_resource_id(res_id):
94
+ res_id = str(res_id)
94
95
  emit_xmllib_input_type_mismatch_warning(
95
96
  expected_type="xsd:ID", value=res_id, res_id=res_id, value_field="resource ID"
96
97
  )
97
98
  if not is_nonempty_value(restype):
99
+ restype = str(restype)
98
100
  emit_xmllib_input_type_mismatch_warning(
99
101
  expected_type="resource type", value=restype, res_id=res_id, value_field="restype"
100
102
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dsp-tools
3
- Version: 18.0.0
3
+ Version: 18.0.0.post3
4
4
  Summary: DSP-TOOLS is a Python package with a command line interface that helps you interact with a DaSCH service platform (DSP) server.
5
5
  Author: DaSCH - Swiss National Data and Service Center for the Humanities
6
6
  Author-email: DaSCH - Swiss National Data and Service Center for the Humanities <info@dasch.swiss>
@@ -3,10 +3,10 @@ dsp_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  dsp_tools/cli/args.py,sha256=qUoEQVULA3eaCkI1xSdEhEcM26rku0lejnjSnKoevGU,1038
4
4
  dsp_tools/cli/call_action.py,sha256=l6pmY1SckKMkh-Y0DW1Aij2IR_D91uoe078fsruXkIQ,3275
5
5
  dsp_tools/cli/call_action_files_only.py,sha256=T0A51uN4pClcLaDv_eREZMwEshAIlHMyEDPOOqZIOKg,2630
6
- dsp_tools/cli/call_action_with_network.py,sha256=nEP60rXWZy_z4tkz5ed6DDOEkHMkXVuyheeNZQogjFs,8556
7
- dsp_tools/cli/create_parsers.py,sha256=UgHp3_3siQoLe1GdFTLn2ya8Vjumf-NibT0Rd58UxuY,19567
6
+ dsp_tools/cli/call_action_with_network.py,sha256=JEMRWL13hvzJyFZ3NIHefMP8GnmTsdgHwgWaS2I9vAw,8466
7
+ dsp_tools/cli/create_parsers.py,sha256=cYvXlVRVeqVRzAydsZ8_OUbRErjD_mz6irxFAVmhFqU,19516
8
8
  dsp_tools/cli/entry_point.py,sha256=gdexHqVDAy8_Atf0oUxvPVQyDGWUSUhio396U5Oc0RI,10331
9
- dsp_tools/cli/utils.py,sha256=57Bmv33A61YHcWDDm2zGOsjEuB_bV6p9FYIdN_42UBs,3072
9
+ dsp_tools/cli/utils.py,sha256=Y3Sq1QlMJw7NvQ3CEB-55LQi-ht3tlsNcRjTISbEQO4,3074
10
10
  dsp_tools/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  dsp_tools/clients/authentication_client.py,sha256=A9nTlOdUE4Ez0psWX6qXwuypNBAA2eSVfHIEPzRmoCs,267
12
12
  dsp_tools/clients/authentication_client_live.py,sha256=Bnc6-M2r_D8BNoZgKi5Rzc2vrz5RtRhwUNjJF3PrVTQ,1917
@@ -16,21 +16,21 @@ dsp_tools/clients/fuseki_metrics.py,sha256=Vy_aWOusnzlD0EnbyHZcTtPIpMEfRA_ihtYby
16
16
  dsp_tools/clients/legal_info_client.py,sha256=itDvGQf1VV1WiH2oHVcH1epSUSdJPRDwdRUvmCw8P4s,742
17
17
  dsp_tools/clients/legal_info_client_live.py,sha256=9nOe8Y-oQRHh4TkD2-tjdxLNNTonQ0i-P6UjCGgIBGA,5987
18
18
  dsp_tools/clients/list_client.py,sha256=L1CcbUcmzwkJVKbrbXa7EB2myJ-sCchjZywwuPh2uS8,1118
19
- dsp_tools/clients/list_client_live.py,sha256=yoznKeBus0gAIERUIjZAbEqGU1CA4AzRRLO48JkrBMU,6198
19
+ dsp_tools/clients/list_client_live.py,sha256=QFDlZtGEvYu4bmaDIJVFkyWDG9pnJmIfz4GTMElxBqg,6553
20
20
  dsp_tools/clients/metadata_client.py,sha256=GD4uYXP3kEym59JAqSub61xXDZSmZaQ2lKRF1_MgYS0,623
21
21
  dsp_tools/clients/metadata_client_live.py,sha256=SLq2Ssob3TQaTx6PUblD-DeTimSLA4Y6woo6246Fca8,1863
22
22
  dsp_tools/clients/ontology_clients.py,sha256=juigGsfZ1uP42gtyEstDzaMfjeKcriS34mgYaFbJW-Y,989
23
- dsp_tools/clients/ontology_create_client_live.py,sha256=LOz3k2_ZiShEcdarhoscLFjsdMHG85mHGsbRuR7cq7Y,5386
24
- dsp_tools/clients/ontology_get_client_live.py,sha256=MeTqWVqTBW22wEebulv3R8fDsjvW2_dd-cs0Wqllxe8,2698
23
+ dsp_tools/clients/ontology_create_client_live.py,sha256=zv32RRWanbIrLnb6kJ4s4vqgAD2ipc4xo_yOXTyZy3o,4492
24
+ dsp_tools/clients/ontology_get_client_live.py,sha256=bq8g0nID9ChCmH5_enxOTLML5IikFEMhJq-kqk5cyaM,2710
25
25
  dsp_tools/clients/project_client.py,sha256=1nsp-RLRTqD1ePk824R4XKbAKCWMYwiGR9uzA-0qRqg,243
26
- dsp_tools/clients/project_client_live.py,sha256=NTnw_DG37YKfAouDExccwt79QHFsT66oPyrY3MXtVSY,1115
26
+ dsp_tools/clients/project_client_live.py,sha256=rymSE8gYrDXErM5k5UExFjABfmtN5f6Pr5Eye5kJdrE,1297
27
27
  dsp_tools/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  dsp_tools/commands/create/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  dsp_tools/commands/create/communicate_problems.py,sha256=GdAOiUZevrYFhRINyDMhcbXdUqtGDKb2nEelhdfSFR0,885
30
30
  dsp_tools/commands/create/constants.py,sha256=ZzWNn_zh-0Oy0SJmGivQbcAnQTmwT0akNchZUppXgh0,276
31
31
  dsp_tools/commands/create/create_on_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  dsp_tools/commands/create/create_on_server/cardinalities.py,sha256=bp-3NokfyhpE5ddKTkib9imFpZiMyRKcN-pHK_DHyfo,5518
33
- dsp_tools/commands/create/create_on_server/lists.py,sha256=y_63BBpALfJKJ-wQfsgINEuevFnRolD07ZWt0Q4yFfA,6195
33
+ dsp_tools/commands/create/create_on_server/lists.py,sha256=P4CsHHrbRMkfz66rRWbG6_MEIhm0kt8Pnou3mcGtdJ0,6759
34
34
  dsp_tools/commands/create/create_on_server/mappers.py,sha256=Lu2DJAICOZu7WP_1UDvyvRAi0T9ZGO88kvx0UfI6v5I,564
35
35
  dsp_tools/commands/create/lists_only.py,sha256=pSgl0XykdguR9445QIAvDTTRbsBuicIxgjD-zFQQzD0,2079
36
36
  dsp_tools/commands/create/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -76,7 +76,7 @@ dsp_tools/commands/ingest_xmlupload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
76
76
  dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py,sha256=i53VPo5bRf6FkGzEuQuZJIzHKO4_aJKkmz3jmIA5q3Y,7617
77
77
  dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py,sha256=AM6nSDKQc0Oqrv2Z0Uyaz8ztcPJrUGnwN5tlpvBzaBg,2579
79
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py,sha256=atfMF_8yaZ7qJ-ZzWLdLFlFEWvN3uiT3iqkINLUXxSQ,7796
79
+ dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py,sha256=1m3_KBbboCTunUAHtAfKDZS9K5DGhr-_EfMj3VOZ-_g,7748
80
80
  dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py,sha256=wR6PGR2DQvPS0YXELzCJ70fvzQnFvIzek3VFWVPoZk0,4883
81
81
  dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
82
  dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py,sha256=ML_k_KyuNOYBcwy6nrqJ077vj72b_a04MbJRy95KPcA,2306
@@ -126,24 +126,24 @@ dsp_tools/commands/validate_data/models/validation.py,sha256=okYFrLhaSQCGfa8A7gR
126
126
  dsp_tools/commands/validate_data/prepare_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
127
  dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py,sha256=sU_VmMAvvNsjKkld6Coc_HJLt32nzXOimvKRxIbte-o,11620
128
128
  dsp_tools/commands/validate_data/prepare_data/make_data_graph.py,sha256=TANm9WA_z-oPGkoMIR2BGZrHtAkizDlnK_5WDVxQRoQ,4098
129
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py,sha256=BcmAC8SLAmNS4kGrNOvMxpGQrWPJCVE1f1jDYRpSvYU,8320
129
+ dsp_tools/commands/validate_data/prepare_data/prepare_data.py,sha256=LL4JplvcQ0HXXqg13xY9pEkuOv9jfaQxB4xJdgXRSQk,8284
130
130
  dsp_tools/commands/validate_data/process_validation_report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py,sha256=W5VYJPs8J3VvJAaFDBGBuCQ3Xtonhn1iRUOxwgO7xV0,16148
132
132
  dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py,sha256=ln7zOq0LgkaVIoTNv2O72Z0tK6WX0UrbwAph-n0tD3E,22299
133
133
  dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py,sha256=YGJnYLHhmc_X4I6RqKDgnLClMo_bNVtzRZBER3uLWp8,6556
134
- dsp_tools/commands/validate_data/shacl_cli_validator.py,sha256=3PMFLwPgei76GI07lcboPrLYvjmYaHv7pg_dNvF2KlQ,2958
134
+ dsp_tools/commands/validate_data/shacl_cli_validator.py,sha256=4v8KM0GOkg1Zuq5ii29T2muUz3ZUsua7W6UhS9C3zcc,3079
135
135
  dsp_tools/commands/validate_data/sparql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
136
  dsp_tools/commands/validate_data/sparql/cardinality_shacl.py,sha256=V45pljnAx6jvsE1VRDKMZjZ1HdmwoMUnPUCQrQIYHMU,7218
137
137
  dsp_tools/commands/validate_data/sparql/construct_shacl.py,sha256=pB8sHn8FiAEiweeIYHROUAJH0YeCk8NWbzEI98YuEIQ,3553
138
138
  dsp_tools/commands/validate_data/sparql/legal_info_shacl.py,sha256=2yhn5HfCJFJpOTB-3XNWfxP1KwW3zKxDfqPdhN_Sazg,1522
139
139
  dsp_tools/commands/validate_data/sparql/value_shacl.py,sha256=uUkOlrMCcqzuVYQTXwTJOJw4RGDTd00y3OtLP41nY2c,13044
140
140
  dsp_tools/commands/validate_data/utils.py,sha256=L3kpuhn46x-OHap9RnN9QwUQjFYpkQFlFXzFKQfy5ZE,1990
141
- dsp_tools/commands/validate_data/validate_data.py,sha256=GKQv0G2pDnB_5wbUghk12wcCWBsc5hoNySsxuQ81C5U,13498
141
+ dsp_tools/commands/validate_data/validate_data.py,sha256=jMAqZfuy_HjHLYR58piXBFdb5oV4_UR8qdHBRYrUM7Q,13450
142
142
  dsp_tools/commands/validate_data/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
143
  dsp_tools/commands/validate_data/validation/check_duplicate_files.py,sha256=8HU7GZkTMXj68WrVTXadtQujjEP_MvkOnQb4iVtEHt4,2228
144
144
  dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py,sha256=Vhr1-nJzd3vzlwSoDJTljY-eFMpFLpTEy_zIEZb5MJs,2966
145
- dsp_tools/commands/validate_data/validation/get_validation_report.py,sha256=jvzFXzyG6bcSNzs6Buj_-NV85g9pwr9spMz_OBG8MQk,4201
146
- dsp_tools/commands/validate_data/validation/validate_ontology.py,sha256=R5-aD9cFc4KSLbT_IanhzSibx71uJX_dBBHgkoHtLKY,4783
145
+ dsp_tools/commands/validate_data/validation/get_validation_report.py,sha256=pJrz-A9cziHS_MsmoAs-P5eyj5h-jV7Z9yZBVyvOpgE,4223
146
+ dsp_tools/commands/validate_data/validation/validate_ontology.py,sha256=ePBoe7cUzeZcA0hUY9-vmkT4SUpaFhmfNwYwU5tsG9w,4805
147
147
  dsp_tools/commands/xmlupload/CLAUDE.md,sha256=EOmh0nPs5ne9iAFCdhG6LHYaYBn4hMkM86G8UfMMsaU,10547
148
148
  dsp_tools/commands/xmlupload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
149
  dsp_tools/commands/xmlupload/iri_resolver.py,sha256=1vHj4jMNCG6ZB0-opDfuLwL0guieTQXMmWYfbCdhoUI,625
@@ -157,7 +157,7 @@ dsp_tools/commands/xmlupload/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
157
157
  dsp_tools/commands/xmlupload/models/bitstream_info.py,sha256=LQHmaSauocNlCmnKSn89tG05dza1rkH671Ii5LocoQQ,464
158
158
  dsp_tools/commands/xmlupload/models/formatted_text_value.py,sha256=fBHctT5cHbDCNIAKs6IlgsY93v1qkKAyMeVwNg5d8g8,200
159
159
  dsp_tools/commands/xmlupload/models/ingest.py,sha256=dwZMpKQJ7cJpgUXCVRzQpyzagoOWPLq5B2NGbsJZPyU,5770
160
- dsp_tools/commands/xmlupload/models/input_problems.py,sha256=Sw4_V6JVMRd2l8m9vL32BpUozQ5DYgbnK9nLNaxIaV0,1995
160
+ dsp_tools/commands/xmlupload/models/input_problems.py,sha256=agr0Qz2JFLlI7S9IeK09jqemxzPriTvuW5pYuTj4FGg,2017
161
161
  dsp_tools/commands/xmlupload/models/lookup_models.py,sha256=2rt1-tqvE-El-QDtDtxTGYMn3ZUN2JsHFwrmC01W4Kg,477
162
162
  dsp_tools/commands/xmlupload/models/permission.py,sha256=ptHV3sY5T0YVPf1zAboxKint4SajEfOI67OVl6YzfUY,1058
163
163
  dsp_tools/commands/xmlupload/models/permissions_parsed.py,sha256=frflZBEGKmcoz7-JZDBvYUamw5hSKuJe5R20Oq-umXE,3648
@@ -187,15 +187,15 @@ dsp_tools/commands/xmlupload/stash/stash_circular_references.py,sha256=EFcROk78B
187
187
  dsp_tools/commands/xmlupload/stash/stash_models.py,sha256=zIYKUyRIGY6SMiQRgA2AozyOKJwEwiq8nyXV06bEMiI,3300
188
188
  dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py,sha256=PTk-d9ZlSxMdrlE2gbd1k5WuHvROFn-e2pYhJJCi5sM,4212
189
189
  dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py,sha256=zMKUa2lx7zZ26bbL6uF-8vVypi8KKLgwBXqF-DADVV4,7460
190
- dsp_tools/commands/xmlupload/upload_config.py,sha256=4PBjzGIly0yh9k9I8IDYRWo81U1Bfuh5h8XitdzsGQE,2598
190
+ dsp_tools/commands/xmlupload/upload_config.py,sha256=7lz3PcrHOsTvEBBzDWTvygtNRaf6luAKo_qoOxJp0Ks,2586
191
191
  dsp_tools/commands/xmlupload/write_diagnostic_info.py,sha256=ODjCAdKZyxHYDUhpIVpdEwIzjP-2HFySrzWN6Tddb1A,1281
192
- dsp_tools/commands/xmlupload/xmlupload.py,sha256=q_xC9CEDSFb4lMmJoECKZrzTGfIWnAgBx0dnGuz33Oo,22373
192
+ dsp_tools/commands/xmlupload/xmlupload.py,sha256=82cNcy0x_FNjJkXRAijsu_T4m4tZHo7u5gJ74aSwC98,22349
193
193
  dsp_tools/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
194
194
  dsp_tools/config/logger_config.py,sha256=Bw2Gu5F2d8un_KNk0hvNtV7fvN2TlThqo6gSwqeccOU,2067
195
195
  dsp_tools/config/warnings_config.py,sha256=15_Lt227HLqhdn6v-zJbi1KG9Fo6Zi1_4fp_a-iY72w,1142
196
196
  dsp_tools/error/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
197
- dsp_tools/error/custom_warnings.py,sha256=7C2DscIz9k7IfM8uebIsKWPcWcSjwpDqbIRDaPw7bI8,1053
198
- dsp_tools/error/exceptions.py,sha256=CjP6zUqODKH5qw9XEo-v3gJcP3Pct0bZ-UbYrIahu-I,5321
197
+ dsp_tools/error/custom_warnings.py,sha256=BPwvzZ9dxFMWYlWwIaDvTjdv24JFaDZU9-HW6MG5DK4,1294
198
+ dsp_tools/error/exceptions.py,sha256=z8e4ccF4ezJ9JO6SD02P6b49yuJ3yUYGPT9YS0ihoO0,6013
199
199
  dsp_tools/error/problems.py,sha256=DotzVg3MYvMJmernd9tTBmDHoT1MOkHdiWVv8iMoFSk,265
200
200
  dsp_tools/error/xmllib_errors.py,sha256=DpYCsBIx_GmsBAUlfk2VMqtzD5IGMRbd2yXTcrJFHR4,549
201
201
  dsp_tools/error/xmllib_warnings.py,sha256=sS9jJXGJtQqCiJ9P2zCM5gpIhTpChbujQz_fPvxLm8g,1557
@@ -227,12 +227,12 @@ dsp_tools/utils/data_formats/date_util.py,sha256=VLNQnSsUX6NB1IY3Ry5KCxCLgHHYN0T
227
227
  dsp_tools/utils/data_formats/iri_util.py,sha256=oFcc3gcikmgJOf7iMhT4tfdUQg9wE7lUW5aysfHjylM,1030
228
228
  dsp_tools/utils/data_formats/shared.py,sha256=9AybXCAboojvRULZPud5e6B7UkjQOuN6f5fiVxwuZe8,2618
229
229
  dsp_tools/utils/data_formats/uri_util.py,sha256=9UGrbtxHVI0Ka0ttxd39KDhGeeP0xOdVLjt6HyV-Ic8,3257
230
- dsp_tools/utils/fuseki_bloating.py,sha256=yUCSijVf_Ne9iWUK_IzbPAkOMkN8Xt9ttPcWWRSIgMI,2381
230
+ dsp_tools/utils/fuseki_bloating.py,sha256=B1k_HS9sLGY2YLqS7wiFBHxthoW4FVsb3JH1YxUOxnQ,2530
231
231
  dsp_tools/utils/json_parsing.py,sha256=KlNvwnZoq-gJqnOVH7tiZMzgdld_3IunuOVvlEVXGXc,1684
232
232
  dsp_tools/utils/rdflib_constants.py,sha256=D5HO7oILBRiQI-bJj14pbCx6zhKY4RGqjIjq6S_IawU,652
233
233
  dsp_tools/utils/rdflib_utils.py,sha256=M9UCXMe8W3SDQ0DYh4i6lRwYkyWozrWLl19NP5A-RlY,284
234
234
  dsp_tools/utils/replace_id_with_iri.py,sha256=5M5vXWJIQ0oO4ELwIt_5QeYBvyGESBc2smuNThHiQUY,2928
235
- dsp_tools/utils/request_utils.py,sha256=KxiFpQ_IH1ZCIF-SknPjRMP5-ZtLP3wWzwSrEZDB2fk,6902
235
+ dsp_tools/utils/request_utils.py,sha256=JVJCCeHTfwXZnOlmsXJL4dHHBO6_q-4JdGEC8icIOzQ,8304
236
236
  dsp_tools/utils/xml_parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
237
237
  dsp_tools/utils/xml_parsing/get_lookups.py,sha256=RaBX_wWTmhxpvP1Ow5lbzNxekSyZ4SbuGZTFc18H1jQ,1386
238
238
  dsp_tools/utils/xml_parsing/get_parsed_resources.py,sha256=H3lLmWcBjuW5oN2fYV_Sv71brnH6E-ZsmwsceZ2l1yw,13496
@@ -265,11 +265,11 @@ dsp_tools/xmllib/models/licenses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
265
265
  dsp_tools/xmllib/models/licenses/other.py,sha256=3S3kaVLHhgrVVG8d9PjApa3UwI3bor_bqx5OliW_Qsw,1986
266
266
  dsp_tools/xmllib/models/licenses/recommended.py,sha256=mxMg0wYrad_7vCbbtsLk7C3JwUeTse7wT-_mpiPVCKw,3924
267
267
  dsp_tools/xmllib/models/permissions.py,sha256=6pamw3q6CNV73OoFcIBZn6YibGTsSXnMoGy6AdkZI7o,1145
268
- dsp_tools/xmllib/models/res.py,sha256=c3edvilYZVDmv2O6Z36sSkHXcuKPAJLfWVpStDTMuJM,62857
268
+ dsp_tools/xmllib/models/res.py,sha256=hUOyyS5sU7pIfFwVo5lQoK62adBgC-cYkGV9MWXWbGA,62925
269
269
  dsp_tools/xmllib/models/root.py,sha256=x8_vrDSJ1pZUJUL8LR460dZe4Cg57G_Hy-Zfr2S29dw,13562
270
270
  dsp_tools/xmllib/value_checkers.py,sha256=Yx3r6_WoZ5Lev8Orp8yDzd03JvP2GBmFNSFT2dzrycM,10712
271
271
  dsp_tools/xmllib/value_converters.py,sha256=WMYS5hd1VlrLLBXnf6pv9yYoPBsv_2MxOO6xv-QsRW4,29218
272
- dsp_tools-18.0.0.dist-info/WHEEL,sha256=UH59_qNuDUAa1VxQvC6fxmbl24EMw6DOIlT1yp8oeuU,78
273
- dsp_tools-18.0.0.dist-info/entry_points.txt,sha256=qjRfEbkeAwLU_AE2Q-l4Y9irPNmu4Wna-3bfRp1bqV4,62
274
- dsp_tools-18.0.0.dist-info/METADATA,sha256=j79Vnn6Ab7AjQuCuUpihzCmWwGbUtdsb0Q8zxmTANc8,4278
275
- dsp_tools-18.0.0.dist-info/RECORD,,
272
+ dsp_tools-18.0.0.post3.dist-info/WHEEL,sha256=5w2T7AS2mz1-rW9CNagNYWRCaB0iQqBMYLwKdlgiR4Q,78
273
+ dsp_tools-18.0.0.post3.dist-info/entry_points.txt,sha256=qjRfEbkeAwLU_AE2Q-l4Y9irPNmu4Wna-3bfRp1bqV4,62
274
+ dsp_tools-18.0.0.post3.dist-info/METADATA,sha256=8RiY5uC7bUpxmhtHLqgUI0Zgx6imVNa6iKRz12SvCto,4284
275
+ dsp_tools-18.0.0.post3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.6
2
+ Generator: uv 0.9.7
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any