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.
- dsp_tools/cli/args.py +13 -0
- dsp_tools/cli/call_action.py +34 -330
- dsp_tools/cli/call_action_files_only.py +74 -0
- dsp_tools/cli/call_action_with_network.py +202 -0
- dsp_tools/cli/create_parsers.py +53 -14
- dsp_tools/cli/utils.py +87 -0
- dsp_tools/clients/list_client.py +49 -0
- dsp_tools/clients/list_client_live.py +166 -0
- dsp_tools/clients/{ontology_client.py → ontology_clients.py} +17 -2
- dsp_tools/clients/{ontology_client_live.py → ontology_create_client_live.py} +21 -40
- dsp_tools/clients/ontology_get_client_live.py +66 -0
- dsp_tools/clients/project_client.py +10 -0
- dsp_tools/clients/project_client_live.py +36 -0
- dsp_tools/commands/create/create_on_server/cardinalities.py +14 -8
- dsp_tools/commands/create/create_on_server/lists.py +163 -0
- dsp_tools/commands/create/lists_only.py +45 -0
- dsp_tools/commands/create/models/input_problems.py +13 -0
- dsp_tools/commands/create/models/parsed_project.py +14 -1
- dsp_tools/commands/create/models/rdf_ontology.py +0 -7
- dsp_tools/commands/create/models/server_project_info.py +17 -3
- dsp_tools/commands/create/parsing/parse_lists.py +45 -0
- dsp_tools/commands/create/parsing/parse_project.py +23 -4
- dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +4 -4
- dsp_tools/commands/project/create/project_create_all.py +17 -13
- dsp_tools/commands/project/create/project_create_default_permissions.py +8 -6
- dsp_tools/commands/project/create/project_create_ontologies.py +30 -18
- dsp_tools/commands/project/legacy_models/listnode.py +0 -30
- dsp_tools/commands/validate_data/models/api_responses.py +2 -16
- dsp_tools/commands/validate_data/prepare_data/prepare_data.py +11 -10
- dsp_tools/commands/validate_data/shacl_cli_validator.py +3 -1
- dsp_tools/commands/validate_data/sparql/value_shacl.py +1 -1
- dsp_tools/commands/validate_data/validate_data.py +3 -3
- dsp_tools/commands/validate_data/validation/get_validation_report.py +1 -1
- dsp_tools/commands/validate_data/validation/validate_ontology.py +1 -1
- dsp_tools/commands/xmlupload/models/input_problems.py +1 -1
- dsp_tools/commands/xmlupload/upload_config.py +1 -1
- dsp_tools/commands/xmlupload/xmlupload.py +2 -2
- dsp_tools/error/custom_warnings.py +7 -0
- dsp_tools/error/exceptions.py +25 -2
- dsp_tools/resources/start-stack/docker-compose.yml +23 -23
- dsp_tools/utils/ansi_colors.py +2 -0
- dsp_tools/utils/fuseki_bloating.py +4 -2
- dsp_tools/utils/request_utils.py +31 -0
- dsp_tools/xmllib/models/res.py +2 -0
- {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/METADATA +1 -1
- {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/RECORD +48 -39
- {dsp_tools-17.0.0.post29.dist-info → dsp_tools-18.0.0.post3.dist-info}/WHEEL +1 -1
- dsp_tools/commands/project/create/project_create_lists.py +0 -200
- dsp_tools/commands/validate_data/api_clients.py +0 -124
- {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=
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
90
|
-
parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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("
|
|
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"
|
|
177
|
+
print(f"WARNING: {err_msg}")
|
|
177
178
|
logger.warning(err_msg)
|
|
178
179
|
return None
|
|
179
180
|
|
|
180
|
-
print(f"
|
|
181
|
-
logger.info(f"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
14
|
-
from dsp_tools.
|
|
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,
|
|
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
|
|
40
|
-
parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(
|
|
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 =
|
|
75
|
-
all_lists = list_client.
|
|
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 =
|
|
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:
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
98
|
-
parsed_resources = use_id2iri_mapping_to_replace_ids(parsed_resources, Path(config.
|
|
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)
|
dsp_tools/error/exceptions.py
CHANGED
|
@@ -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
|
|
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."""
|