rdf4j-python 0.1.3__py3-none-any.whl → 0.1.5__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.
- rdf4j_python/_client/_client.py +24 -2
- rdf4j_python/_driver/_async_rdf4j_db.py +1 -0
- rdf4j_python/_driver/_async_repository.py +44 -12
- rdf4j_python/model/repository_config.py +15 -928
- rdf4j_python-0.1.5.dist-info/METADATA +259 -0
- {rdf4j_python-0.1.3.dist-info → rdf4j_python-0.1.5.dist-info}/RECORD +9 -9
- {rdf4j_python-0.1.3.dist-info → rdf4j_python-0.1.5.dist-info}/WHEEL +1 -1
- rdf4j_python-0.1.3.dist-info/METADATA +0 -77
- {rdf4j_python-0.1.3.dist-info → rdf4j_python-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {rdf4j_python-0.1.3.dist-info → rdf4j_python-0.1.5.dist-info}/top_level.txt +0 -0
rdf4j_python/_client/_client.py
CHANGED
|
@@ -42,6 +42,17 @@ class BaseClient:
|
|
|
42
42
|
class SyncApiClient(BaseClient):
|
|
43
43
|
"""Synchronous API client using httpx.Client."""
|
|
44
44
|
|
|
45
|
+
def __init__(self, base_url: str, timeout: int = 10):
|
|
46
|
+
"""
|
|
47
|
+
Initializes the SyncApiClient.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
base_url (str): The base URL for the API endpoints.
|
|
51
|
+
timeout (int, optional): Request timeout in seconds. Defaults to 10.
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(base_url, timeout)
|
|
54
|
+
self.client = httpx.Client(timeout=self.timeout)
|
|
55
|
+
|
|
45
56
|
def __enter__(self):
|
|
46
57
|
"""
|
|
47
58
|
Enters the context and initializes the HTTP client.
|
|
@@ -49,7 +60,7 @@ class SyncApiClient(BaseClient):
|
|
|
49
60
|
Returns:
|
|
50
61
|
SyncApiClient: The instance of the client.
|
|
51
62
|
"""
|
|
52
|
-
self.client
|
|
63
|
+
self.client.__enter__()
|
|
53
64
|
return self
|
|
54
65
|
|
|
55
66
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
@@ -142,6 +153,17 @@ class SyncApiClient(BaseClient):
|
|
|
142
153
|
class AsyncApiClient(BaseClient):
|
|
143
154
|
"""Asynchronous API client using httpx.AsyncClient."""
|
|
144
155
|
|
|
156
|
+
def __init__(self, base_url: str, timeout: int = 10):
|
|
157
|
+
"""
|
|
158
|
+
Initializes the AsyncApiClient.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
base_url (str): The base URL for the API endpoints.
|
|
162
|
+
timeout (int, optional): Request timeout in seconds. Defaults to 10.
|
|
163
|
+
"""
|
|
164
|
+
super().__init__(base_url, timeout)
|
|
165
|
+
self.client = httpx.AsyncClient(timeout=self.timeout)
|
|
166
|
+
|
|
145
167
|
async def __aenter__(self):
|
|
146
168
|
"""
|
|
147
169
|
Enters the async context and initializes the HTTP client.
|
|
@@ -149,7 +171,7 @@ class AsyncApiClient(BaseClient):
|
|
|
149
171
|
Returns:
|
|
150
172
|
AsyncApiClient: The instance of the client.
|
|
151
173
|
"""
|
|
152
|
-
|
|
174
|
+
await self.client.__aenter__()
|
|
153
175
|
return self
|
|
154
176
|
|
|
155
177
|
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
@@ -69,6 +69,7 @@ class AsyncRdf4j:
|
|
|
69
69
|
query_solutions = og.parse_query_results(
|
|
70
70
|
response.text, format=og.QueryResultsFormat.JSON
|
|
71
71
|
)
|
|
72
|
+
assert isinstance(query_solutions, og.QuerySolutions)
|
|
72
73
|
return [
|
|
73
74
|
RepositoryMetadata.from_sparql_query_solution(query_solution)
|
|
74
75
|
for query_solution in query_solutions
|
|
@@ -25,10 +25,21 @@ from rdf4j_python.model.term import (
|
|
|
25
25
|
from rdf4j_python.utils.const import Rdf4jContentType
|
|
26
26
|
from rdf4j_python.utils.helpers import serialize_statements
|
|
27
27
|
|
|
28
|
+
try:
|
|
29
|
+
from SPARQLWrapper import SPARQLWrapper
|
|
30
|
+
|
|
31
|
+
_has_sparql_wrapper = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
_has_sparql_wrapper = False
|
|
34
|
+
|
|
28
35
|
|
|
29
36
|
class AsyncRdf4JRepository:
|
|
30
37
|
"""Asynchronous interface for interacting with an RDF4J repository."""
|
|
31
38
|
|
|
39
|
+
_client: AsyncApiClient
|
|
40
|
+
_repository_id: str
|
|
41
|
+
_sparql_wrapper: Optional["SPARQLWrapper"] = None
|
|
42
|
+
|
|
32
43
|
def __init__(self, client: AsyncApiClient, repository_id: str):
|
|
33
44
|
"""Initializes the repository interface.
|
|
34
45
|
|
|
@@ -39,32 +50,47 @@ class AsyncRdf4JRepository:
|
|
|
39
50
|
self._client = client
|
|
40
51
|
self._repository_id = repository_id
|
|
41
52
|
|
|
53
|
+
async def get_sparql_wrapper(self) -> "SPARQLWrapper":
|
|
54
|
+
"""Returns the SPARQLWrapper for the repository.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
SPARQLWrapper: The SPARQLWrapper for the repository.
|
|
58
|
+
"""
|
|
59
|
+
if not _has_sparql_wrapper:
|
|
60
|
+
raise ImportError(
|
|
61
|
+
"SPARQLWrapper is not installed. Please install it with `pip install rdf4j-python[sparqlwrapper]`"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if self._sparql_wrapper is None:
|
|
65
|
+
self._sparql_wrapper = SPARQLWrapper(
|
|
66
|
+
f"{self._client.get_base_url()}/repositories/{self._repository_id}"
|
|
67
|
+
)
|
|
68
|
+
return self._sparql_wrapper
|
|
69
|
+
|
|
42
70
|
async def query(
|
|
43
71
|
self,
|
|
44
72
|
sparql_query: str,
|
|
45
73
|
infer: bool = True,
|
|
46
|
-
|
|
47
|
-
):
|
|
74
|
+
) -> og.QuerySolutions | og.QueryBoolean:
|
|
48
75
|
"""Executes a SPARQL SELECT query.
|
|
49
76
|
|
|
50
77
|
Args:
|
|
51
78
|
sparql_query (str): The SPARQL query string.
|
|
52
79
|
infer (bool): Whether to include inferred statements. Defaults to True.
|
|
53
|
-
accept (Rdf4jContentType): The expected response format.
|
|
54
80
|
|
|
55
81
|
Returns:
|
|
56
|
-
|
|
82
|
+
og.QuerySolutions | og.QueryBoolean: Parsed query results.
|
|
57
83
|
"""
|
|
58
84
|
path = f"/repositories/{self._repository_id}"
|
|
59
85
|
params = {"query": sparql_query, "infer": str(infer).lower()}
|
|
60
|
-
headers = {"Accept":
|
|
86
|
+
headers = {"Accept": Rdf4jContentType.SPARQL_RESULTS_JSON}
|
|
61
87
|
response = await self._client.get(path, params=params, headers=headers)
|
|
62
88
|
self._handle_repo_not_found_exception(response)
|
|
63
|
-
|
|
64
|
-
return response.json()
|
|
65
|
-
return response.text
|
|
89
|
+
return og.parse_query_results(response.text, format=og.QueryResultsFormat.JSON)
|
|
66
90
|
|
|
67
|
-
async def update(
|
|
91
|
+
async def update(
|
|
92
|
+
self, sparql_update_query: str, content_type: Rdf4jContentType
|
|
93
|
+
) -> None:
|
|
68
94
|
"""Executes a SPARQL UPDATE command.
|
|
69
95
|
|
|
70
96
|
Args:
|
|
@@ -74,11 +100,16 @@ class AsyncRdf4JRepository:
|
|
|
74
100
|
RepositoryNotFoundException: If the repository doesn't exist.
|
|
75
101
|
httpx.HTTPStatusError: If the update fails.
|
|
76
102
|
"""
|
|
103
|
+
# SPARQL UPDATE operations return HTTP 204 No Content on success.
|
|
104
|
+
# No result data is returned as per SPARQL 1.1 UPDATE specification.
|
|
77
105
|
path = f"/repositories/{self._repository_id}/statements"
|
|
78
|
-
headers = {"Content-Type":
|
|
79
|
-
response = await self._client.post(
|
|
106
|
+
headers = {"Content-Type": content_type}
|
|
107
|
+
response = await self._client.post(
|
|
108
|
+
path, content=sparql_update_query, headers=headers
|
|
109
|
+
)
|
|
80
110
|
self._handle_repo_not_found_exception(response)
|
|
81
|
-
response.
|
|
111
|
+
if response.status_code != httpx.codes.NO_CONTENT:
|
|
112
|
+
raise RepositoryUpdateException(f"Failed to update: {response.text}")
|
|
82
113
|
|
|
83
114
|
async def get_namespaces(self):
|
|
84
115
|
"""Retrieves all namespaces in the repository.
|
|
@@ -97,6 +128,7 @@ class AsyncRdf4JRepository:
|
|
|
97
128
|
query_solutions = og.parse_query_results(
|
|
98
129
|
response.text, format=og.QueryResultsFormat.JSON
|
|
99
130
|
)
|
|
131
|
+
assert isinstance(query_solutions, og.QuerySolutions)
|
|
100
132
|
return [
|
|
101
133
|
Namespace.from_sparql_query_solution(query_solution)
|
|
102
134
|
for query_solution in query_solutions
|