dsp-tools 17.0.0.post29__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.

Files changed (50) hide show
  1. dsp_tools/cli/args.py +13 -0
  2. dsp_tools/cli/call_action.py +34 -330
  3. dsp_tools/cli/call_action_files_only.py +74 -0
  4. dsp_tools/cli/call_action_with_network.py +202 -0
  5. dsp_tools/cli/create_parsers.py +53 -14
  6. dsp_tools/cli/utils.py +87 -0
  7. dsp_tools/clients/list_client.py +49 -0
  8. dsp_tools/clients/list_client_live.py +166 -0
  9. dsp_tools/clients/{ontology_client.py → ontology_clients.py} +17 -2
  10. dsp_tools/clients/{ontology_client_live.py → ontology_create_client_live.py} +21 -40
  11. dsp_tools/clients/ontology_get_client_live.py +66 -0
  12. dsp_tools/clients/project_client.py +10 -0
  13. dsp_tools/clients/project_client_live.py +36 -0
  14. dsp_tools/commands/create/create_on_server/cardinalities.py +14 -8
  15. dsp_tools/commands/create/create_on_server/lists.py +163 -0
  16. dsp_tools/commands/create/lists_only.py +45 -0
  17. dsp_tools/commands/create/models/input_problems.py +13 -0
  18. dsp_tools/commands/create/models/parsed_project.py +14 -1
  19. dsp_tools/commands/create/models/rdf_ontology.py +0 -7
  20. dsp_tools/commands/create/models/server_project_info.py +17 -3
  21. dsp_tools/commands/create/parsing/parse_lists.py +45 -0
  22. dsp_tools/commands/create/parsing/parse_project.py +23 -4
  23. dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +4 -4
  24. dsp_tools/commands/project/create/project_create_all.py +17 -13
  25. dsp_tools/commands/project/create/project_create_default_permissions.py +8 -6
  26. dsp_tools/commands/project/create/project_create_ontologies.py +30 -18
  27. dsp_tools/commands/project/legacy_models/listnode.py +0 -30
  28. dsp_tools/commands/validate_data/models/api_responses.py +2 -16
  29. dsp_tools/commands/validate_data/prepare_data/prepare_data.py +11 -10
  30. dsp_tools/commands/validate_data/shacl_cli_validator.py +3 -1
  31. dsp_tools/commands/validate_data/sparql/value_shacl.py +1 -1
  32. dsp_tools/commands/validate_data/validate_data.py +3 -3
  33. dsp_tools/commands/validate_data/validation/get_validation_report.py +1 -1
  34. dsp_tools/commands/validate_data/validation/validate_ontology.py +1 -1
  35. dsp_tools/commands/xmlupload/models/input_problems.py +1 -1
  36. dsp_tools/commands/xmlupload/upload_config.py +1 -1
  37. dsp_tools/commands/xmlupload/xmlupload.py +2 -2
  38. dsp_tools/error/custom_warnings.py +7 -0
  39. dsp_tools/error/exceptions.py +25 -2
  40. dsp_tools/resources/start-stack/docker-compose.yml +23 -23
  41. dsp_tools/utils/ansi_colors.py +2 -0
  42. dsp_tools/utils/fuseki_bloating.py +4 -2
  43. dsp_tools/utils/request_utils.py +31 -0
  44. dsp_tools/xmllib/models/res.py +2 -0
  45. {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/METADATA +1 -1
  46. {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/RECORD +48 -39
  47. {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/WHEEL +1 -1
  48. dsp_tools/commands/project/create/project_create_lists.py +0 -200
  49. dsp_tools/commands/validate_data/api_clients.py +0 -124
  50. {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/entry_points.txt +0 -0
@@ -11,12 +11,25 @@ from dsp_tools.commands.create.models.parsed_project import ParsedPermissions
11
11
  from dsp_tools.commands.create.models.parsed_project import ParsedProject
12
12
  from dsp_tools.commands.create.models.parsed_project import ParsedProjectMetadata
13
13
  from dsp_tools.commands.create.models.parsed_project import ParsedUser
14
+ from dsp_tools.commands.create.parsing.parse_lists import parse_list_section
14
15
  from dsp_tools.commands.create.parsing.parse_ontology import parse_ontology
15
16
  from dsp_tools.commands.create.parsing.parsing_utils import create_prefix_lookup
16
17
  from dsp_tools.commands.project.create.project_validate import validate_project
17
18
  from dsp_tools.utils.json_parsing import parse_json_input
18
19
 
19
20
 
21
+ def parse_lists_only(
22
+ project_file_as_path_or_parsed: str | Path | dict[str, Any],
23
+ ) -> tuple[ParsedProjectMetadata, list[ParsedList]] | CollectedProblems:
24
+ complete_json = _parse_and_validate(project_file_as_path_or_parsed)
25
+ project_json = complete_json["project"]
26
+ project_metadata = _parse_metadata(project_json)
27
+ parsed_lists, problems = _parse_lists(project_json)
28
+ if isinstance(problems, CollectedProblems):
29
+ return problems
30
+ return project_metadata, parsed_lists
31
+
32
+
20
33
  def parse_project(
21
34
  project_file_as_path_or_parsed: str | Path | dict[str, Any], api_url: str
22
35
  ) -> ParsedProject | list[CollectedProblems]:
@@ -28,6 +41,9 @@ def _parse_project(complete_json: dict[str, Any], api_url: str) -> ParsedProject
28
41
  prefix_lookup = create_prefix_lookup(complete_json, api_url)
29
42
  project_json = complete_json["project"]
30
43
  ontologies, failures = _parse_all_ontologies(project_json, prefix_lookup)
44
+ parsed_lists, problems = _parse_lists(project_json)
45
+ if isinstance(problems, CollectedProblems):
46
+ failures.append(problems)
31
47
  if failures:
32
48
  return failures
33
49
  return ParsedProject(
@@ -36,7 +52,7 @@ def _parse_project(complete_json: dict[str, Any], api_url: str) -> ParsedProject
36
52
  permissions=_parse_permissions(project_json),
37
53
  groups=_parse_groups(project_json),
38
54
  users=_parse_users(project_json),
39
- lists=_parse_lists(project_json),
55
+ lists=parsed_lists,
40
56
  ontologies=ontologies,
41
57
  )
42
58
 
@@ -79,10 +95,13 @@ def _parse_users(project_json: dict[str, Any]) -> list[ParsedUser]:
79
95
  return [ParsedUser(x) for x in found]
80
96
 
81
97
 
82
- def _parse_lists(project_json: dict[str, Any]) -> list[ParsedList]:
98
+ def _parse_lists(project_json: dict[str, Any]) -> tuple[list[ParsedList], CollectedProblems | None]:
83
99
  if not (found := project_json.get("lists")):
84
- return []
85
- return [ParsedList(x["name"], x) for x in found]
100
+ return [], None
101
+ result = parse_list_section(found)
102
+ if isinstance(result, CollectedProblems):
103
+ return [], result
104
+ return result, None
86
105
 
87
106
 
88
107
  def _parse_all_ontologies(
@@ -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)
@@ -15,12 +15,13 @@ from dsp_tools.clients.authentication_client_live import AuthenticationClientLiv
15
15
  from dsp_tools.clients.connection import Connection
16
16
  from dsp_tools.clients.connection_live import ConnectionLive
17
17
  from dsp_tools.commands.create.communicate_problems import print_problem_collection
18
+ from dsp_tools.commands.create.create_on_server.lists import create_lists
19
+ from dsp_tools.commands.create.create_on_server.lists import get_existing_lists_on_server
18
20
  from dsp_tools.commands.create.models.parsed_project import ParsedProject
19
21
  from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
20
22
  from dsp_tools.commands.create.parsing.parse_project import parse_project
21
23
  from dsp_tools.commands.project.create.parse_project import parse_project_json
22
24
  from dsp_tools.commands.project.create.project_create_default_permissions import create_default_permissions
23
- from dsp_tools.commands.project.create.project_create_lists import create_lists_on_server
24
25
  from dsp_tools.commands.project.create.project_create_ontologies import create_ontologies
25
26
  from dsp_tools.commands.project.legacy_models.context import Context
26
27
  from dsp_tools.commands.project.legacy_models.group import Group
@@ -33,6 +34,8 @@ from dsp_tools.error.exceptions import InputError
33
34
  from dsp_tools.error.exceptions import InvalidInputError
34
35
  from dsp_tools.error.exceptions import PermanentConnectionError
35
36
  from dsp_tools.legacy_models.langstring import LangString
37
+ from dsp_tools.utils.ansi_colors import BOLD
38
+ from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
36
39
  from dsp_tools.utils.json_parsing import parse_json_input
37
40
 
38
41
  load_dotenv()
@@ -89,8 +92,8 @@ def create_project( # noqa: PLR0915,PLR0912 (too many statements & branches)
89
92
  con = ConnectionLive(creds.server, auth)
90
93
 
91
94
  # create project on DSP server
92
- info_str = f"Create project '{legacy_project.metadata.shortname}' ({legacy_project.metadata.shortcode})..."
93
- print(info_str)
95
+ info_str = f"Create project '{legacy_project.metadata.shortname}' ({legacy_project.metadata.shortcode}):"
96
+ print(BOLD + info_str + RESET_TO_DEFAULT)
94
97
  logger.info(info_str)
95
98
  project_remote, success = _create_project_on_server(
96
99
  project_definition=legacy_project.metadata,
@@ -102,17 +105,18 @@ def create_project( # noqa: PLR0915,PLR0912 (too many statements & branches)
102
105
  overall_success = False
103
106
 
104
107
  # create the lists
105
- names_and_iris_of_list_nodes: dict[str, Any] = {}
106
- if legacy_project.lists:
107
- print("Create lists...")
108
- logger.info("Create lists...")
109
- names_and_iris_of_list_nodes, success = create_lists_on_server(
110
- lists_to_create=legacy_project.lists,
111
- con=con,
112
- project_remote=project_remote,
108
+ if parsed_project.lists:
109
+ list_name_2_iri, list_problems = create_lists(
110
+ parsed_lists=parsed_project.lists,
111
+ shortcode=parsed_project.project_metadata.shortcode,
112
+ auth=auth,
113
+ project_iri=project_iri,
113
114
  )
114
- if not success:
115
+ if list_problems:
115
116
  overall_success = False
117
+ print_problem_collection(list_problems)
118
+ else:
119
+ list_name_2_iri = get_existing_lists_on_server(parsed_project.project_metadata.shortcode, auth)
116
120
 
117
121
  # create the groups
118
122
  current_project_groups: dict[str, Group] = {}
@@ -146,7 +150,7 @@ def create_project( # noqa: PLR0915,PLR0912 (too many statements & branches)
146
150
  con=con,
147
151
  context=context,
148
152
  knora_api_prefix=knora_api_prefix,
149
- names_and_iris_of_list_nodes=names_and_iris_of_list_nodes,
153
+ list_name_2_iri=list_name_2_iri,
150
154
  ontology_definitions=legacy_project.ontologies,
151
155
  project_remote=project_remote,
152
156
  verbose=verbose,
@@ -1,6 +1,8 @@
1
1
  from loguru import logger
2
2
 
3
3
  from dsp_tools.commands.project.models.permissions_client import PermissionsClient
4
+ from dsp_tools.utils.ansi_colors import BOLD
5
+ from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
4
6
 
5
7
  USER_IRI_PREFIX = "http://www.knora.org/ontology/knora-admin#"
6
8
 
@@ -11,23 +13,23 @@ def create_default_permissions(
11
13
  default_permissions_overrule: dict[str, str | list[str]] | None,
12
14
  shortcode: str,
13
15
  ) -> bool:
14
- logger.info("Set default permissions...")
15
- print("Set default permissions...")
16
+ print(BOLD + "Processing default permissions:" + RESET_TO_DEFAULT)
17
+ logger.info("Processing default permissions:")
16
18
  if not _delete_existing_doaps(perm_client):
17
- print("WARNING: Cannot delete the existing default permissions")
19
+ print(" WARNING: Cannot delete the existing default permissions")
18
20
  logger.warning("Cannot delete the existing default permissions")
19
21
  return False
20
22
  if not _create_new_doap(perm_client, default_permissions):
21
- print("WARNING: Cannot create default permissions")
23
+ print(" WARNING: Cannot create default permissions")
22
24
  logger.warning("Cannot create default permissions")
23
25
  return False
24
26
  if default_permissions_overrule:
25
27
  if not _create_overrules(perm_client, default_permissions_overrule, shortcode):
26
- print("WARNING: Cannot create default permissions overrules")
28
+ print(" WARNING: Cannot create default permissions overrules")
27
29
  logger.warning("Cannot create default permissions overrules")
28
30
  return False
31
+ print(" Default permissions have been set")
29
32
  logger.info("Default permissions have been set")
30
- print("Default permissions have been set")
31
33
  return True
32
34
 
33
35
 
@@ -7,11 +7,12 @@ from loguru import logger
7
7
 
8
8
  from dsp_tools.clients.authentication_client import AuthenticationClient
9
9
  from dsp_tools.clients.connection import Connection
10
- from dsp_tools.clients.ontology_client_live import OntologyClientLive
10
+ from dsp_tools.clients.ontology_create_client_live import OntologyCreateClientLive
11
11
  from dsp_tools.commands.create.communicate_problems import print_problem_collection
12
12
  from dsp_tools.commands.create.create_on_server.cardinalities import add_all_cardinalities
13
13
  from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
14
14
  from dsp_tools.commands.create.models.server_project_info import CreatedIriCollection
15
+ from dsp_tools.commands.create.models.server_project_info import ListNameToIriLookup
15
16
  from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
16
17
  from dsp_tools.commands.project.legacy_models.context import Context
17
18
  from dsp_tools.commands.project.legacy_models.ontology import Ontology
@@ -22,13 +23,15 @@ from dsp_tools.error.exceptions import BaseError
22
23
  from dsp_tools.error.exceptions import InputError
23
24
  from dsp_tools.legacy_models.datetimestamp import DateTimeStamp
24
25
  from dsp_tools.legacy_models.langstring import LangString
26
+ from dsp_tools.utils.ansi_colors import BOLD
27
+ from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
25
28
 
26
29
 
27
30
  def create_ontologies(
28
31
  con: Connection,
29
32
  context: Context,
30
33
  knora_api_prefix: str,
31
- names_and_iris_of_list_nodes: dict[str, Any],
34
+ list_name_2_iri: ListNameToIriLookup,
32
35
  ontology_definitions: list[dict[str, Any]],
33
36
  project_remote: Project,
34
37
  verbose: bool,
@@ -45,7 +48,7 @@ def create_ontologies(
45
48
  con: Connection to the DSP server
46
49
  context: prefixes and the ontology IRIs they stand for
47
50
  knora_api_prefix: the prefix that stands for the knora-api ontology
48
- names_and_iris_of_list_nodes: IRIs of list nodes that were already created and are available on the DSP server
51
+ list_name_2_iri: IRIs of list nodes that were already created and are available on the DSP server
49
52
  ontology_definitions: the "ontologies" section of the parsed JSON project file
50
53
  project_remote: representation of the project on the DSP server
51
54
  verbose: verbose switch
@@ -61,17 +64,15 @@ def create_ontologies(
61
64
  True if everything went smoothly, False otherwise
62
65
  """
63
66
  success_collection = CreatedIriCollection()
64
- onto_client = OntologyClientLive(auth.server, auth)
67
+ onto_client = OntologyCreateClientLive(auth.server, auth)
65
68
 
66
69
  overall_success = True
67
-
68
- print("Create ontologies...")
69
- logger.info("Create ontologies...")
70
+ logger.info("Processing Ontology Section")
70
71
  try:
71
72
  project_ontologies = Ontology.getProjectOntologies(con=con, project_id=str(project_remote.iri))
72
73
  except BaseError:
73
74
  err_msg = "Unable to retrieve remote ontologies. Cannot check if your ontology already exists."
74
- print("WARNING: {err_msg}")
75
+ print(f" WARNING: {err_msg}")
75
76
  logger.exception(err_msg)
76
77
  project_ontologies = []
77
78
 
@@ -114,7 +115,7 @@ def create_ontologies(
114
115
  onto_name=ontology_definition["name"],
115
116
  property_definitions=ontology_definition.get("properties", []),
116
117
  ontology_remote=ontology_remote,
117
- names_and_iris_of_list_nodes=names_and_iris_of_list_nodes,
118
+ list_name_2_iri=list_name_2_iri,
118
119
  con=con,
119
120
  last_modification_date=last_modification_date,
120
121
  knora_api_prefix=knora_api_prefix,
@@ -125,7 +126,7 @@ def create_ontologies(
125
126
  if not success:
126
127
  overall_success = False
127
128
 
128
- print("Add cardinalities to resource classes...")
129
+ print(BOLD + "Processing Cardinalities:" + RESET_TO_DEFAULT)
129
130
  problems = add_all_cardinalities(
130
131
  ontologies=parsed_ontologies,
131
132
  project_iri_lookup=project_iri_lookup,
@@ -173,12 +174,12 @@ def _create_ontology(
173
174
  # skip if it already exists on the DSP server
174
175
  if onto_name in [onto.name for onto in project_ontologies]:
175
176
  err_msg = f"Ontology '{onto_name}' already exists on the DSP server. Skipping..."
176
- print(f" WARNING: {err_msg}")
177
+ print(f"WARNING: {err_msg}")
177
178
  logger.warning(err_msg)
178
179
  return None
179
180
 
180
- print(f"Create ontology '{onto_name}'...")
181
- logger.info(f"Create ontology '{onto_name}'...")
181
+ print(BOLD + f"Processing ontology '{onto_name}':" + RESET_TO_DEFAULT)
182
+ logger.info(f"Processing ontology '{onto_name}'")
182
183
  ontology_local = Ontology(
183
184
  con=con,
184
185
  project=project_remote,
@@ -308,11 +309,11 @@ def _sort_resources(
308
309
  return sorted_resources
309
310
 
310
311
 
311
- def _add_property_classes_to_remote_ontology(
312
+ def _add_property_classes_to_remote_ontology( # noqa: PLR0912
312
313
  onto_name: str,
313
314
  property_definitions: list[dict[str, Any]],
314
315
  ontology_remote: Ontology,
315
- names_and_iris_of_list_nodes: dict[str, Any],
316
+ list_name_2_iri: ListNameToIriLookup,
316
317
  con: Connection,
317
318
  last_modification_date: DateTimeStamp,
318
319
  knora_api_prefix: str,
@@ -328,7 +329,7 @@ def _add_property_classes_to_remote_ontology(
328
329
  onto_name: name of the current ontology
329
330
  property_definitions: the part of the parsed JSON project file that contains the properties of the current onto
330
331
  ontology_remote: representation of the current ontology on the DSP server
331
- names_and_iris_of_list_nodes: IRIs of list nodes that were already created and are available on the DSP server
332
+ list_name_2_iri: IRIs of list nodes that were already created and are available on the DSP server
332
333
  con: connection to the DSP server
333
334
  last_modification_date: last modification date of the ontology on the DSP server
334
335
  knora_api_prefix: the prefix that stands for the knora-api ontology
@@ -373,7 +374,18 @@ def _add_property_classes_to_remote_ontology(
373
374
  # get the gui_attributes
374
375
  gui_attributes = prop_class.get("gui_attributes")
375
376
  if gui_attributes and gui_attributes.get("hlist"):
376
- list_iri = names_and_iris_of_list_nodes[gui_attributes["hlist"]]["id"]
377
+ list_name = gui_attributes["hlist"]
378
+ list_iri = list_name_2_iri.get_iri(list_name)
379
+ if not list_iri:
380
+ err_msg = (
381
+ f"Unable to create property class '{prop_class['name']}' "
382
+ f"because the list with the name '{list_name}' does not exist on the server."
383
+ )
384
+ print(f" WARNING: {err_msg}")
385
+ logger.warning(err_msg)
386
+ overall_success = False
387
+ continue
388
+
377
389
  gui_attributes["hlist"] = f"<{list_iri}>"
378
390
 
379
391
  # create the property class
@@ -405,7 +417,7 @@ def _add_property_classes_to_remote_ontology(
405
417
  err.message,
406
418
  ):
407
419
  err_msg += f", because it refers to a class of another project: '{found.group(1)}'."
408
- print(f"WARNING: {err_msg}")
420
+ print(f" WARNING: {err_msg}")
409
421
  logger.exception(err_msg)
410
422
  overall_success = False
411
423
 
@@ -301,36 +301,6 @@ class ListNode(Model):
301
301
  rootNodeIri=rootNodeIri,
302
302
  )
303
303
 
304
- def create(self) -> ListNode:
305
- """
306
- Create a new List
307
-
308
- :return: JSON-object from DSP-API
309
- """
310
- jsonobj = self._toJsonObj_create()
311
- if self._parent:
312
- result = self._con.post(ListNode.ROUTE_SLASH + quote_plus(self._parent), jsonobj)
313
- return ListNode.fromJsonObj(self._con, result["nodeinfo"])
314
- else:
315
- result = self._con.post(ListNode.ROUTE, jsonobj)
316
- return ListNode.fromJsonObj(self._con, result["list"]["listinfo"])
317
-
318
- def _toJsonObj_create(self):
319
- tmp = {}
320
- if self._project is None:
321
- raise BaseError("There must be a project id given!")
322
- tmp["projectIri"] = self._project
323
- if self._label.isEmpty():
324
- raise BaseError("There must be a valid ListNode label!")
325
- tmp["labels"] = self._label.toJsonObj()
326
- if self._comments:
327
- tmp["comments"] = self._comments.toJsonObj()
328
- if self._name:
329
- tmp["name"] = self._name
330
- if self._parent:
331
- tmp["parentNodeIri"] = self._parent
332
- return tmp
333
-
334
304
  def read(self) -> Any:
335
305
  """
336
306
  Read a project from DSP-API
@@ -5,6 +5,8 @@ from dataclasses import dataclass
5
5
  from rdflib import Graph
6
6
  from rdflib import URIRef
7
7
 
8
+ from dsp_tools.clients.list_client import OneList
9
+
8
10
 
9
11
  @dataclass
10
12
  class SHACLValidationReport:
@@ -24,22 +26,6 @@ class ListLookup:
24
26
  lists: dict[tuple[str, str], str]
25
27
 
26
28
 
27
- @dataclass
28
- class OneList:
29
- list_iri: str
30
- list_name: str
31
- nodes: list[OneNode]
32
-
33
- def hlist(self) -> str:
34
- return f'"hlist=<{self.list_iri}>"'
35
-
36
-
37
- @dataclass
38
- class OneNode:
39
- name: str
40
- iri: str
41
-
42
-
43
29
  @dataclass
44
30
  class SHACLListInfo:
45
31
  list_iri: URIRef
@@ -8,14 +8,15 @@ from rdflib import URIRef
8
8
 
9
9
  from dsp_tools.clients.authentication_client import AuthenticationClient
10
10
  from dsp_tools.clients.legal_info_client_live import LegalInfoClientLive
11
+ from dsp_tools.clients.list_client import OneList
12
+ from dsp_tools.clients.list_client_live import ListGetClientLive
11
13
  from dsp_tools.clients.metadata_client import ExistingResourcesRetrieved
12
14
  from dsp_tools.clients.metadata_client_live import MetadataClientLive
13
- from dsp_tools.commands.validate_data.api_clients import ListClient
14
- from dsp_tools.commands.validate_data.api_clients import OntologyClient
15
+ from dsp_tools.clients.ontology_clients import OntologyGetClient
16
+ from dsp_tools.clients.ontology_get_client_live import OntologyGetClientLive
15
17
  from dsp_tools.commands.validate_data.models.api_responses import EnabledLicenseIris
16
18
  from dsp_tools.commands.validate_data.models.api_responses import InfoForResourceInDB
17
19
  from dsp_tools.commands.validate_data.models.api_responses import ListLookup
18
- from dsp_tools.commands.validate_data.models.api_responses import OneList
19
20
  from dsp_tools.commands.validate_data.models.api_responses import ProjectDataFromApi
20
21
  from dsp_tools.commands.validate_data.models.validation import RDFGraphs
21
22
  from dsp_tools.commands.validate_data.prepare_data.get_rdf_like_data import get_rdf_like_data
@@ -29,15 +30,15 @@ from dsp_tools.utils.xml_parsing.parse_clean_validate_xml import parse_and_clean
29
30
 
30
31
 
31
32
  def get_info_and_parsed_resources_from_file(
32
- file: Path, api_url: str, id2iri_replacement_file: str | None
33
+ file: Path, api_url: str, id2iri_file: str | None
33
34
  ) -> tuple[list[ParsedResource], str, dict[str, list[str]], list[str]]:
34
35
  root = parse_and_clean_xml_file(file)
35
36
  shortcode = root.attrib["shortcode"]
36
37
  authorship_lookup = get_authorship_lookup(root)
37
38
  permission_ids = [perm.attrib["id"] for perm in root.findall("permissions")]
38
39
  parsed_resources = get_parsed_resources(root, api_url)
39
- if id2iri_replacement_file:
40
- 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))
41
42
  return parsed_resources, shortcode, authorship_lookup, permission_ids
42
43
 
43
44
 
@@ -71,8 +72,8 @@ def _make_list_lookup(project_lists: list[OneList]) -> ListLookup:
71
72
  def _get_project_specific_information_from_api(
72
73
  auth: AuthenticationClient, shortcode: str, do_not_request_resource_metadata_from_db: bool
73
74
  ) -> tuple[ProjectDataFromApi, ExistingResourcesRetrieved]:
74
- list_client = ListClient(auth.server, shortcode)
75
- all_lists = list_client.get_lists()
75
+ list_client = ListGetClientLive(auth.server, shortcode)
76
+ all_lists = list_client.get_all_lists_and_nodes()
76
77
  enabled_licenses = _get_license_iris(shortcode, auth)
77
78
  if do_not_request_resource_metadata_from_db:
78
79
  existing_resources_retrieved = ExistingResourcesRetrieved.FALSE
@@ -107,7 +108,7 @@ def _create_graphs(
107
108
  permission_ids: list[str],
108
109
  ) -> RDFGraphs:
109
110
  logger.debug("Create all graphs.")
110
- onto_client = OntologyClient(auth.server, shortcode)
111
+ onto_client = OntologyGetClientLive(auth.server, shortcode)
111
112
  ontologies, onto_iris = _get_project_ontos(onto_client)
112
113
  knora_ttl = onto_client.get_knora_api()
113
114
  knora_api = Graph()
@@ -154,7 +155,7 @@ def _bind_prefixes_to_graph(g: Graph, project_ontos: list[str]) -> Graph:
154
155
  return g
155
156
 
156
157
 
157
- def _get_project_ontos(onto_client: OntologyClient) -> tuple[Graph, list[str]]:
158
+ def _get_project_ontos(onto_client: OntologyGetClient) -> tuple[Graph, list[str]]:
158
159
  logger.debug("Get project ontologies from server.")
159
160
  all_ontos, onto_iris = onto_client.get_ontologies()
160
161
  onto_g = Graph()
@@ -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
@@ -8,7 +8,7 @@ from rdflib import Literal
8
8
  from rdflib import URIRef
9
9
  from rdflib.collection import Collection
10
10
 
11
- from dsp_tools.commands.validate_data.models.api_responses import OneList
11
+ from dsp_tools.clients.list_client import OneList
12
12
  from dsp_tools.commands.validate_data.models.api_responses import SHACLListInfo
13
13
  from dsp_tools.utils.rdflib_constants import KNORA_API
14
14
  from dsp_tools.utils.rdflib_constants import PropertyTypeAlias
@@ -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."""
@@ -154,3 +169,11 @@ class XmlUploadListNodeNotFoundError(BaseError):
154
169
 
155
170
  class UnknownDOAPException(BaseError):
156
171
  """Class for errors that are raised if a DOAP cannot be parsed"""
172
+
173
+
174
+ class CreateError(BaseError):
175
+ """Errors for the create command."""
176
+
177
+
178
+ class ProjectNotFoundError(CreateError):
179
+ """Class if a project is expected to exist but could not be found."""