dsp-tools 17.0.0.post14__py3-none-any.whl → 17.0.0.post21__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/clients/metadata_client.py +24 -0
- dsp_tools/clients/metadata_client_live.py +42 -0
- dsp_tools/clients/ontology_client.py +21 -0
- dsp_tools/clients/ontology_client_live.py +139 -0
- dsp_tools/commands/create/communicate_problems.py +19 -0
- dsp_tools/commands/create/constants.py +6 -3
- dsp_tools/commands/create/create_on_server/cardinalities.py +121 -0
- dsp_tools/commands/create/create_on_server/mappers.py +12 -0
- dsp_tools/commands/create/models/input_problems.py +11 -2
- dsp_tools/commands/create/models/rdf_ontology.py +19 -0
- dsp_tools/commands/create/models/server_project_info.py +25 -0
- dsp_tools/commands/create/parsing/parse_ontology.py +7 -7
- dsp_tools/commands/create/parsing/parse_project.py +1 -1
- dsp_tools/commands/create/parsing/parsing_utils.py +2 -2
- dsp_tools/commands/create/serialisation/__init__.py +0 -0
- dsp_tools/commands/create/serialisation/ontology.py +41 -0
- dsp_tools/commands/project/create/project_create_all.py +35 -25
- dsp_tools/commands/project/create/project_create_ontologies.py +39 -89
- dsp_tools/commands/project/legacy_models/resourceclass.py +0 -33
- dsp_tools/error/exceptions.py +4 -0
- dsp_tools/utils/data_formats/iri_util.py +7 -0
- dsp_tools/utils/rdflib_utils.py +10 -0
- {dsp_tools-17.0.0.post14.dist-info → dsp_tools-17.0.0.post21.dist-info}/METADATA +1 -1
- {dsp_tools-17.0.0.post14.dist-info → dsp_tools-17.0.0.post21.dist-info}/RECORD +27 -15
- /dsp_tools/commands/create/{parsing/parse_lists.py → create_on_server/__init__.py} +0 -0
- {dsp_tools-17.0.0.post14.dist-info → dsp_tools-17.0.0.post21.dist-info}/WHEEL +0 -0
- {dsp_tools-17.0.0.post14.dist-info → dsp_tools-17.0.0.post21.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from enum import auto
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MetadataRetrieval(Enum):
|
|
10
|
+
SUCCESS = auto()
|
|
11
|
+
FAILURE = auto()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class MetadataClient(Protocol):
|
|
16
|
+
"""
|
|
17
|
+
Protocol class/interface for the metadata endpoint in the API.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
server: str
|
|
21
|
+
authentication_client: AuthenticationClient
|
|
22
|
+
|
|
23
|
+
def get_resource_metadata(self, shortcode: str) -> tuple[MetadataRetrieval, list[dict[str, str]]]:
|
|
24
|
+
"""Get all resource metadata from one project."""
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
from dsp_tools.clients.metadata_client import MetadataClient
|
|
8
|
+
from dsp_tools.clients.metadata_client import MetadataRetrieval
|
|
9
|
+
from dsp_tools.utils.request_utils import RequestParameters
|
|
10
|
+
from dsp_tools.utils.request_utils import log_request
|
|
11
|
+
from dsp_tools.utils.request_utils import log_response
|
|
12
|
+
|
|
13
|
+
TIMEOUT = 120
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class MetadataClientLive(MetadataClient):
|
|
18
|
+
server: str
|
|
19
|
+
authentication_client: AuthenticationClient
|
|
20
|
+
|
|
21
|
+
def get_resource_metadata(self, shortcode: str) -> tuple[MetadataRetrieval, list[dict[str, str]]]:
|
|
22
|
+
url = f"{self.server}/v2/metadata/projects/{shortcode}/resources?format=JSON"
|
|
23
|
+
header = {"Authorization": f"Bearer {self.authentication_client.get_token()}"}
|
|
24
|
+
params = RequestParameters(method="GET", url=url, timeout=TIMEOUT, headers=header)
|
|
25
|
+
logger.debug("GET Resource Metadata")
|
|
26
|
+
log_request(params)
|
|
27
|
+
try:
|
|
28
|
+
response = requests.get(
|
|
29
|
+
url=params.url,
|
|
30
|
+
headers=params.headers,
|
|
31
|
+
timeout=params.timeout,
|
|
32
|
+
)
|
|
33
|
+
if response.ok:
|
|
34
|
+
# we log the response separately because if it was successful it will be too big
|
|
35
|
+
log_response(response, include_response_content=False)
|
|
36
|
+
return MetadataRetrieval.SUCCESS, response.json()
|
|
37
|
+
# here the response text is important
|
|
38
|
+
log_response(response)
|
|
39
|
+
return MetadataRetrieval.FAILURE, []
|
|
40
|
+
except Exception as err: # noqa: BLE001 (blind exception)
|
|
41
|
+
logger.error(err)
|
|
42
|
+
return MetadataRetrieval.FAILURE, []
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from typing import Protocol
|
|
3
|
+
|
|
4
|
+
from rdflib import Literal
|
|
5
|
+
|
|
6
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OntologyClient(Protocol):
|
|
10
|
+
"""
|
|
11
|
+
Protocol class/interface for the ontology endpoint in the API.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
server: str
|
|
15
|
+
authentication_client: AuthenticationClient
|
|
16
|
+
|
|
17
|
+
def get_last_modification_date(self, project_iri: str, onto_iri: str) -> str:
|
|
18
|
+
"""Get the last modification date of an ontology"""
|
|
19
|
+
|
|
20
|
+
def post_resource_cardinalities(self, cardinality_graph: dict[str, Any]) -> Literal | None:
|
|
21
|
+
"""Add cardinalities to an existing resource class."""
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from http import HTTPStatus
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from rdflib import Graph
|
|
8
|
+
from rdflib import Literal
|
|
9
|
+
from rdflib import URIRef
|
|
10
|
+
from requests import ReadTimeout
|
|
11
|
+
from requests import Response
|
|
12
|
+
|
|
13
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
14
|
+
from dsp_tools.clients.ontology_client import OntologyClient
|
|
15
|
+
from dsp_tools.error.exceptions import BadCredentialsError
|
|
16
|
+
from dsp_tools.error.exceptions import UnexpectedApiResponseError
|
|
17
|
+
from dsp_tools.utils.rdflib_constants import KNORA_API
|
|
18
|
+
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_request
|
|
21
|
+
from dsp_tools.utils.request_utils import log_response
|
|
22
|
+
|
|
23
|
+
TIMEOUT = 60
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class OntologyClientLive(OntologyClient):
|
|
28
|
+
"""
|
|
29
|
+
Client for the ontology endpoint in the API.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
server: str
|
|
33
|
+
authentication_client: AuthenticationClient
|
|
34
|
+
|
|
35
|
+
def get_last_modification_date(self, project_iri: str, onto_iri: str) -> Literal:
|
|
36
|
+
url = f"{self.server}/v2/ontologies/metadata"
|
|
37
|
+
header = {"X-Knora-Accept-Project": project_iri}
|
|
38
|
+
logger.debug("GET ontology metadata")
|
|
39
|
+
try:
|
|
40
|
+
response = self._get_and_log_request(url, header)
|
|
41
|
+
except (TimeoutError, ReadTimeout) as err:
|
|
42
|
+
log_and_raise_timeouts(err)
|
|
43
|
+
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
|
+
)
|
|
58
|
+
|
|
59
|
+
def post_resource_cardinalities(self, cardinality_graph: dict[str, Any]) -> Literal | None:
|
|
60
|
+
url = f"{self.server}/v2/ontologies/cardinalities"
|
|
61
|
+
|
|
62
|
+
logger.debug("POST resource cardinalities to ontology")
|
|
63
|
+
try:
|
|
64
|
+
response = self._post_and_log_request(url, cardinality_graph)
|
|
65
|
+
except (TimeoutError, ReadTimeout) as err:
|
|
66
|
+
log_and_raise_timeouts(err)
|
|
67
|
+
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
|
|
74
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
75
|
+
raise BadCredentialsError(
|
|
76
|
+
"Only a project or system administrator can add cardinalities to resource classes. "
|
|
77
|
+
"Your permissions are insufficient for this action."
|
|
78
|
+
)
|
|
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
|
|
85
|
+
|
|
86
|
+
def _post_and_log_request(
|
|
87
|
+
self,
|
|
88
|
+
url: str,
|
|
89
|
+
data: dict[str, Any] | None,
|
|
90
|
+
headers: dict[str, str] | None = None,
|
|
91
|
+
) -> Response:
|
|
92
|
+
data_dict, generic_headers = self._prepare_request(data, headers)
|
|
93
|
+
params = RequestParameters("POST", url, TIMEOUT, data_dict, generic_headers)
|
|
94
|
+
log_request(params)
|
|
95
|
+
response = requests.post(
|
|
96
|
+
url=params.url,
|
|
97
|
+
headers=params.headers,
|
|
98
|
+
data=params.data_serialized,
|
|
99
|
+
timeout=params.timeout,
|
|
100
|
+
)
|
|
101
|
+
log_response(response)
|
|
102
|
+
return response
|
|
103
|
+
|
|
104
|
+
def _get_and_log_request(
|
|
105
|
+
self,
|
|
106
|
+
url: str,
|
|
107
|
+
headers: dict[str, str] | None = None,
|
|
108
|
+
) -> Response:
|
|
109
|
+
_, generic_headers = self._prepare_request({}, headers)
|
|
110
|
+
params = RequestParameters(method="GET", url=url, timeout=TIMEOUT, headers=generic_headers)
|
|
111
|
+
log_request(params)
|
|
112
|
+
response = requests.get(
|
|
113
|
+
url=params.url,
|
|
114
|
+
headers=params.headers,
|
|
115
|
+
timeout=params.timeout,
|
|
116
|
+
)
|
|
117
|
+
log_response(response)
|
|
118
|
+
return response
|
|
119
|
+
|
|
120
|
+
def _prepare_request(
|
|
121
|
+
self, data: dict[str, Any] | None, headers: dict[str, str] | None
|
|
122
|
+
) -> tuple[dict[str, Any] | None, dict[str, str]]:
|
|
123
|
+
generic_headers = {
|
|
124
|
+
"Content-Type": "application/json",
|
|
125
|
+
"Authorization": f"Bearer {self.authentication_client.get_token()}",
|
|
126
|
+
}
|
|
127
|
+
data_dict = data if data else None
|
|
128
|
+
if headers:
|
|
129
|
+
generic_headers.update(headers)
|
|
130
|
+
return data_dict, generic_headers
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _parse_last_modification_date(response_text: str, onto_iri: URIRef | None = None) -> Literal | None:
|
|
134
|
+
g = Graph()
|
|
135
|
+
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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from loguru import logger
|
|
2
|
+
|
|
3
|
+
from dsp_tools.commands.create.models.input_problems import CollectedProblems
|
|
4
|
+
from dsp_tools.commands.create.models.input_problems import CreateProblem
|
|
5
|
+
from dsp_tools.utils.ansi_colors import BOLD_RED
|
|
6
|
+
from dsp_tools.utils.ansi_colors import RED
|
|
7
|
+
from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def print_problem_collection(problem_collection: CollectedProblems) -> None:
|
|
11
|
+
individual_problems = _create_individual_problem_strings(problem_collection.problems)
|
|
12
|
+
logger.error(problem_collection.header, individual_problems)
|
|
13
|
+
print(BOLD_RED, problem_collection.header, RESET_TO_DEFAULT)
|
|
14
|
+
print(RED, individual_problems, RESET_TO_DEFAULT)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _create_individual_problem_strings(problems: list[CreateProblem]) -> str:
|
|
18
|
+
str_list = [f"{p.problematic_object}: {p.problem!s}" for p in problems]
|
|
19
|
+
return " - " + "\n - ".join(str_list)
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
SALSAH_GUI = "http://api.knora.org/ontology/salsah-gui/v2#"
|
|
1
|
+
from rdflib import Namespace
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
KNORA_API_STR = "http://api.knora.org/ontology/knora-api/v2#"
|
|
4
|
+
SALSAH_GUI_STR = "http://api.knora.org/ontology/salsah-gui/v2#"
|
|
5
|
+
SALSAH_GUI = Namespace(SALSAH_GUI_STR)
|
|
6
|
+
|
|
7
|
+
UNIVERSAL_PREFIXES = {"knora-api": KNORA_API_STR, "salsah-gui": SALSAH_GUI_STR}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from rdflib import Literal
|
|
5
|
+
from rdflib import URIRef
|
|
6
|
+
|
|
7
|
+
from dsp_tools.clients.ontology_client import OntologyClient
|
|
8
|
+
from dsp_tools.clients.ontology_client_live import OntologyClientLive
|
|
9
|
+
from dsp_tools.commands.create.models.input_problems import CollectedProblems
|
|
10
|
+
from dsp_tools.commands.create.models.input_problems import CreateProblem
|
|
11
|
+
from dsp_tools.commands.create.models.input_problems import ProblemType
|
|
12
|
+
from dsp_tools.commands.create.models.input_problems import UploadProblem
|
|
13
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedClassCardinalities
|
|
14
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
|
|
15
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedPropertyCardinality
|
|
16
|
+
from dsp_tools.commands.create.models.server_project_info import CreatedIriCollection
|
|
17
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
18
|
+
from dsp_tools.commands.create.serialisation.ontology import _make_one_cardinality_graph
|
|
19
|
+
from dsp_tools.commands.create.serialisation.ontology import make_ontology_base_graph
|
|
20
|
+
from dsp_tools.utils.data_formats.iri_util import from_dsp_iri_to_prefixed_iri
|
|
21
|
+
from dsp_tools.utils.rdflib_utils import serialise_json
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def add_all_cardinalities(
|
|
25
|
+
ontologies: list[ParsedOntology],
|
|
26
|
+
project_iri_lookup: ProjectIriLookup,
|
|
27
|
+
created_iris: CreatedIriCollection,
|
|
28
|
+
onto_client: OntologyClientLive,
|
|
29
|
+
) -> CollectedProblems | None:
|
|
30
|
+
all_problems = []
|
|
31
|
+
for onto in ontologies:
|
|
32
|
+
onto_iri = project_iri_lookup.onto_iris.get(onto.name)
|
|
33
|
+
# we do not inform about onto failures here, as it will have been done upstream
|
|
34
|
+
if onto_iri:
|
|
35
|
+
last_mod_date = onto_client.get_last_modification_date(project_iri_lookup.project_iri, onto_iri)
|
|
36
|
+
problems = _add_all_cardinalities_for_one_onto(
|
|
37
|
+
cardinalities=onto.cardinalities,
|
|
38
|
+
onto_iri=URIRef(onto_iri),
|
|
39
|
+
last_modification_date=last_mod_date,
|
|
40
|
+
onto_client=onto_client,
|
|
41
|
+
created_iris=created_iris,
|
|
42
|
+
)
|
|
43
|
+
all_problems.extend(problems)
|
|
44
|
+
if all_problems:
|
|
45
|
+
return CollectedProblems("During the cardinality creation the following problems occurred:", all_problems)
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _add_all_cardinalities_for_one_onto(
|
|
50
|
+
cardinalities: list[ParsedClassCardinalities],
|
|
51
|
+
onto_iri: URIRef,
|
|
52
|
+
last_modification_date: Literal,
|
|
53
|
+
onto_client: OntologyClient,
|
|
54
|
+
created_iris: CreatedIriCollection,
|
|
55
|
+
) -> list[CreateProblem]:
|
|
56
|
+
problems: list[CreateProblem] = []
|
|
57
|
+
for c in cardinalities:
|
|
58
|
+
# we do not inform about classes failures here, as it will have been done upstream
|
|
59
|
+
if c.class_iri not in created_iris.classes:
|
|
60
|
+
logger.warning(f"CARDINALITY: Class '{c.class_iri}' not in successes, no cardinalities added.")
|
|
61
|
+
continue
|
|
62
|
+
last_modification_date, creation_problems = _add_cardinalities_for_one_class(
|
|
63
|
+
resource_card=c,
|
|
64
|
+
onto_iri=onto_iri,
|
|
65
|
+
last_modification_date=last_modification_date,
|
|
66
|
+
onto_client=onto_client,
|
|
67
|
+
successful_props=created_iris.properties,
|
|
68
|
+
)
|
|
69
|
+
problems.extend(creation_problems)
|
|
70
|
+
return problems
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _add_cardinalities_for_one_class(
|
|
74
|
+
resource_card: ParsedClassCardinalities,
|
|
75
|
+
onto_iri: URIRef,
|
|
76
|
+
last_modification_date: Literal,
|
|
77
|
+
onto_client: OntologyClient,
|
|
78
|
+
successful_props: set[str],
|
|
79
|
+
) -> tuple[Literal, list[UploadProblem]]:
|
|
80
|
+
res_iri = URIRef(resource_card.class_iri)
|
|
81
|
+
problems = []
|
|
82
|
+
for one_card in resource_card.cards:
|
|
83
|
+
if one_card.propname not in successful_props:
|
|
84
|
+
logger.warning(f"CARDINALITY: Property '{one_card.propname}' not in successes, no cardinality added.")
|
|
85
|
+
continue
|
|
86
|
+
last_modification_date, problem = _add_one_cardinality(
|
|
87
|
+
one_card, res_iri, onto_iri, last_modification_date, onto_client
|
|
88
|
+
)
|
|
89
|
+
if problem:
|
|
90
|
+
problems.append(problem)
|
|
91
|
+
return last_modification_date, problems
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _add_one_cardinality(
|
|
95
|
+
card: ParsedPropertyCardinality,
|
|
96
|
+
res_iri: URIRef,
|
|
97
|
+
onto_iri: URIRef,
|
|
98
|
+
last_modification_date: Literal,
|
|
99
|
+
onto_client: OntologyClient,
|
|
100
|
+
) -> tuple[Literal, UploadProblem | None]:
|
|
101
|
+
card_serialised = _serialise_card(card, res_iri, onto_iri, last_modification_date)
|
|
102
|
+
new_mod_date = onto_client.post_resource_cardinalities(card_serialised)
|
|
103
|
+
if not new_mod_date:
|
|
104
|
+
prefixed_cls = from_dsp_iri_to_prefixed_iri(str(res_iri))
|
|
105
|
+
prefixed_prop = from_dsp_iri_to_prefixed_iri(card.propname)
|
|
106
|
+
return last_modification_date, UploadProblem(
|
|
107
|
+
f"{prefixed_cls} / {prefixed_prop}",
|
|
108
|
+
ProblemType.CARDINALITY_COULD_NOT_BE_ADDED,
|
|
109
|
+
)
|
|
110
|
+
return new_mod_date, None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _serialise_card(
|
|
114
|
+
card: ParsedPropertyCardinality, res_iri: URIRef, onto_iri: URIRef, last_modification_date: Literal
|
|
115
|
+
) -> dict[str, Any]:
|
|
116
|
+
onto_g = make_ontology_base_graph(onto_iri, last_modification_date)
|
|
117
|
+
onto_serialised = next(iter(serialise_json(onto_g)))
|
|
118
|
+
card_g = _make_one_cardinality_graph(card, res_iri)
|
|
119
|
+
card_serialised = serialise_json(card_g)
|
|
120
|
+
onto_serialised["@graph"] = card_serialised
|
|
121
|
+
return onto_serialised
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from rdflib import OWL
|
|
2
|
+
from rdflib import Literal
|
|
3
|
+
|
|
4
|
+
from dsp_tools.commands.create.models.parsed_ontology import Cardinality
|
|
5
|
+
from dsp_tools.commands.create.models.rdf_ontology import RdfCardinalityRestriction
|
|
6
|
+
|
|
7
|
+
PARSED_CARDINALITY_TO_RDF = {
|
|
8
|
+
Cardinality.C_1: RdfCardinalityRestriction(OWL.cardinality, Literal(1)),
|
|
9
|
+
Cardinality.C_0_1: RdfCardinalityRestriction(OWL.maxCardinality, Literal(1)),
|
|
10
|
+
Cardinality.C_1_N: RdfCardinalityRestriction(OWL.minCardinality, Literal(1)),
|
|
11
|
+
Cardinality.C_0_N: RdfCardinalityRestriction(OWL.minCardinality, Literal(0)),
|
|
12
|
+
}
|
|
@@ -7,17 +7,26 @@ from enum import StrEnum
|
|
|
7
7
|
@dataclass
|
|
8
8
|
class CollectedProblems:
|
|
9
9
|
header: str
|
|
10
|
-
problems: list[
|
|
10
|
+
problems: list[CreateProblem]
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@dataclass
|
|
14
|
-
class
|
|
14
|
+
class CreateProblem:
|
|
15
15
|
problematic_object: str
|
|
16
16
|
problem: ProblemType
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
@dataclass
|
|
20
|
+
class InputProblem(CreateProblem): ...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class UploadProblem(CreateProblem): ...
|
|
25
|
+
|
|
26
|
+
|
|
19
27
|
class ProblemType(StrEnum):
|
|
20
28
|
PREFIX_COULD_NOT_BE_RESOLVED = (
|
|
21
29
|
"The prefix used is not defined in the 'prefix' section of the file, "
|
|
22
30
|
"nor does it belong to one of the project ontologies."
|
|
23
31
|
)
|
|
32
|
+
CARDINALITY_COULD_NOT_BE_ADDED = "The cardinality could not be added."
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from rdflib import Literal
|
|
6
|
+
from rdflib import URIRef
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class RdfResourceCardinality:
|
|
11
|
+
resource_iri: URIRef
|
|
12
|
+
on_property: URIRef
|
|
13
|
+
cardinality: RdfCardinalityRestriction
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class RdfCardinalityRestriction:
|
|
18
|
+
owl_property: URIRef
|
|
19
|
+
cardinality_value: Literal
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import field
|
|
3
|
+
|
|
4
|
+
from dsp_tools.commands.create.constants import KNORA_API_STR
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ProjectIriLookup:
|
|
9
|
+
project_iri: str
|
|
10
|
+
onto_iris: dict[str, str] = field(default_factory=dict)
|
|
11
|
+
|
|
12
|
+
def add_onto(self, name: str, iri: str) -> None:
|
|
13
|
+
self.onto_iris[name] = iri
|
|
14
|
+
|
|
15
|
+
def get_onto_iri(self, name: str) -> str | None:
|
|
16
|
+
return self.onto_iris.get(name)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class CreatedIriCollection:
|
|
21
|
+
classes: set[str] = field(default_factory=set)
|
|
22
|
+
properties: set[str] = field(default_factory=set)
|
|
23
|
+
|
|
24
|
+
def __post_init__(self) -> None:
|
|
25
|
+
self.properties.update({f"{KNORA_API_STR}seqnum", f"{KNORA_API_STR}isPartOf"})
|
|
@@ -2,7 +2,7 @@ from typing import Any
|
|
|
2
2
|
from typing import cast
|
|
3
3
|
|
|
4
4
|
from dsp_tools.commands.create.models.input_problems import CollectedProblems
|
|
5
|
-
from dsp_tools.commands.create.models.input_problems import
|
|
5
|
+
from dsp_tools.commands.create.models.input_problems import CreateProblem
|
|
6
6
|
from dsp_tools.commands.create.models.input_problems import ProblemType
|
|
7
7
|
from dsp_tools.commands.create.models.parsed_ontology import Cardinality
|
|
8
8
|
from dsp_tools.commands.create.models.parsed_ontology import ParsedClass
|
|
@@ -46,7 +46,7 @@ def parse_ontology(ontology_json: dict[str, Any], prefixes: dict[str, str]) -> P
|
|
|
46
46
|
|
|
47
47
|
def _parse_properties(
|
|
48
48
|
properties_list: list[dict[str, Any]], current_onto_prefix: str
|
|
49
|
-
) -> tuple[list[ParsedProperty], list[
|
|
49
|
+
) -> tuple[list[ParsedProperty], list[CreateProblem]]:
|
|
50
50
|
parsed = []
|
|
51
51
|
for prop in properties_list:
|
|
52
52
|
parsed.append(ParsedProperty(f"{current_onto_prefix}{prop['name']}", prop))
|
|
@@ -55,7 +55,7 @@ def _parse_properties(
|
|
|
55
55
|
|
|
56
56
|
def _parse_classes(
|
|
57
57
|
classes_list: list[dict[str, Any]], current_onto_prefix: str
|
|
58
|
-
) -> tuple[list[ParsedClass], list[
|
|
58
|
+
) -> tuple[list[ParsedClass], list[CreateProblem]]:
|
|
59
59
|
parsed = []
|
|
60
60
|
for cls in classes_list:
|
|
61
61
|
parsed.append(ParsedClass(f"{current_onto_prefix}{cls['name']}", cls))
|
|
@@ -64,7 +64,7 @@ def _parse_classes(
|
|
|
64
64
|
|
|
65
65
|
def _parse_cardinalities(
|
|
66
66
|
classes_list: list[dict[str, Any]], current_onto_prefix: str, prefixes: dict[str, str]
|
|
67
|
-
) -> tuple[list[ParsedClassCardinalities], list[
|
|
67
|
+
) -> tuple[list[ParsedClassCardinalities], list[CreateProblem]]:
|
|
68
68
|
parsed = []
|
|
69
69
|
failures = []
|
|
70
70
|
for c in classes_list:
|
|
@@ -79,7 +79,7 @@ def _parse_cardinalities(
|
|
|
79
79
|
|
|
80
80
|
def _parse_one_class_cardinality(
|
|
81
81
|
cls_json: dict[str, Any], current_onto_prefix: str, prefixes: dict[str, str]
|
|
82
|
-
) -> ParsedClassCardinalities | list[
|
|
82
|
+
) -> ParsedClassCardinalities | list[CreateProblem]:
|
|
83
83
|
failures = []
|
|
84
84
|
parsed = []
|
|
85
85
|
for c in cls_json["cardinalities"]:
|
|
@@ -96,10 +96,10 @@ def _parse_one_class_cardinality(
|
|
|
96
96
|
|
|
97
97
|
def _parse_one_cardinality(
|
|
98
98
|
card_json: dict[str, str | int], current_onto_prefix: str, prefixes: dict[str, str]
|
|
99
|
-
) -> ParsedPropertyCardinality |
|
|
99
|
+
) -> ParsedPropertyCardinality | CreateProblem:
|
|
100
100
|
prp_name = cast(str, card_json["propname"])
|
|
101
101
|
if not (resolved := resolve_to_absolute_iri(prp_name, current_onto_prefix, prefixes)):
|
|
102
|
-
return
|
|
102
|
+
return CreateProblem(prp_name, ProblemType.PREFIX_COULD_NOT_BE_RESOLVED)
|
|
103
103
|
gui = cast(int | None, card_json.get("gui_order"))
|
|
104
104
|
return ParsedPropertyCardinality(
|
|
105
105
|
propname=resolved,
|
|
@@ -56,7 +56,7 @@ def _parse_metadata(project_json: dict[str, Any]) -> ParsedProjectMetadata:
|
|
|
56
56
|
longname=project_json["longname"],
|
|
57
57
|
descriptions=project_json["descriptions"],
|
|
58
58
|
keywords=project_json["keywords"],
|
|
59
|
-
enabled_licenses=project_json
|
|
59
|
+
enabled_licenses=project_json.get("enabled_licenses", []),
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
|
|
@@ -2,7 +2,7 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
import regex
|
|
4
4
|
|
|
5
|
-
from dsp_tools.commands.create.constants import
|
|
5
|
+
from dsp_tools.commands.create.constants import KNORA_API_STR
|
|
6
6
|
from dsp_tools.commands.create.constants import UNIVERSAL_PREFIXES
|
|
7
7
|
from dsp_tools.utils.data_formats.uri_util import is_uri
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ def resolve_to_absolute_iri(prefixed: str, current_onto: str, prefix_lookup: dic
|
|
|
14
14
|
return f"{current_onto}{prefixed.lstrip(':')}"
|
|
15
15
|
segments = prefixed.split(":", maxsplit=1)
|
|
16
16
|
if len(segments) == 1:
|
|
17
|
-
return f"{
|
|
17
|
+
return f"{KNORA_API_STR}{segments[0]}"
|
|
18
18
|
if not (found := prefix_lookup.get(segments[0])):
|
|
19
19
|
return None
|
|
20
20
|
return f"{found}{segments[1]}"
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from rdflib import OWL
|
|
2
|
+
from rdflib import RDF
|
|
3
|
+
from rdflib import RDFS
|
|
4
|
+
from rdflib import BNode
|
|
5
|
+
from rdflib import Graph
|
|
6
|
+
from rdflib import Literal
|
|
7
|
+
from rdflib import URIRef
|
|
8
|
+
|
|
9
|
+
from dsp_tools.commands.create.constants import SALSAH_GUI
|
|
10
|
+
from dsp_tools.commands.create.create_on_server.mappers import PARSED_CARDINALITY_TO_RDF
|
|
11
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedPropertyCardinality
|
|
12
|
+
from dsp_tools.utils.rdflib_constants import KNORA_API
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def make_ontology_base_graph(onto_iri: URIRef, last_modification_date: Literal) -> Graph:
|
|
16
|
+
g = Graph()
|
|
17
|
+
g.add((onto_iri, RDF.type, OWL.Ontology))
|
|
18
|
+
g.add((onto_iri, KNORA_API.lastModificationDate, last_modification_date))
|
|
19
|
+
return g
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def make_cardinality_graph_for_request(
|
|
23
|
+
card: ParsedPropertyCardinality, res_iri: URIRef, onto_iri: URIRef, last_modification_date: Literal
|
|
24
|
+
) -> Graph:
|
|
25
|
+
g = make_ontology_base_graph(onto_iri, last_modification_date)
|
|
26
|
+
g += _make_one_cardinality_graph(card, res_iri)
|
|
27
|
+
return g
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _make_one_cardinality_graph(card: ParsedPropertyCardinality, res_iri: URIRef) -> Graph:
|
|
31
|
+
card_info = PARSED_CARDINALITY_TO_RDF[card.cardinality]
|
|
32
|
+
g = Graph()
|
|
33
|
+
bn_card = BNode()
|
|
34
|
+
g.add((res_iri, RDF.type, OWL.Class))
|
|
35
|
+
g.add((res_iri, RDFS.subClassOf, bn_card))
|
|
36
|
+
g.add((bn_card, RDF.type, OWL.Restriction))
|
|
37
|
+
g.add((bn_card, card_info.owl_property, card_info.cardinality_value))
|
|
38
|
+
g.add((bn_card, OWL.onProperty, URIRef(card.propname)))
|
|
39
|
+
if card.gui_order is not None:
|
|
40
|
+
g.add((bn_card, SALSAH_GUI.guiOrder, Literal(card.gui_order)))
|
|
41
|
+
return g
|
|
@@ -4,6 +4,7 @@ of the project, the creation of groups, users, lists, resource classes, properti
|
|
|
4
4
|
import os
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import Any
|
|
7
|
+
from typing import cast
|
|
7
8
|
from urllib.parse import quote_plus
|
|
8
9
|
|
|
9
10
|
from dotenv import load_dotenv
|
|
@@ -13,11 +14,14 @@ from dsp_tools.cli.args import ServerCredentials
|
|
|
13
14
|
from dsp_tools.clients.authentication_client_live import AuthenticationClientLive
|
|
14
15
|
from dsp_tools.clients.connection import Connection
|
|
15
16
|
from dsp_tools.clients.connection_live import ConnectionLive
|
|
17
|
+
from dsp_tools.commands.create.communicate_problems import print_problem_collection
|
|
18
|
+
from dsp_tools.commands.create.models.parsed_project import ParsedProject
|
|
19
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
20
|
+
from dsp_tools.commands.create.parsing.parse_project import parse_project
|
|
16
21
|
from dsp_tools.commands.project.create.parse_project import parse_project_json
|
|
17
22
|
from dsp_tools.commands.project.create.project_create_default_permissions import create_default_permissions
|
|
18
23
|
from dsp_tools.commands.project.create.project_create_lists import create_lists_on_server
|
|
19
24
|
from dsp_tools.commands.project.create.project_create_ontologies import create_ontologies
|
|
20
|
-
from dsp_tools.commands.project.create.project_validate import validate_project
|
|
21
25
|
from dsp_tools.commands.project.legacy_models.context import Context
|
|
22
26
|
from dsp_tools.commands.project.legacy_models.group import Group
|
|
23
27
|
from dsp_tools.commands.project.legacy_models.project import Project
|
|
@@ -34,7 +38,7 @@ from dsp_tools.utils.json_parsing import parse_json_input
|
|
|
34
38
|
load_dotenv()
|
|
35
39
|
|
|
36
40
|
|
|
37
|
-
def create_project( # noqa: PLR0915 (too many statements)
|
|
41
|
+
def create_project( # noqa: PLR0915,PLR0912 (too many statements & branches)
|
|
38
42
|
project_file_as_path_or_parsed: str | Path | dict[str, Any],
|
|
39
43
|
creds: ServerCredentials,
|
|
40
44
|
verbose: bool = False,
|
|
@@ -69,38 +73,41 @@ def create_project( # noqa: PLR0915 (too many statements)
|
|
|
69
73
|
knora_api_prefix = "knora-api:"
|
|
70
74
|
overall_success = True
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
# includes validation
|
|
77
|
+
parsed_project = parse_project(project_file_as_path_or_parsed, creds.server)
|
|
78
|
+
if not isinstance(parsed_project, ParsedProject):
|
|
79
|
+
for problem in parsed_project:
|
|
80
|
+
print_problem_collection(problem)
|
|
81
|
+
return False
|
|
73
82
|
|
|
83
|
+
# required for the legacy code
|
|
84
|
+
project_json = parse_json_input(project_file_as_path_or_parsed=project_file_as_path_or_parsed)
|
|
74
85
|
context = Context(project_json.get("prefixes", {}))
|
|
75
|
-
|
|
76
|
-
# validate against JSON schema
|
|
77
|
-
validate_project(project_json)
|
|
78
|
-
print(" JSON project file is syntactically correct and passed validation.")
|
|
79
|
-
logger.info("JSON project file is syntactically correct and passed validation.")
|
|
80
|
-
|
|
81
|
-
project = parse_project_json(project_json)
|
|
86
|
+
legacy_project = parse_project_json(project_json)
|
|
82
87
|
|
|
83
88
|
auth = AuthenticationClientLive(creds.server, creds.user, creds.password)
|
|
84
89
|
con = ConnectionLive(creds.server, auth)
|
|
85
90
|
|
|
86
91
|
# create project on DSP server
|
|
87
|
-
info_str = f"Create project '{
|
|
92
|
+
info_str = f"Create project '{legacy_project.metadata.shortname}' ({legacy_project.metadata.shortcode})..."
|
|
88
93
|
print(info_str)
|
|
89
94
|
logger.info(info_str)
|
|
90
95
|
project_remote, success = _create_project_on_server(
|
|
91
|
-
project_definition=
|
|
96
|
+
project_definition=legacy_project.metadata,
|
|
92
97
|
con=con,
|
|
93
98
|
)
|
|
99
|
+
project_iri = cast(str, project_remote.iri)
|
|
100
|
+
project_iri_lookup = ProjectIriLookup(project_iri)
|
|
94
101
|
if not success:
|
|
95
102
|
overall_success = False
|
|
96
103
|
|
|
97
104
|
# create the lists
|
|
98
105
|
names_and_iris_of_list_nodes: dict[str, Any] = {}
|
|
99
|
-
if
|
|
106
|
+
if legacy_project.lists:
|
|
100
107
|
print("Create lists...")
|
|
101
108
|
logger.info("Create lists...")
|
|
102
109
|
names_and_iris_of_list_nodes, success = create_lists_on_server(
|
|
103
|
-
lists_to_create=
|
|
110
|
+
lists_to_create=legacy_project.lists,
|
|
104
111
|
con=con,
|
|
105
112
|
project_remote=project_remote,
|
|
106
113
|
)
|
|
@@ -109,24 +116,24 @@ def create_project( # noqa: PLR0915 (too many statements)
|
|
|
109
116
|
|
|
110
117
|
# create the groups
|
|
111
118
|
current_project_groups: dict[str, Group] = {}
|
|
112
|
-
if
|
|
119
|
+
if legacy_project.groups:
|
|
113
120
|
print("Create groups...")
|
|
114
121
|
logger.info("Create groups...")
|
|
115
122
|
current_project_groups, success = _create_groups(
|
|
116
123
|
con=con,
|
|
117
|
-
groups=
|
|
124
|
+
groups=legacy_project.groups,
|
|
118
125
|
project=project_remote,
|
|
119
126
|
)
|
|
120
127
|
if not success:
|
|
121
128
|
overall_success = False
|
|
122
129
|
|
|
123
130
|
# create or update the users
|
|
124
|
-
if
|
|
131
|
+
if legacy_project.users:
|
|
125
132
|
print("Create users...")
|
|
126
133
|
logger.info("Create users...")
|
|
127
134
|
success = _create_users(
|
|
128
135
|
con=con,
|
|
129
|
-
users_section=
|
|
136
|
+
users_section=legacy_project.users,
|
|
130
137
|
current_project_groups=current_project_groups,
|
|
131
138
|
current_project=project_remote,
|
|
132
139
|
verbose=verbose,
|
|
@@ -140,9 +147,12 @@ def create_project( # noqa: PLR0915 (too many statements)
|
|
|
140
147
|
context=context,
|
|
141
148
|
knora_api_prefix=knora_api_prefix,
|
|
142
149
|
names_and_iris_of_list_nodes=names_and_iris_of_list_nodes,
|
|
143
|
-
ontology_definitions=
|
|
150
|
+
ontology_definitions=legacy_project.ontologies,
|
|
144
151
|
project_remote=project_remote,
|
|
145
152
|
verbose=verbose,
|
|
153
|
+
parsed_ontologies=parsed_project.ontologies,
|
|
154
|
+
project_iri_lookup=project_iri_lookup,
|
|
155
|
+
auth=auth,
|
|
146
156
|
)
|
|
147
157
|
if not success:
|
|
148
158
|
overall_success = False
|
|
@@ -151,9 +161,9 @@ def create_project( # noqa: PLR0915 (too many statements)
|
|
|
151
161
|
perm_client = PermissionsClient(auth, str(project_remote.iri))
|
|
152
162
|
success = create_default_permissions(
|
|
153
163
|
perm_client,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
legacy_project.metadata.default_permissions,
|
|
165
|
+
legacy_project.metadata.default_permissions_overrule,
|
|
166
|
+
legacy_project.metadata.shortcode,
|
|
157
167
|
)
|
|
158
168
|
if not success:
|
|
159
169
|
overall_success = False
|
|
@@ -161,15 +171,15 @@ def create_project( # noqa: PLR0915 (too many statements)
|
|
|
161
171
|
# final steps
|
|
162
172
|
if overall_success:
|
|
163
173
|
msg = (
|
|
164
|
-
f"Successfully created project '{
|
|
165
|
-
f"({
|
|
174
|
+
f"Successfully created project '{legacy_project.metadata.shortname}' "
|
|
175
|
+
f"({legacy_project.metadata.shortcode}) with all its ontologies. "
|
|
166
176
|
f"There were no problems during the creation process."
|
|
167
177
|
)
|
|
168
178
|
print(f"========================================================\n{msg}")
|
|
169
179
|
logger.info(msg)
|
|
170
180
|
else:
|
|
171
181
|
msg = (
|
|
172
|
-
f"The project '{
|
|
182
|
+
f"The project '{legacy_project.metadata.shortname}' ({legacy_project.metadata.shortcode}) "
|
|
173
183
|
f"with its ontologies could be created, "
|
|
174
184
|
f"but during the creation process, some problems occurred. Please carefully check the console output."
|
|
175
185
|
)
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from typing import Optional
|
|
3
|
+
from typing import cast
|
|
3
4
|
|
|
4
5
|
import regex
|
|
5
6
|
from loguru import logger
|
|
6
7
|
|
|
8
|
+
from dsp_tools.clients.authentication_client import AuthenticationClient
|
|
7
9
|
from dsp_tools.clients.connection import Connection
|
|
10
|
+
from dsp_tools.clients.ontology_client_live import OntologyClientLive
|
|
11
|
+
from dsp_tools.commands.create.communicate_problems import print_problem_collection
|
|
12
|
+
from dsp_tools.commands.create.create_on_server.cardinalities import add_all_cardinalities
|
|
13
|
+
from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
|
|
14
|
+
from dsp_tools.commands.create.models.server_project_info import CreatedIriCollection
|
|
15
|
+
from dsp_tools.commands.create.models.server_project_info import ProjectIriLookup
|
|
8
16
|
from dsp_tools.commands.project.legacy_models.context import Context
|
|
9
|
-
from dsp_tools.commands.project.legacy_models.helpers import Cardinality
|
|
10
17
|
from dsp_tools.commands.project.legacy_models.ontology import Ontology
|
|
11
18
|
from dsp_tools.commands.project.legacy_models.project import Project
|
|
12
19
|
from dsp_tools.commands.project.legacy_models.propertyclass import PropertyClass
|
|
@@ -25,6 +32,9 @@ def create_ontologies(
|
|
|
25
32
|
ontology_definitions: list[dict[str, Any]],
|
|
26
33
|
project_remote: Project,
|
|
27
34
|
verbose: bool,
|
|
35
|
+
parsed_ontologies: list[ParsedOntology],
|
|
36
|
+
project_iri_lookup: ProjectIriLookup,
|
|
37
|
+
auth: AuthenticationClient,
|
|
28
38
|
) -> bool:
|
|
29
39
|
"""
|
|
30
40
|
Iterates over the ontologies in a JSON project file and creates the ontologies that don't exist on the DSP server
|
|
@@ -39,6 +49,9 @@ def create_ontologies(
|
|
|
39
49
|
ontology_definitions: the "ontologies" section of the parsed JSON project file
|
|
40
50
|
project_remote: representation of the project on the DSP server
|
|
41
51
|
verbose: verbose switch
|
|
52
|
+
parsed_ontologies: parsed ontologies
|
|
53
|
+
project_iri_lookup: lookup for IRIs
|
|
54
|
+
auth: Authentication Client
|
|
42
55
|
|
|
43
56
|
Raises:
|
|
44
57
|
InputError: if an error occurs during the creation of an ontology.
|
|
@@ -47,6 +60,8 @@ def create_ontologies(
|
|
|
47
60
|
Returns:
|
|
48
61
|
True if everything went smoothly, False otherwise
|
|
49
62
|
"""
|
|
63
|
+
success_collection = CreatedIriCollection()
|
|
64
|
+
onto_client = OntologyClientLive(auth.server, auth)
|
|
50
65
|
|
|
51
66
|
overall_success = True
|
|
52
67
|
|
|
@@ -60,6 +75,9 @@ def create_ontologies(
|
|
|
60
75
|
logger.exception(err_msg)
|
|
61
76
|
project_ontologies = []
|
|
62
77
|
|
|
78
|
+
for existing_onto in project_ontologies:
|
|
79
|
+
project_iri_lookup.add_onto(existing_onto.name, existing_onto.iri)
|
|
80
|
+
|
|
63
81
|
created_ontos: list[tuple[dict[str, Any], Ontology, dict[str, ResourceClass]]] = []
|
|
64
82
|
for ontology_definition in ontology_definitions:
|
|
65
83
|
ontology_remote = _create_ontology(
|
|
@@ -75,6 +93,8 @@ def create_ontologies(
|
|
|
75
93
|
if not ontology_remote:
|
|
76
94
|
overall_success = False
|
|
77
95
|
continue
|
|
96
|
+
else:
|
|
97
|
+
project_iri_lookup.add_onto(ontology_remote.name, ontology_remote.iri)
|
|
78
98
|
|
|
79
99
|
# add the empty resource classes to the remote ontology
|
|
80
100
|
last_modification_date, remote_res_classes, success = _add_resource_classes_to_remote_ontology(
|
|
@@ -85,11 +105,12 @@ def create_ontologies(
|
|
|
85
105
|
last_modification_date=ontology_remote.lastModificationDate,
|
|
86
106
|
verbose=verbose,
|
|
87
107
|
)
|
|
108
|
+
success_collection.classes.update(set(remote_res_classes.keys()))
|
|
88
109
|
if not success:
|
|
89
110
|
overall_success = False
|
|
90
111
|
|
|
91
112
|
# add the property classes to the remote ontology
|
|
92
|
-
last_modification_date, success = _add_property_classes_to_remote_ontology(
|
|
113
|
+
last_modification_date, success, property_successes = _add_property_classes_to_remote_ontology(
|
|
93
114
|
onto_name=ontology_definition["name"],
|
|
94
115
|
property_definitions=ontology_definition.get("properties", []),
|
|
95
116
|
ontology_remote=ontology_remote,
|
|
@@ -99,22 +120,21 @@ def create_ontologies(
|
|
|
99
120
|
knora_api_prefix=knora_api_prefix,
|
|
100
121
|
verbose=verbose,
|
|
101
122
|
)
|
|
123
|
+
success_collection.properties.update(property_successes)
|
|
102
124
|
created_ontos.append((ontology_definition, ontology_remote, remote_res_classes))
|
|
103
125
|
if not success:
|
|
104
126
|
overall_success = False
|
|
105
127
|
|
|
106
128
|
print("Add cardinalities to resource classes...")
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
)
|
|
116
|
-
if not success:
|
|
117
|
-
overall_success = False
|
|
129
|
+
problems = add_all_cardinalities(
|
|
130
|
+
ontologies=parsed_ontologies,
|
|
131
|
+
project_iri_lookup=project_iri_lookup,
|
|
132
|
+
created_iris=success_collection,
|
|
133
|
+
onto_client=onto_client,
|
|
134
|
+
)
|
|
135
|
+
if problems:
|
|
136
|
+
overall_success = False
|
|
137
|
+
print_problem_collection(problems)
|
|
118
138
|
|
|
119
139
|
return overall_success
|
|
120
140
|
|
|
@@ -297,7 +317,7 @@ def _add_property_classes_to_remote_ontology(
|
|
|
297
317
|
last_modification_date: DateTimeStamp,
|
|
298
318
|
knora_api_prefix: str,
|
|
299
319
|
verbose: bool,
|
|
300
|
-
) -> tuple[DateTimeStamp, bool]:
|
|
320
|
+
) -> tuple[DateTimeStamp, bool, set[str]]:
|
|
301
321
|
"""
|
|
302
322
|
Creates the property classes defined in the "properties" section of an ontology. The
|
|
303
323
|
containing project and the containing ontology must already be existing on the DSP server.
|
|
@@ -317,6 +337,7 @@ def _add_property_classes_to_remote_ontology(
|
|
|
317
337
|
Returns:
|
|
318
338
|
a tuple consisting of the last modification date of the ontology, and the success status
|
|
319
339
|
"""
|
|
340
|
+
property_successes = set()
|
|
320
341
|
overall_success = True
|
|
321
342
|
print(" Create property classes...")
|
|
322
343
|
logger.info("Create property classes...")
|
|
@@ -370,11 +391,13 @@ def _add_property_classes_to_remote_ontology(
|
|
|
370
391
|
comment=LangString(prop_class["comments"]) if prop_class.get("comments") else None,
|
|
371
392
|
)
|
|
372
393
|
try:
|
|
373
|
-
last_modification_date,
|
|
394
|
+
last_modification_date, prop_class_created = prop_class_local.create(last_modification_date)
|
|
374
395
|
ontology_remote.lastModificationDate = last_modification_date
|
|
375
396
|
if verbose:
|
|
376
397
|
print(f" Created property class '{prop_class['name']}'")
|
|
377
398
|
logger.info(f"Created property class '{prop_class['name']}'")
|
|
399
|
+
prop_iri = cast(str, prop_class_created.iri)
|
|
400
|
+
property_successes.add(prop_iri)
|
|
378
401
|
except BaseError as err:
|
|
379
402
|
err_msg = f"Unable to create property class '{prop_class['name']}'"
|
|
380
403
|
if found := regex.search(
|
|
@@ -386,7 +409,7 @@ def _add_property_classes_to_remote_ontology(
|
|
|
386
409
|
logger.exception(err_msg)
|
|
387
410
|
overall_success = False
|
|
388
411
|
|
|
389
|
-
return last_modification_date, overall_success
|
|
412
|
+
return last_modification_date, overall_success, property_successes
|
|
390
413
|
|
|
391
414
|
|
|
392
415
|
def _sort_prop_classes(
|
|
@@ -423,76 +446,3 @@ def _sort_prop_classes(
|
|
|
423
446
|
ok_propclass_names.append(prop_name)
|
|
424
447
|
prop_classes_to_sort.remove(prop)
|
|
425
448
|
return sorted_prop_classes
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
def _add_cardinalities_to_resource_classes(
|
|
429
|
-
resclass_definitions: list[dict[str, Any]],
|
|
430
|
-
ontology_remote: Ontology,
|
|
431
|
-
remote_res_classes: dict[str, ResourceClass],
|
|
432
|
-
knora_api_prefix: str,
|
|
433
|
-
context: Context,
|
|
434
|
-
verbose: bool,
|
|
435
|
-
) -> bool:
|
|
436
|
-
"""
|
|
437
|
-
Iterates over the resource classes of an ontology of a JSON project definition, and adds the cardinalities to each
|
|
438
|
-
resource class. The resource classes and the properties must already be existing on the DSP server.
|
|
439
|
-
If an error occurs during creation of a cardinality, it is printed out, the process continues, but the success
|
|
440
|
-
status will be false.
|
|
441
|
-
|
|
442
|
-
Args:
|
|
443
|
-
resclass_definitions: the part of the parsed JSON project file that contains the resources of the current onto
|
|
444
|
-
ontology_remote: representation of the current ontology on the DSP server
|
|
445
|
-
remote_res_classes: representations of the resource classes on the DSP server
|
|
446
|
-
knora_api_prefix: the prefix that stands for the knora-api ontology
|
|
447
|
-
context: the context of the current project
|
|
448
|
-
verbose: verbose switch
|
|
449
|
-
|
|
450
|
-
Returns:
|
|
451
|
-
success status
|
|
452
|
-
"""
|
|
453
|
-
overall_success = True
|
|
454
|
-
print(f" Add cardinalities to resource classes of ontology '{ontology_remote.iri}'...")
|
|
455
|
-
logger.info(f"Add cardinalities to resource classes of ontology '{ontology_remote.iri}'...")
|
|
456
|
-
switcher = {
|
|
457
|
-
"1": Cardinality.C_1,
|
|
458
|
-
"0-1": Cardinality.C_0_1,
|
|
459
|
-
"0-n": Cardinality.C_0_n,
|
|
460
|
-
"1-n": Cardinality.C_1_n,
|
|
461
|
-
}
|
|
462
|
-
for res_class in resclass_definitions:
|
|
463
|
-
res_class_remote = remote_res_classes.get(f"{ontology_remote.iri}#{res_class['name']}")
|
|
464
|
-
if not res_class_remote:
|
|
465
|
-
msg = (
|
|
466
|
-
f"Unable to add cardinalities to resource class '{res_class['name']}': "
|
|
467
|
-
f"This class doesn't exist on the DSP server."
|
|
468
|
-
)
|
|
469
|
-
print(f"WARNINIG: {msg}")
|
|
470
|
-
logger.exception(msg)
|
|
471
|
-
overall_success = False
|
|
472
|
-
continue
|
|
473
|
-
for card_info in res_class.get("cardinalities", []):
|
|
474
|
-
if ":" in card_info["propname"]:
|
|
475
|
-
prefix, prop = card_info["propname"].split(":")
|
|
476
|
-
qualified_propname = card_info["propname"] if prefix else f"{ontology_remote.name}:{prop}"
|
|
477
|
-
else:
|
|
478
|
-
qualified_propname = knora_api_prefix + card_info["propname"]
|
|
479
|
-
|
|
480
|
-
try:
|
|
481
|
-
last_modification_date = res_class_remote.addProperty(
|
|
482
|
-
property_id=qualified_propname,
|
|
483
|
-
cardinality=switcher[card_info["cardinality"]],
|
|
484
|
-
gui_order=card_info.get("gui_order"),
|
|
485
|
-
last_modification_date=ontology_remote.lastModificationDate,
|
|
486
|
-
context=context,
|
|
487
|
-
)
|
|
488
|
-
ontology_remote.lastModificationDate = last_modification_date
|
|
489
|
-
if verbose:
|
|
490
|
-
print(f" Added cardinality '{card_info['propname']}' to resource class '{res_class['name']}'")
|
|
491
|
-
logger.info(f"Added cardinality '{card_info['propname']}' to resource class '{res_class['name']}'")
|
|
492
|
-
except BaseError:
|
|
493
|
-
err_msg = f"Unable to add cardinality '{qualified_propname}' to resource class {res_class['name']}."
|
|
494
|
-
print(f"WARNING: {err_msg}")
|
|
495
|
-
logger.exception(err_msg)
|
|
496
|
-
overall_success = False
|
|
497
|
-
|
|
498
|
-
return overall_success
|
|
@@ -477,39 +477,6 @@ class ResourceClass(Model):
|
|
|
477
477
|
def has_properties(self) -> dict[str, HasProperty]:
|
|
478
478
|
return self._has_properties
|
|
479
479
|
|
|
480
|
-
def getProperty(self, property_id: str) -> Optional[HasProperty]:
|
|
481
|
-
if self._has_properties is None:
|
|
482
|
-
return None
|
|
483
|
-
else:
|
|
484
|
-
return self._has_properties.get(self._context.get_prefixed_iri(property_id))
|
|
485
|
-
|
|
486
|
-
def addProperty(
|
|
487
|
-
self,
|
|
488
|
-
last_modification_date: DateTimeStamp,
|
|
489
|
-
property_id: str,
|
|
490
|
-
cardinality: Cardinality,
|
|
491
|
-
context: Context,
|
|
492
|
-
gui_order: Optional[int] = None,
|
|
493
|
-
) -> DateTimeStamp:
|
|
494
|
-
self._context.context.update(context.context)
|
|
495
|
-
if self._has_properties.get(property_id) is None:
|
|
496
|
-
latest_modification_date, resclass = HasProperty(
|
|
497
|
-
con=self._con,
|
|
498
|
-
context=self._context,
|
|
499
|
-
ontology_id=self._ontology_id,
|
|
500
|
-
property_id=property_id,
|
|
501
|
-
resclass_id=self.iri,
|
|
502
|
-
cardinality=cardinality,
|
|
503
|
-
gui_order=gui_order,
|
|
504
|
-
).create(last_modification_date)
|
|
505
|
-
hp = resclass.getProperty(property_id)
|
|
506
|
-
hp.ontology_id = self._context.iri_from_prefix(self._ontology_id)
|
|
507
|
-
hp.resclass_id = self._iri
|
|
508
|
-
self._has_properties[hp.property_id] = hp
|
|
509
|
-
return latest_modification_date
|
|
510
|
-
else:
|
|
511
|
-
raise BaseError("Property already has cardinality in this class! " + property_id)
|
|
512
|
-
|
|
513
480
|
@classmethod
|
|
514
481
|
def fromJsonObj(cls, con: Connection, context: Context, json_obj: Any) -> ResourceClass:
|
|
515
482
|
if isinstance(json_obj, list):
|
dsp_tools/error/exceptions.py
CHANGED
|
@@ -65,6 +65,10 @@ class InvalidGuiAttributeError(BaseError):
|
|
|
65
65
|
"""This error is raised when a invalid gui-attribute is used."""
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
class UnexpectedApiResponseError(BaseError):
|
|
69
|
+
"""This error is raised when the API gives an unexpected response, that we cannot anticipate and handle cleanly."""
|
|
70
|
+
|
|
71
|
+
|
|
68
72
|
class UserFilepathNotFoundError(InputError):
|
|
69
73
|
"""This error is raised if a filepath from the user does not exist."""
|
|
70
74
|
|
|
@@ -12,3 +12,10 @@ def is_iri(s: str) -> bool:
|
|
|
12
12
|
def is_resource_iri(s: str) -> bool:
|
|
13
13
|
"""Checks whether a string is a valid resource IRI."""
|
|
14
14
|
return regex.fullmatch(_resource_iri_pattern, s) is not None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def from_dsp_iri_to_prefixed_iri(iri: str) -> str:
|
|
18
|
+
dsp_iri_re = r".+\/(.+?)\/v2#(.+)$"
|
|
19
|
+
if not (found := regex.search(dsp_iri_re, iri)):
|
|
20
|
+
return iri
|
|
21
|
+
return f"{found.group(1)}:{found.group(2)}"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from rdflib import Graph
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def serialise_json(rdf_graph: Graph) -> list[dict[str, Any]]:
|
|
8
|
+
graph_bytes = rdf_graph.serialize(format="json-ld", encoding="utf-8")
|
|
9
|
+
json_graph: list[dict[str, Any]] = json.loads(graph_bytes)
|
|
10
|
+
return json_graph
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dsp-tools
|
|
3
|
-
Version: 17.0.0.
|
|
3
|
+
Version: 17.0.0.post21
|
|
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>
|
|
@@ -12,18 +12,29 @@ dsp_tools/clients/connection_live.py,sha256=Y0T-F93FFGnY2Z7qHhG56v3Ajg7U7ATq4QHI
|
|
|
12
12
|
dsp_tools/clients/fuseki_metrics.py,sha256=Vy_aWOusnzlD0EnbyHZcTtPIpMEfRA_ihtYbysTq7sQ,2059
|
|
13
13
|
dsp_tools/clients/legal_info_client.py,sha256=itDvGQf1VV1WiH2oHVcH1epSUSdJPRDwdRUvmCw8P4s,742
|
|
14
14
|
dsp_tools/clients/legal_info_client_live.py,sha256=9nOe8Y-oQRHh4TkD2-tjdxLNNTonQ0i-P6UjCGgIBGA,5987
|
|
15
|
+
dsp_tools/clients/metadata_client.py,sha256=Ozlnz8-_lgPHHKPXsRyLDx1ccvBPoIYLbAJcfYnKvXY,610
|
|
16
|
+
dsp_tools/clients/metadata_client_live.py,sha256=LKaGCBZTAyJg0JHxrDOkcrb_Z3csNKXHEhKiWlVylis,1739
|
|
17
|
+
dsp_tools/clients/ontology_client.py,sha256=bATGyI8YFFCl0yis9beJjGB1ZlJuO_GqYnlB-2ulv94,638
|
|
18
|
+
dsp_tools/clients/ontology_client_live.py,sha256=8uWoRxwlCvUHQZYQsQ5XojAlpEAqzIhFNYROQfsNWf4,5367
|
|
15
19
|
dsp_tools/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
20
|
dsp_tools/commands/create/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
dsp_tools/commands/create/
|
|
21
|
+
dsp_tools/commands/create/communicate_problems.py,sha256=GdAOiUZevrYFhRINyDMhcbXdUqtGDKb2nEelhdfSFR0,885
|
|
22
|
+
dsp_tools/commands/create/constants.py,sha256=ZzWNn_zh-0Oy0SJmGivQbcAnQTmwT0akNchZUppXgh0,276
|
|
23
|
+
dsp_tools/commands/create/create_on_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
dsp_tools/commands/create/create_on_server/cardinalities.py,sha256=QW0i6TSNmP-dGS2WSad1np9QHz41-A51ArspuAQZGJg,5260
|
|
25
|
+
dsp_tools/commands/create/create_on_server/mappers.py,sha256=Lu2DJAICOZu7WP_1UDvyvRAi0T9ZGO88kvx0UfI6v5I,564
|
|
18
26
|
dsp_tools/commands/create/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
dsp_tools/commands/create/models/input_problems.py,sha256=
|
|
27
|
+
dsp_tools/commands/create/models/input_problems.py,sha256=Oa8-fQy2FTtmfXzMVdhBE9Cs3PlOgTWga4XmK5QkM7s,665
|
|
20
28
|
dsp_tools/commands/create/models/parsed_ontology.py,sha256=EUuD47SmWXyB74vGdxGwuvRzq1f4_YdciwYmqcEwqWc,815
|
|
21
29
|
dsp_tools/commands/create/models/parsed_project.py,sha256=Gnl9gJEm5sNbccYG24cwT4doS-oqh_cywjbqk1V4wZQ,928
|
|
30
|
+
dsp_tools/commands/create/models/rdf_ontology.py,sha256=TyXHmblr9j5XZFVqjLT516MrVYPgzjXWvTX4TckEPPk,361
|
|
31
|
+
dsp_tools/commands/create/models/server_project_info.py,sha256=k5EVYo8ZJhMMB5XKja9Xl6CFQ_oLRFdRZPjMyj4XmO4,699
|
|
22
32
|
dsp_tools/commands/create/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
dsp_tools/commands/create/parsing/
|
|
24
|
-
dsp_tools/commands/create/parsing/
|
|
25
|
-
dsp_tools/commands/create/parsing/
|
|
26
|
-
dsp_tools/commands/create/
|
|
33
|
+
dsp_tools/commands/create/parsing/parse_ontology.py,sha256=4cqo2wa9wcLBszWXgPrixQgaHYPHfENQbF6dkeBVNiU,4268
|
|
34
|
+
dsp_tools/commands/create/parsing/parse_project.py,sha256=CghB-pJ6RcllOP0jn8Hs50kRcxS2Q0iS8A_QNGbjzZU,4005
|
|
35
|
+
dsp_tools/commands/create/parsing/parsing_utils.py,sha256=-kr9ulha4T6reaQsQ2lImuqKEp2w4tQi66tjm2lDa9w,1636
|
|
36
|
+
dsp_tools/commands/create/serialisation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
+
dsp_tools/commands/create/serialisation/ontology.py,sha256=NK4kjriHs7dt5fXNiIBc1z_mE9szI4YemJ--hkYYeCk,1581
|
|
27
38
|
dsp_tools/commands/excel2json/CLAUDE.md,sha256=y7ZcmrHbewN48sV0wyZhNfXDXdERG4PRvdz02Mqh0gg,3399
|
|
28
39
|
dsp_tools/commands/excel2json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
40
|
dsp_tools/commands/excel2json/json_header.py,sha256=3PkhYHloGhuK9_zl7XrqboRksquWzGsdNNNo7-LC2c8,13543
|
|
@@ -66,10 +77,10 @@ dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py,sha256=QXj58UiT
|
|
|
66
77
|
dsp_tools/commands/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
67
78
|
dsp_tools/commands/project/create/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
79
|
dsp_tools/commands/project/create/parse_project.py,sha256=xYcFaUtKLZigxDZpD7O2JNueHmy_-Ar1iE2LJe97gos,4081
|
|
69
|
-
dsp_tools/commands/project/create/project_create_all.py,sha256=
|
|
80
|
+
dsp_tools/commands/project/create/project_create_all.py,sha256=GM1XjpRvGoT79wGO9VF27c8CBdV42dIOhcT3AdKSwzg,24888
|
|
70
81
|
dsp_tools/commands/project/create/project_create_default_permissions.py,sha256=CygzQ4rFF6SYUCkSvrO6gkjpINWZh4wjq_2V0PExwso,5990
|
|
71
82
|
dsp_tools/commands/project/create/project_create_lists.py,sha256=A9kKe4gVP1Ug869102bRXK5RraZUtGzv5cWyFfK_DEA,7963
|
|
72
|
-
dsp_tools/commands/project/create/project_create_ontologies.py,sha256=
|
|
83
|
+
dsp_tools/commands/project/create/project_create_ontologies.py,sha256=Ie5WHTKg5S1bRCg3SmmbB1tjem3NwRrX3N32TeAWzyI,19465
|
|
73
84
|
dsp_tools/commands/project/create/project_validate.py,sha256=H5TVvqO5V63roGEde1J0n21twkajy4AkVSDGmZb4Jp8,27443
|
|
74
85
|
dsp_tools/commands/project/get/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
86
|
dsp_tools/commands/project/get/get.py,sha256=_5LxbSP5Fi0PyXODjvND3ZC9E_x91yk6Xb6tcldG5j0,6447
|
|
@@ -84,7 +95,7 @@ dsp_tools/commands/project/legacy_models/model.py,sha256=AzxebBc5Y19kPFvsr4cPLWr
|
|
|
84
95
|
dsp_tools/commands/project/legacy_models/ontology.py,sha256=uXX0U4FVzx53GIjTyZhCN96oxdSc1Jaq-O818XrsSEc,12557
|
|
85
96
|
dsp_tools/commands/project/legacy_models/project.py,sha256=TlC-DPvaIxCdhnO82s_92lcC8--JzO840cLzrmrG4Fo,12012
|
|
86
97
|
dsp_tools/commands/project/legacy_models/propertyclass.py,sha256=tDr23zwcZptZzBIAQSW27aRtRuSbM6PI_hk2ZXnuLm8,16954
|
|
87
|
-
dsp_tools/commands/project/legacy_models/resourceclass.py,sha256=
|
|
98
|
+
dsp_tools/commands/project/legacy_models/resourceclass.py,sha256=eMorLi4x3zaeq-zBgf3lniKRpcJnQNpGLkJUPPTPsYY,26599
|
|
88
99
|
dsp_tools/commands/project/legacy_models/user.py,sha256=qJ1vxK_yQbLb7z1i7KmJA3j5wYZKAUHPBGIhIXHhfq4,16057
|
|
89
100
|
dsp_tools/commands/project/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
101
|
dsp_tools/commands/project/models/permissions_client.py,sha256=v_Y02kTWFi7l9JE18lUxkyjc-vyt8KK7h8MN8MtsgXw,2494
|
|
@@ -175,7 +186,7 @@ dsp_tools/config/logger_config.py,sha256=Bw2Gu5F2d8un_KNk0hvNtV7fvN2TlThqo6gSwqe
|
|
|
175
186
|
dsp_tools/config/warnings_config.py,sha256=15_Lt227HLqhdn6v-zJbi1KG9Fo6Zi1_4fp_a-iY72w,1142
|
|
176
187
|
dsp_tools/error/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
177
188
|
dsp_tools/error/custom_warnings.py,sha256=7C2DscIz9k7IfM8uebIsKWPcWcSjwpDqbIRDaPw7bI8,1053
|
|
178
|
-
dsp_tools/error/exceptions.py,sha256=
|
|
189
|
+
dsp_tools/error/exceptions.py,sha256=giLM6Hx17lMdCjNdlwMr4zqdGcqUHypAxESSAtkvvnU,4853
|
|
179
190
|
dsp_tools/error/problems.py,sha256=DotzVg3MYvMJmernd9tTBmDHoT1MOkHdiWVv8iMoFSk,265
|
|
180
191
|
dsp_tools/error/xmllib_errors.py,sha256=DpYCsBIx_GmsBAUlfk2VMqtzD5IGMRbd2yXTcrJFHR4,549
|
|
181
192
|
dsp_tools/error/xmllib_warnings.py,sha256=sS9jJXGJtQqCiJ9P2zCM5gpIhTpChbujQz_fPvxLm8g,1557
|
|
@@ -204,12 +215,13 @@ dsp_tools/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
204
215
|
dsp_tools/utils/ansi_colors.py,sha256=p2vq-wzfmE-wdDddvC26UcOA6Z1qhFTdzP0dPoW4sy0,1691
|
|
205
216
|
dsp_tools/utils/data_formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
206
217
|
dsp_tools/utils/data_formats/date_util.py,sha256=VLNQnSsUX6NB1IY3Ry5KCxCLgHHYN0TSSBRn8hyXN-4,4714
|
|
207
|
-
dsp_tools/utils/data_formats/iri_util.py,sha256=
|
|
218
|
+
dsp_tools/utils/data_formats/iri_util.py,sha256=O_TQb104ukjVsaqgkstz54QvjgqFPLSxVvqH6HVNjQc,670
|
|
208
219
|
dsp_tools/utils/data_formats/shared.py,sha256=9AybXCAboojvRULZPud5e6B7UkjQOuN6f5fiVxwuZe8,2618
|
|
209
220
|
dsp_tools/utils/data_formats/uri_util.py,sha256=9UGrbtxHVI0Ka0ttxd39KDhGeeP0xOdVLjt6HyV-Ic8,3257
|
|
210
221
|
dsp_tools/utils/fuseki_bloating.py,sha256=yUCSijVf_Ne9iWUK_IzbPAkOMkN8Xt9ttPcWWRSIgMI,2381
|
|
211
222
|
dsp_tools/utils/json_parsing.py,sha256=KlNvwnZoq-gJqnOVH7tiZMzgdld_3IunuOVvlEVXGXc,1684
|
|
212
223
|
dsp_tools/utils/rdflib_constants.py,sha256=D5HO7oILBRiQI-bJj14pbCx6zhKY4RGqjIjq6S_IawU,652
|
|
224
|
+
dsp_tools/utils/rdflib_utils.py,sha256=M9UCXMe8W3SDQ0DYh4i6lRwYkyWozrWLl19NP5A-RlY,284
|
|
213
225
|
dsp_tools/utils/replace_id_with_iri.py,sha256=5M5vXWJIQ0oO4ELwIt_5QeYBvyGESBc2smuNThHiQUY,2928
|
|
214
226
|
dsp_tools/utils/request_utils.py,sha256=KxiFpQ_IH1ZCIF-SknPjRMP5-ZtLP3wWzwSrEZDB2fk,6902
|
|
215
227
|
dsp_tools/utils/xml_parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -248,7 +260,7 @@ dsp_tools/xmllib/models/res.py,sha256=c3edvilYZVDmv2O6Z36sSkHXcuKPAJLfWVpStDTMuJ
|
|
|
248
260
|
dsp_tools/xmllib/models/root.py,sha256=x8_vrDSJ1pZUJUL8LR460dZe4Cg57G_Hy-Zfr2S29dw,13562
|
|
249
261
|
dsp_tools/xmllib/value_checkers.py,sha256=Yx3r6_WoZ5Lev8Orp8yDzd03JvP2GBmFNSFT2dzrycM,10712
|
|
250
262
|
dsp_tools/xmllib/value_converters.py,sha256=WMYS5hd1VlrLLBXnf6pv9yYoPBsv_2MxOO6xv-QsRW4,29218
|
|
251
|
-
dsp_tools-17.0.0.
|
|
252
|
-
dsp_tools-17.0.0.
|
|
253
|
-
dsp_tools-17.0.0.
|
|
254
|
-
dsp_tools-17.0.0.
|
|
263
|
+
dsp_tools-17.0.0.post21.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
|
|
264
|
+
dsp_tools-17.0.0.post21.dist-info/entry_points.txt,sha256=qjRfEbkeAwLU_AE2Q-l4Y9irPNmu4Wna-3bfRp1bqV4,62
|
|
265
|
+
dsp_tools-17.0.0.post21.dist-info/METADATA,sha256=c-CiHkhfevQLuSoAyhtEYoAA1CF4nWN8HoR5o7H6e_8,4285
|
|
266
|
+
dsp_tools-17.0.0.post21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|