rdf4j-python 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -1,8 +1,9 @@
1
1
  from typing import Iterable
2
2
 
3
+ import pyoxigraph as og
4
+
3
5
  from rdf4j_python._client import AsyncApiClient
4
- from rdf4j_python.model import RDF4JDataSet
5
- from rdf4j_python.model.term import IRI, RDFStatement
6
+ from rdf4j_python.model.term import IRI, Quad, QuadResultSet, Triple
6
7
  from rdf4j_python.utils.const import Rdf4jContentType
7
8
  from rdf4j_python.utils.helpers import serialize_statements
8
9
 
@@ -22,11 +23,11 @@ class AsyncNamedGraph:
22
23
  self._repository_id = repository_id
23
24
  self._graph_uri = graph_uri
24
25
 
25
- async def get(self) -> RDF4JDataSet:
26
+ async def get(self) -> QuadResultSet:
26
27
  """Fetches all RDF statements from this named graph.
27
28
 
28
29
  Returns:
29
- str: RDF data serialized in the requested format.
30
+ QuadResultSet: RDF data serialized in the requested format.
30
31
 
31
32
  Raises:
32
33
  httpx.HTTPStatusError: If the request fails.
@@ -35,13 +36,13 @@ class AsyncNamedGraph:
35
36
  headers = {"Accept": Rdf4jContentType.NQUADS}
36
37
  response = await self._client.get(path, headers=headers)
37
38
  response.raise_for_status()
38
- return RDF4JDataSet.from_raw_text(response.text)
39
+ return og.parse(response.content, format=og.RdfFormat.N_QUADS)
39
40
 
40
- async def add(self, statements: Iterable[RDFStatement]):
41
+ async def add(self, statements: Iterable[Quad] | Iterable[Triple]):
41
42
  """Adds RDF statements to this named graph.
42
43
 
43
44
  Args:
44
- statements (Iterable[RDFStatement]): RDF statements to add.
45
+ statements (Iterable[Quad] | Iterable[Triple]): RDF statements to add.
45
46
 
46
47
  Raises:
47
48
  httpx.HTTPStatusError: If the request fails.
@@ -1,5 +1,5 @@
1
1
  import httpx
2
- import rdflib
2
+ import pyoxigraph as og
3
3
 
4
4
  from rdf4j_python._client import AsyncApiClient
5
5
  from rdf4j_python.exception.repo_exception import (
@@ -66,12 +66,13 @@ class AsyncRdf4j:
66
66
  "/repositories",
67
67
  headers={"Accept": Rdf4jContentType.SPARQL_RESULTS_JSON},
68
68
  )
69
- result = rdflib.query.Result.parse(
70
- response, format=Rdf4jContentType.SPARQL_RESULTS_JSON
69
+ query_solutions = og.parse_query_results(
70
+ response.text, format=og.QueryResultsFormat.JSON
71
71
  )
72
+ assert isinstance(query_solutions, og.QuerySolutions)
72
73
  return [
73
- RepositoryMetadata.from_rdflib_binding(binding)
74
- for binding in result.bindings
74
+ RepositoryMetadata.from_sparql_query_solution(query_solution)
75
+ for query_solution in query_solutions
75
76
  ]
76
77
 
77
78
  async def get_repository(self, repository_id: str) -> AsyncRdf4JRepository:
@@ -1,10 +1,7 @@
1
1
  from typing import Iterable, Optional
2
2
 
3
3
  import httpx
4
- import rdflib
5
- import rdflib.resource
6
- import rdflib.serializer
7
- import rdflib.store
4
+ import pyoxigraph as og
8
5
 
9
6
  from rdf4j_python._client import AsyncApiClient
10
7
  from rdf4j_python._driver._async_named_graph import AsyncNamedGraph
@@ -14,21 +11,35 @@ from rdf4j_python.exception.repo_exception import (
14
11
  RepositoryNotFoundException,
15
12
  RepositoryUpdateException,
16
13
  )
17
- from rdf4j_python.model import Namespace, RDF4JDataSet
14
+ from rdf4j_python.model import Namespace
18
15
  from rdf4j_python.model.term import (
16
+ IRI,
19
17
  Context,
20
18
  Object,
21
19
  Predicate,
22
- RDFStatement,
20
+ Quad,
21
+ QuadResultSet,
23
22
  Subject,
23
+ Triple,
24
24
  )
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
- accept: Rdf4jContentType = Rdf4jContentType.SPARQL_RESULTS_JSON,
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
- dict or str: Parsed JSON results or raw response text.
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": accept.value}
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
- if "json" in response.headers.get("Content-Type", ""):
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(self, sparql_update: str):
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,15 @@ class AsyncRdf4JRepository:
74
100
  RepositoryNotFoundException: If the repository doesn't exist.
75
101
  httpx.HTTPStatusError: If the update fails.
76
102
  """
103
+ # TODO: handle update results
77
104
  path = f"/repositories/{self._repository_id}/statements"
78
- headers = {"Content-Type": Rdf4jContentType.SPARQL_UPDATE.value}
79
- response = await self._client.post(path, data=sparql_update, headers=headers)
105
+ headers = {"Content-Type": content_type}
106
+ response = await self._client.post(
107
+ path, content=sparql_update_query, headers=headers
108
+ )
80
109
  self._handle_repo_not_found_exception(response)
81
- response.raise_for_status()
110
+ if response.status_code != httpx.codes.NO_CONTENT:
111
+ raise RepositoryUpdateException(f"Failed to update: {response.text}")
82
112
 
83
113
  async def get_namespaces(self):
84
114
  """Retrieves all namespaces in the repository.
@@ -92,26 +122,33 @@ class AsyncRdf4JRepository:
92
122
  path = f"/repositories/{self._repository_id}/namespaces"
93
123
  headers = {"Accept": Rdf4jContentType.SPARQL_RESULTS_JSON}
94
124
  response = await self._client.get(path, headers=headers)
95
- result = rdflib.query.Result.parse(
96
- response, format=Rdf4jContentType.SPARQL_RESULTS_JSON
97
- )
98
125
  self._handle_repo_not_found_exception(response)
99
- return [Namespace.from_rdflib_binding(binding) for binding in result.bindings]
100
126
 
101
- async def set_namespace(self, prefix: str, namespace: str):
127
+ query_solutions = og.parse_query_results(
128
+ response.text, format=og.QueryResultsFormat.JSON
129
+ )
130
+ assert isinstance(query_solutions, og.QuerySolutions)
131
+ return [
132
+ Namespace.from_sparql_query_solution(query_solution)
133
+ for query_solution in query_solutions
134
+ ]
135
+
136
+ async def set_namespace(self, prefix: str, namespace: IRI):
102
137
  """Sets a namespace prefix.
103
138
 
104
139
  Args:
105
140
  prefix (str): The namespace prefix.
106
- namespace (str): The namespace URI.
141
+ namespace (IRI): The namespace URI.
107
142
 
108
143
  Raises:
109
144
  RepositoryNotFoundException: If the repository doesn't exist.
110
145
  NamespaceException: If the request fails.
111
146
  """
112
147
  path = f"/repositories/{self._repository_id}/namespaces/{prefix}"
113
- headers = {"Content-Type": Rdf4jContentType.NTRIPLES.value}
114
- response = await self._client.put(path, content=namespace, headers=headers)
148
+ headers = {"Content-Type": Rdf4jContentType.NTRIPLES}
149
+ response = await self._client.put(
150
+ path, content=namespace.value, headers=headers
151
+ )
115
152
  self._handle_repo_not_found_exception(response)
116
153
  if response.status_code != httpx.codes.NO_CONTENT:
117
154
  raise NamespaceException(f"Failed to set namespace: {response.text}")
@@ -130,7 +167,7 @@ class AsyncRdf4JRepository:
130
167
  NamespaceException: If retrieval fails.
131
168
  """
132
169
  path = f"/repositories/{self._repository_id}/namespaces/{prefix}"
133
- headers = {"Accept": Rdf4jContentType.NTRIPLES.value}
170
+ headers = {"Accept": Rdf4jContentType.NTRIPLES}
134
171
  response = await self._client.get(path, headers=headers)
135
172
  self._handle_repo_not_found_exception(response)
136
173
 
@@ -192,7 +229,7 @@ class AsyncRdf4JRepository:
192
229
  object_: Optional[Object] = None,
193
230
  contexts: Optional[list[Context]] = None,
194
231
  infer: bool = True,
195
- ) -> RDF4JDataSet:
232
+ ) -> QuadResultSet:
196
233
  """Retrieves statements matching the given pattern.
197
234
 
198
235
  Args:
@@ -202,7 +239,7 @@ class AsyncRdf4JRepository:
202
239
  contexts (Optional[list[Context]]): Filter by context (named graph).
203
240
 
204
241
  Returns:
205
- DataSet: Dataset of matching RDF statements.
242
+ QuadResultSet: QuadResultSet of matching RDF statements.
206
243
 
207
244
  Raises:
208
245
  RepositoryNotFoundException: If the repository doesn't exist.
@@ -211,20 +248,18 @@ class AsyncRdf4JRepository:
211
248
  params = {}
212
249
 
213
250
  if subject:
214
- params["subj"] = subject.n3()
251
+ params["subj"] = str(subject)
215
252
  if predicate:
216
- params["pred"] = predicate.n3()
253
+ params["pred"] = str(predicate)
217
254
  if object_:
218
- params["obj"] = object_.n3()
255
+ params["obj"] = str(object_)
219
256
  if contexts:
220
- params["context"] = [ctx.n3() for ctx in contexts]
257
+ params["context"] = [str(ctx) for ctx in contexts]
221
258
  params["infer"] = str(infer).lower()
222
259
 
223
260
  headers = {"Accept": Rdf4jContentType.NQUADS}
224
261
  response = await self._client.get(path, params=params, headers=headers)
225
- dataset = RDF4JDataSet()
226
- dataset.parse(data=response.text, format="nquads")
227
- return dataset
262
+ return og.parse(response.content, format=og.RdfFormat.N_QUADS)
228
263
 
229
264
  async def delete_statements(
230
265
  self,
@@ -250,13 +285,13 @@ class AsyncRdf4JRepository:
250
285
  params = {}
251
286
 
252
287
  if subject:
253
- params["subj"] = subject.n3()
288
+ params["subj"] = str(subject)
254
289
  if predicate:
255
- params["pred"] = predicate.n3()
290
+ params["pred"] = str(predicate)
256
291
  if object_:
257
- params["obj"] = object_.n3()
292
+ params["obj"] = str(object_)
258
293
  if contexts:
259
- params["context"] = [ctx.n3() for ctx in contexts]
294
+ params["context"] = [str(ctx) for ctx in contexts]
260
295
 
261
296
  response = await self._client.delete(path, params=params)
262
297
  self._handle_repo_not_found_exception(response)
@@ -286,21 +321,26 @@ class AsyncRdf4JRepository:
286
321
  httpx.HTTPStatusError: If addition fails.
287
322
  """
288
323
  path = f"/repositories/{self._repository_id}/statements"
324
+ statement: Triple | Quad
325
+ if context is None:
326
+ statement = Triple(subject, predicate, object)
327
+ else:
328
+ statement = Quad(subject, predicate, object, context)
329
+
289
330
  response = await self._client.post(
290
331
  path,
291
- content=serialize_statements([(subject, predicate, object, context)]),
332
+ content=serialize_statements([statement]),
292
333
  headers={"Content-Type": Rdf4jContentType.NQUADS},
293
334
  )
294
335
  self._handle_repo_not_found_exception(response)
295
336
  if response.status_code != httpx.codes.NO_CONTENT:
296
337
  raise RepositoryUpdateException(f"Failed to add statement: {response.text}")
297
338
 
298
- async def add_statements(self, statements: Iterable[RDFStatement]):
339
+ async def add_statements(self, statements: Iterable[Quad] | Iterable[Triple]):
299
340
  """Adds a list of RDF statements to the repository.
300
341
 
301
342
  Args:
302
- statements (Iterable[RDFStatement]): A list of RDF statements.
303
- RDFStatement: A tuple of subject, predicate, object, and context.
343
+ statements (Iterable[Quad] | Iterable[Triple]): A list of RDF statements.
304
344
 
305
345
  Raises:
306
346
  RepositoryNotFoundException: If the repository doesn't exist.
@@ -320,26 +360,26 @@ class AsyncRdf4JRepository:
320
360
 
321
361
  async def replace_statements(
322
362
  self,
323
- statements: Iterable[RDFStatement],
324
- contexts: Optional[list[Context]] = None,
363
+ statements: Iterable[Quad] | Iterable[Triple],
364
+ contexts: Optional[Iterable[Context]] = None,
325
365
  base_uri: Optional[str] = None,
326
366
  ):
327
367
  """Replaces all repository statements with the given RDF data.
328
368
 
329
369
  Args:
330
- statements (Iterable[RDFStatement]): RDF statements to load.
331
- contexts (Optional[list[Context]]): One or more specific contexts to restrict deletion to.
370
+ statements (Iterable[Quad] | Iterable[Triple]): RDF statements to load.
371
+ contexts (Optional[Iterable[Context]]): One or more specific contexts to restrict deletion to.
332
372
 
333
373
  Raises:
334
374
  RepositoryNotFoundException: If the repository doesn't exist.
335
375
  httpx.HTTPStatusError: If the operation fails.
336
376
  """
337
377
  path = f"/repositories/{self._repository_id}/statements"
338
- headers = {"Content-Type": Rdf4jContentType.NQUADS.value}
378
+ headers = {"Content-Type": Rdf4jContentType.NQUADS}
339
379
 
340
380
  params = {}
341
381
  if contexts:
342
- params["context"] = [ctx.n3() for ctx in contexts]
382
+ params["context"] = [str(ctx) for ctx in contexts]
343
383
  if base_uri:
344
384
  params["baseUri"] = base_uri
345
385
 
@@ -2,12 +2,10 @@
2
2
  RDF4J Python Model Module
3
3
  """
4
4
 
5
- from ._dataset import RDF4JDataSet
6
5
  from ._namespace import Namespace
7
6
  from ._repository_info import RepositoryMetadata
8
7
 
9
8
  __all__ = [
10
9
  "Namespace",
11
10
  "RepositoryMetadata",
12
- "RDF4JDataSet",
13
11
  ]
@@ -1,11 +1,32 @@
1
- from typing import Mapping
2
-
3
- from rdflib.namespace import Namespace as RdflibNamespace
4
- from rdflib.term import Identifier, Variable
1
+ import pyoxigraph as og
5
2
 
6
3
  from rdf4j_python.model.term import IRI
7
4
 
8
- from ._base_model import _BaseModel
5
+
6
+ class _Namespace(str):
7
+ def __new__(cls, value: str | bytes) -> "Namespace":
8
+ try:
9
+ rt = str.__new__(cls, value)
10
+ except UnicodeDecodeError:
11
+ rt = str.__new__(cls, value, "utf-8")
12
+ return rt
13
+
14
+ def term(self, name: str) -> IRI:
15
+ return IRI(self + (name if isinstance(name, str) else ""))
16
+
17
+ def __getitem__(self, key: str) -> IRI:
18
+ return self.term(key)
19
+
20
+ def __getattr__(self, name: str) -> IRI:
21
+ if name.startswith("__"):
22
+ raise AttributeError
23
+ return self.term(name)
24
+
25
+ def __repr__(self) -> str:
26
+ return f"Namespace({super().__repr__()})"
27
+
28
+ def __contains__(self, ref: str) -> bool:
29
+ return ref.startswith(self)
9
30
 
10
31
 
11
32
  class Namespace:
@@ -14,7 +35,7 @@ class Namespace:
14
35
  """
15
36
 
16
37
  _prefix: str
17
- _namespace: RdflibNamespace
38
+ _namespace: _Namespace
18
39
 
19
40
  def __init__(self, prefix: str, namespace: str):
20
41
  """
@@ -25,24 +46,26 @@ class Namespace:
25
46
  namespace (str): The namespace URI.
26
47
  """
27
48
  self._prefix = prefix
28
- self._namespace = RdflibNamespace(namespace)
49
+ self._namespace = _Namespace(namespace)
29
50
 
30
51
  @classmethod
31
- def from_rdflib_binding(cls, binding: Mapping[Variable, Identifier]) -> "Namespace":
52
+ def from_sparql_query_solution(
53
+ cls, query_solution: og.QuerySolution
54
+ ) -> "Namespace":
32
55
  """
33
- Creates a Namespace from a RDFlib binding.
56
+ Creates a Namespace from a binding.
34
57
 
35
58
  Args:
36
- binding (Mapping[Variable, Identifier]): The RDFlib binding.
59
+ binding (Mapping[Variable, Identifier]): The binding.
37
60
 
38
61
  Returns:
39
62
  Namespace: The created Namespace.
40
63
  """
41
- prefix = _BaseModel.get_literal(binding, "prefix", "")
42
- namespace = _BaseModel.get_literal(binding, "namespace", "")
64
+ prefix: og.Literal = query_solution[og.Variable("prefix")]
65
+ namespace: og.NamedNode = query_solution[og.Variable("namespace")]
43
66
  return cls(
44
- prefix=prefix,
45
- namespace=namespace,
67
+ prefix=prefix.value,
68
+ namespace=namespace.value,
46
69
  )
47
70
 
48
71
  def __str__(self):
@@ -85,7 +108,7 @@ class Namespace:
85
108
  Returns:
86
109
  IRI: The IRI for the term.
87
110
  """
88
- return IRI(self._namespace.term(name))
111
+ return self._namespace.term(name)
89
112
 
90
113
  def __getitem__(self, item: str) -> IRI:
91
114
  """
@@ -1,13 +1,10 @@
1
1
  from dataclasses import dataclass
2
- from typing import Mapping
3
2
 
4
- from rdflib.term import Identifier, Variable
5
-
6
- from ._base_model import _BaseModel
3
+ import pyoxigraph as og
7
4
 
8
5
 
9
6
  @dataclass
10
- class RepositoryMetadata(_BaseModel):
7
+ class RepositoryMetadata:
11
8
  """
12
9
  Represents a repository metadata RDF4J.
13
10
  """
@@ -28,25 +25,38 @@ class RepositoryMetadata(_BaseModel):
28
25
  return f"Repository(id={self.id}, title={self.title}, uri={self.uri})"
29
26
 
30
27
  @classmethod
31
- def from_rdflib_binding(
32
- cls, result: Mapping[Variable, Identifier]
28
+ def from_sparql_query_solution(
29
+ cls, query_solution: og.QuerySolution
33
30
  ) -> "RepositoryMetadata":
34
31
  """
35
- Create a Repository instance from a SPARQL query result
36
- represented as a Mapping from rdflib Variables to Identifiers.
32
+ Create a RepositoryMetadata instance from a SPARQL query result.
37
33
 
38
34
  Args:
39
- result (Mapping[Variable, Identifier]): The SPARQL query result.
35
+ query_solution (og.QuerySolution): The SPARQL query result.
40
36
 
41
37
  Returns:
42
38
  RepositoryMetadata: The RepositoryMetadata instance.
39
+
40
+ Raises:
41
+ ValueError: If the query solution is missing required fields.
43
42
  """
44
43
 
45
44
  # Construct and return the Repository object
45
+ if query_solution["id"] is None:
46
+ raise ValueError("id is required")
47
+ if query_solution["uri"] is None:
48
+ raise ValueError("uri is required")
49
+ if query_solution["title"] is None:
50
+ raise ValueError("title is required")
51
+ if query_solution["readable"] is None:
52
+ raise ValueError("readable is required")
53
+ if query_solution["writable"] is None:
54
+ raise ValueError("writable is required")
55
+
46
56
  return cls(
47
- id=_BaseModel.get_literal(result, "id", ""),
48
- uri=_BaseModel.get_uri(result, "uri", ""),
49
- title=_BaseModel.get_literal(result, "title", ""),
50
- readable=_BaseModel.get_literal(result, "readable", False),
51
- writable=_BaseModel.get_literal(result, "writable", False),
57
+ id=query_solution["id"].value,
58
+ uri=query_solution["uri"].value,
59
+ title=query_solution["title"].value,
60
+ readable=bool(query_solution["readable"].value),
61
+ writable=bool(query_solution["writable"].value),
52
62
  )
@@ -1,10 +1,15 @@
1
1
  from typing import Any, Dict, Optional
2
2
 
3
- from rdflib import BNode, Graph, Literal, Namespace, URIRef
4
- from rdflib.namespace import RDF, RDFS, XSD
3
+ from pyoxigraph import Dataset, Quad, RdfFormat, serialize
4
+
5
+ from rdf4j_python.model import Namespace
6
+ from rdf4j_python.model.term import IRI as URIRef
7
+ from rdf4j_python.model.term import BlankNode as BNode
8
+ from rdf4j_python.model.term import Literal
9
+ from rdf4j_python.model.vocabulary import RDF, RDFS, XSD
5
10
 
6
11
  # Define the RDF4J configuration namespace
7
- CONFIG = Namespace("tag:rdf4j.org,2023:config/")
12
+ CONFIG = Namespace("config", "tag:rdf4j.org,2023:config/")
8
13
 
9
14
 
10
15
  class RepositoryConfig:
@@ -54,35 +59,32 @@ class RepositoryConfig:
54
59
  """
55
60
  return self._title
56
61
 
57
- def to_turtle(self) -> str:
62
+ def to_turtle(self) -> bytes | None:
58
63
  """
59
- Serializes the Repository configuration to Turtle syntax using RDFlib.
64
+ Serializes the Repository configuration to Turtle syntax using .
60
65
 
61
66
  Returns:
62
- str: A UTF-8 encoded Turtle string representing the RDF4J repository configuration.
67
+ bytes | None: A UTF-8 encoded Turtle string representing the RDF4J repository configuration.
63
68
  The serialization includes the repository ID, optional human-readable title,
64
69
  and nested repository implementation configuration if available.
65
70
 
66
71
  Raises:
67
72
  ValueError: If any of the configuration values are of unsupported types during serialization.
68
73
  """
69
- graph = Graph()
70
- graph.bind("rdfs", RDFS)
71
- graph.bind("config", CONFIG)
72
- graph.bind("xsd", XSD)
74
+ graph = Dataset()
73
75
  repo_node = BNode()
74
- graph.add((repo_node, RDF["type"], CONFIG["Repository"]))
76
+ graph.add(Quad(repo_node, RDF["type"], CONFIG["Repository"], None))
75
77
 
76
- graph.add((repo_node, CONFIG["rep.id"], Literal(self._repo_id)))
78
+ graph.add(Quad(repo_node, CONFIG["rep.id"], Literal(self._repo_id), None))
77
79
 
78
80
  if self._title:
79
- graph.add((repo_node, RDFS["label"], Literal(self._title)))
81
+ graph.add(Quad(repo_node, RDFS["label"], Literal(self._title), None))
80
82
 
81
83
  if self._impl:
82
84
  impl_node = self._impl.add_to_graph(graph)
83
- graph.add((repo_node, CONFIG["rep.impl"], impl_node))
85
+ graph.add(Quad(repo_node, CONFIG["rep.impl"], impl_node, None))
84
86
 
85
- return graph.serialize(format="turtle").encode("utf-8")
87
+ return serialize(graph, format=RdfFormat.TURTLE)
86
88
 
87
89
  class Builder:
88
90
  """
@@ -168,14 +170,14 @@ class RepositoryConfig:
168
170
 
169
171
  class RepositoryImplConfig:
170
172
  """
171
- Base class for repository implementation configurations using RDFlib.
173
+ Base class for repository implementation configurations using .
172
174
  """
173
175
 
174
176
  def __init__(self, rep_type: str):
175
177
  self.rep_type = rep_type
176
178
  self.config_params: Dict[str, Any] = {}
177
179
 
178
- def add_to_graph(self, graph: Graph) -> URIRef:
180
+ def add_to_graph(self, graph: Dataset) -> URIRef:
179
181
  """
180
182
  Adds the repository implementation configuration to the RDF graph.
181
183
 
@@ -183,28 +185,45 @@ class RepositoryImplConfig:
183
185
  The RDF node representing this configuration.
184
186
  """
185
187
  sail_node = BNode()
186
- graph.add((sail_node, CONFIG["rep.type"], Literal(self.rep_type)))
188
+ graph.add(Quad(sail_node, CONFIG["rep.type"], Literal(self.rep_type), None))
187
189
  for key, value in self.config_params.items():
188
190
  if isinstance(value, str):
189
- graph.add((sail_node, CONFIG[key], Literal(value)))
190
- elif isinstance(value, int):
191
+ graph.add(Quad(sail_node, CONFIG[key], Literal(value), None))
192
+ elif isinstance(value, int) and not isinstance(value, bool):
191
193
  graph.add(
192
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.integer))
194
+ Quad(
195
+ sail_node,
196
+ CONFIG[key],
197
+ Literal(value, datatype=XSD["integer"]),
198
+ None,
199
+ )
193
200
  )
194
201
  elif isinstance(value, float):
195
- graph.add((sail_node, CONFIG[key], Literal(value, datatype=XSD.double)))
202
+ graph.add(
203
+ Quad(
204
+ sail_node,
205
+ CONFIG[key],
206
+ Literal(value, datatype=XSD["double"]),
207
+ None,
208
+ )
209
+ )
196
210
  elif isinstance(value, bool):
197
211
  graph.add(
198
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.boolean))
212
+ Quad(
213
+ sail_node,
214
+ CONFIG[key],
215
+ Literal(str(value).lower(), datatype=XSD["boolean"]),
216
+ None,
217
+ )
199
218
  )
200
219
  elif isinstance(value, list):
201
220
  for item in value:
202
- graph.add((sail_node, CONFIG[key], URIRef(item))) # Assuming IRIs
221
+ graph.add(Quad(sail_node, CONFIG[key], URIRef(item), None))
203
222
  elif isinstance(value, RepositoryImplConfig) or isinstance(
204
223
  value, SailConfig
205
224
  ):
206
225
  nested_node = value.add_to_graph(graph)
207
- graph.add((sail_node, CONFIG[key], nested_node))
226
+ graph.add(Quad(sail_node, CONFIG[key], nested_node, None))
208
227
  else:
209
228
  raise ValueError(f"Unsupported configuration value type: {type(value)}")
210
229
  return sail_node
@@ -212,7 +231,7 @@ class RepositoryImplConfig:
212
231
 
213
232
  class SPARQLRepositoryConfig(RepositoryImplConfig):
214
233
  """
215
- Configuration for a SPARQLRepository using RDFlib.
234
+ Configuration for a SPARQLRepository.
216
235
  """
217
236
 
218
237
  TYPE = "openrdf:SPARQLRepository"
@@ -265,7 +284,7 @@ class SPARQLRepositoryConfig(RepositoryImplConfig):
265
284
 
266
285
  class HTTPRepositoryConfig(RepositoryImplConfig):
267
286
  """
268
- Configuration for an HTTPRepository using RDFlib.
287
+ Configuration for an HTTPRepository.
269
288
  """
270
289
 
271
290
  TYPE = "openrdf:HTTPRepository"
@@ -320,7 +339,7 @@ class HTTPRepositoryConfig(RepositoryImplConfig):
320
339
 
321
340
  class SailRepositoryConfig(RepositoryImplConfig):
322
341
  """
323
- Configuration for a SailRepository using RDFlib.
342
+ Configuration for a SailRepository.
324
343
  """
325
344
 
326
345
  TYPE = "openrdf:SailRepository"
@@ -329,7 +348,7 @@ class SailRepositoryConfig(RepositoryImplConfig):
329
348
  super().__init__(rep_type=SailRepositoryConfig.TYPE)
330
349
  self.config_params["sail.impl"] = sail_impl
331
350
 
332
- def add_to_graph(self, graph: Graph) -> URIRef:
351
+ def add_to_graph(self, graph: Dataset) -> URIRef:
333
352
  """
334
353
  Adds the SailRepository configuration to the RDF graph.
335
354
  """
@@ -364,7 +383,7 @@ class SailRepositoryConfig(RepositoryImplConfig):
364
383
 
365
384
  class DatasetRepositoryConfig(RepositoryImplConfig):
366
385
  """
367
- Configuration for a DatasetRepository using RDFlib.
386
+ Configuration for a DatasetRepository using .
368
387
  """
369
388
 
370
389
  TYPE = "openrdf:DatasetRepository"
@@ -373,7 +392,7 @@ class DatasetRepositoryConfig(RepositoryImplConfig):
373
392
  super().__init__(rep_type=DatasetRepositoryConfig.TYPE)
374
393
  self.config_params["delegate"] = delegate
375
394
 
376
- def add_to_graph(self, graph: Graph) -> URIRef:
395
+ def add_to_graph(self, graph: Dataset) -> URIRef:
377
396
  """
378
397
  Adds the DatasetRepository configuration to the RDF Graph
379
398
  """
@@ -390,7 +409,7 @@ class DatasetRepositoryConfig(RepositoryImplConfig):
390
409
 
391
410
  class SailConfig:
392
411
  """
393
- Base class for SAIL configurations using RDFlib.
412
+ Base class for SAIL configurations using .
394
413
  """
395
414
 
396
415
  def __init__(
@@ -410,7 +429,7 @@ class SailConfig:
410
429
  default_query_evaluation_mode
411
430
  )
412
431
 
413
- def add_to_graph(self, graph: Graph) -> URIRef:
432
+ def add_to_graph(self, graph: Dataset) -> URIRef:
414
433
  """
415
434
  Adds the SAIL configuration to the RDF graph.
416
435
 
@@ -418,28 +437,45 @@ class SailConfig:
418
437
  The RDF node representing this configuration.
419
438
  """
420
439
  sail_node = BNode()
421
- graph.add((sail_node, CONFIG["sail.type"], Literal(self.sail_type)))
440
+ graph.add(Quad(sail_node, CONFIG["sail.type"], Literal(self.sail_type), None))
422
441
  for key, value in self.config_params.items():
423
442
  if isinstance(value, str):
424
- graph.add((sail_node, CONFIG[key], Literal(value)))
425
- elif isinstance(value, int):
443
+ graph.add(Quad(sail_node, CONFIG[key], Literal(value), None))
444
+ elif isinstance(value, bool):
426
445
  graph.add(
427
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.integer))
446
+ Quad(
447
+ sail_node,
448
+ CONFIG[key],
449
+ Literal(str(value).lower(), datatype=XSD["boolean"]),
450
+ None,
451
+ )
452
+ )
453
+ elif isinstance(value, int) and not isinstance(value, bool):
454
+ graph.add(
455
+ Quad(
456
+ sail_node,
457
+ CONFIG[key],
458
+ Literal(str(value), datatype=XSD["integer"]),
459
+ None,
460
+ )
428
461
  )
429
462
  elif isinstance(value, float):
430
- graph.add((sail_node, CONFIG[key], Literal(value, datatype=XSD.double)))
431
- elif isinstance(value, bool):
432
463
  graph.add(
433
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.boolean))
464
+ Quad(
465
+ sail_node,
466
+ CONFIG[key],
467
+ Literal(str(value), datatype=XSD["double"]),
468
+ None,
469
+ )
434
470
  )
435
471
  elif isinstance(value, list):
436
472
  for item in value:
437
- graph.add((sail_node, CONFIG[key], URIRef(item)))
473
+ graph.add(Quad(sail_node, CONFIG[key], URIRef(item), None))
438
474
  elif isinstance(value, SailConfig) or isinstance(
439
475
  value, RepositoryImplConfig
440
476
  ):
441
477
  nested_node = value.add_to_graph(graph)
442
- graph.add((sail_node, CONFIG[key], nested_node))
478
+ graph.add(Quad(sail_node, CONFIG[key], nested_node, None))
443
479
  else:
444
480
  raise ValueError(f"Unsupported configuration value type: {type(value)}")
445
481
  return sail_node
@@ -447,7 +483,7 @@ class SailConfig:
447
483
 
448
484
  class MemoryStoreConfig(SailConfig):
449
485
  """
450
- Configuration for a MemoryStore using RDFlib.
486
+ Configuration for a MemoryStore using .
451
487
  """
452
488
 
453
489
  TYPE = "openrdf:MemoryStore"
@@ -543,7 +579,7 @@ class MemoryStoreConfig(SailConfig):
543
579
 
544
580
  class NativeStoreConfig(SailConfig):
545
581
  """
546
- Configuration for a NativeStore using RDFlib.
582
+ Configuration for a NativeStore using .
547
583
  """
548
584
 
549
585
  TYPE = "openrdf:NativeStore"
@@ -711,7 +747,7 @@ class NativeStoreConfig(SailConfig):
711
747
 
712
748
  class ElasticsearchStoreConfig(SailConfig):
713
749
  """
714
- Configuration for an ElasticsearchStore using RDFlib.
750
+ Configuration for an ElasticsearchStore using .
715
751
  """
716
752
 
717
753
  TYPE = "rdf4j:ElasticsearchStore"
@@ -835,7 +871,7 @@ class ElasticsearchStoreConfig(SailConfig):
835
871
 
836
872
  class SchemaCachingRDFSInferencerConfig(SailConfig):
837
873
  """
838
- Configuration for the RDF Schema inferencer using RDFlib.
874
+ Configuration for the RDF Schema inferencer using .
839
875
  """
840
876
 
841
877
  TYPE = "rdf4j:SchemaCachingRDFSInferencer"
@@ -861,7 +897,7 @@ class SchemaCachingRDFSInferencerConfig(SailConfig):
861
897
  )
862
898
  self.config_params["delegate"] = delegate
863
899
 
864
- def add_to_graph(self, graph: Graph) -> URIRef:
900
+ def add_to_graph(self, graph: Dataset) -> URIRef:
865
901
  """
866
902
  Adds the SchemaCachingRDFSInferencer configuration to the RDF graph.
867
903
 
@@ -873,7 +909,7 @@ class SchemaCachingRDFSInferencerConfig(SailConfig):
873
909
  """
874
910
  sail_node = super().add_to_graph(graph)
875
911
  delegate_node = self.config_params["delegate"].to_rdf(graph)
876
- graph.add((sail_node, CONFIG.delegate, delegate_node))
912
+ graph.add(Quad(sail_node, CONFIG.delegate, delegate_node, None))
877
913
  return sail_node
878
914
 
879
915
  class Builder:
@@ -928,7 +964,7 @@ class SchemaCachingRDFSInferencerConfig(SailConfig):
928
964
 
929
965
  class DirectTypeHierarchyInferencerConfig(SailConfig):
930
966
  """
931
- Configuration for the Direct Type inferencer using RDFlib.
967
+ Configuration for the Direct Type inferencer using .
932
968
  """
933
969
 
934
970
  TYPE = "openrdf:DirectTypeHierarchyInferencer"
@@ -954,7 +990,7 @@ class DirectTypeHierarchyInferencerConfig(SailConfig):
954
990
  )
955
991
  self.config_params["delegate"] = delegate
956
992
 
957
- def add_to_graph(self, graph: Graph) -> URIRef:
993
+ def add_to_graph(self, graph: Dataset) -> URIRef:
958
994
  """
959
995
  Adds the DirectTypeHierarchyInferencerConfig to the graph
960
996
 
@@ -966,7 +1002,7 @@ class DirectTypeHierarchyInferencerConfig(SailConfig):
966
1002
  """
967
1003
  sail_node = super().add_to_graph(graph)
968
1004
  delegate_node = self.config_params["delegate"].to_rdf(graph)
969
- graph.add((sail_node, CONFIG["delegate"], delegate_node))
1005
+ graph.add(Quad(sail_node, CONFIG["delegate"], delegate_node, None))
970
1006
  return sail_node
971
1007
 
972
1008
  class Builder:
@@ -1027,7 +1063,7 @@ class DirectTypeHierarchyInferencerConfig(SailConfig):
1027
1063
 
1028
1064
  class SHACLSailConfig(SailConfig):
1029
1065
  """
1030
- Configuration for the SHACL Sail using RDFlib.
1066
+ Configuration for the SHACL Sail using .
1031
1067
  """
1032
1068
 
1033
1069
  TYPE = "rdf4j:ShaclSail"
@@ -1127,7 +1163,7 @@ class SHACLSailConfig(SailConfig):
1127
1163
  validation_results_limit_per_constraint
1128
1164
  )
1129
1165
 
1130
- def add_to_graph(self, graph: Graph) -> URIRef:
1166
+ def add_to_graph(self, graph: Dataset) -> URIRef:
1131
1167
  """
1132
1168
  Adds the SHACLSailConfig to the RDF graph.
1133
1169
 
@@ -1139,21 +1175,38 @@ class SHACLSailConfig(SailConfig):
1139
1175
  """
1140
1176
  sail_node = super().add_to_graph(graph) # Get the basic node
1141
1177
  delegate_node = self.config_params["delegate"].to_rdf(graph)
1142
- graph.add((sail_node, CONFIG.delegate, delegate_node))
1178
+ graph.add(Quad(sail_node, CONFIG.delegate, delegate_node, None))
1143
1179
 
1144
1180
  # Add SHACL-specific parameters
1145
1181
  for key, value in self.config_params.items():
1146
1182
  if key != "delegate": # Delegate is already handled
1147
1183
  if isinstance(value, bool):
1148
1184
  graph.add(
1149
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.boolean))
1185
+ Quad(
1186
+ sail_node,
1187
+ CONFIG[key],
1188
+ Literal(str(value).lower(), datatype=XSD["boolean"]),
1189
+ None,
1190
+ )
1150
1191
  )
1151
- elif isinstance(value, int):
1192
+ elif isinstance(value, int) and not isinstance(value, bool):
1152
1193
  graph.add(
1153
- (sail_node, CONFIG[key], Literal(value, datatype=XSD.integer))
1194
+ Quad(
1195
+ sail_node,
1196
+ CONFIG[key],
1197
+ Literal(str(value), datatype=XSD["integer"]),
1198
+ None,
1199
+ )
1154
1200
  )
1155
1201
  else:
1156
- graph.add((sail_node, CONFIG[key], Literal(value)))
1202
+ graph.add(
1203
+ Quad(
1204
+ sail_node,
1205
+ CONFIG[key],
1206
+ Literal(value),
1207
+ None,
1208
+ )
1209
+ )
1157
1210
  return sail_node
1158
1211
 
1159
1212
  class Builder:
@@ -1,14 +1,20 @@
1
- from typing import Optional, Tuple, TypeAlias
1
+ from typing import TypeAlias
2
2
 
3
- from rdflib import URIRef as _URIRef
4
- from rdflib.term import IdentifiedNode, Node
3
+ import pyoxigraph as og
5
4
 
6
- IRI: TypeAlias = _URIRef
5
+ IRI: TypeAlias = og.NamedNode
6
+ BlankNode: TypeAlias = og.BlankNode
7
+ Literal: TypeAlias = og.Literal
8
+ DefaultGraph: TypeAlias = og.DefaultGraph
9
+ Variable: TypeAlias = og.Variable
7
10
 
11
+ Quad: TypeAlias = og.Quad
12
+ Triple: TypeAlias = og.Triple
8
13
 
9
- Subject: TypeAlias = Node
10
- Predicate: TypeAlias = Node
11
- Object: TypeAlias = Node
12
- Context: TypeAlias = Optional[IdentifiedNode]
14
+ Subject: TypeAlias = IRI | BlankNode | Triple
15
+ Predicate: TypeAlias = IRI
16
+ Object: TypeAlias = IRI | BlankNode | Literal
17
+ Context: TypeAlias = IRI | BlankNode | DefaultGraph | None
13
18
 
14
- RDFStatement: TypeAlias = Tuple[Subject, Predicate, Object, Context]
19
+
20
+ QuadResultSet: TypeAlias = og.QuadParser
@@ -4,3 +4,4 @@ from rdf4j_python.model import Namespace
4
4
  RDF = Namespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
5
5
  RDFS = Namespace("rdfs", "http://www.w3.org/2000/01/rdf-schema#")
6
6
  EXAMPLE = Namespace("ex", "http://example.org/")
7
+ XSD = Namespace("xsd", "http://www.w3.org/2001/XMLSchema#")
@@ -1,22 +1,20 @@
1
+ from io import BytesIO
1
2
  from typing import Iterable
2
3
 
3
- from rdf4j_python.model.term import RDFStatement
4
+ import pyoxigraph as og
4
5
 
6
+ from rdf4j_python.model.term import Quad, Triple
5
7
 
6
- def serialize_statements(statements: Iterable[RDFStatement]) -> str:
8
+
9
+ def serialize_statements(statements: Iterable[Quad] | Iterable[Triple]) -> bytes:
7
10
  """Serializes statements to RDF data.
8
11
 
9
12
  Args:
10
- statements (Iterable[RDFStatement]): RDF statements.
13
+ statements (Iterable[Quad] | Iterable[Triple]): RDF statements.
11
14
 
12
15
  Returns:
13
- str: Serialized RDF data.
16
+ bytes: Serialized RDF data.
14
17
  """
15
- lines = []
16
- for subj, pred, obj, ctx in statements:
17
- parts = [subj.n3(), pred.n3(), obj.n3()]
18
- if ctx:
19
- parts.append(ctx.n3())
20
- parts.append(".")
21
- lines.append(" ".join(parts))
22
- return "\n".join(lines) + "\n"
18
+ io = BytesIO()
19
+ og.serialize(statements, output=io, format=og.RdfFormat.N_QUADS)
20
+ return io.getvalue()
@@ -1,13 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rdf4j-python
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: The Python client for RDF4J
5
5
  Author-email: Chengxu Bian <cbian564@gmail.com>
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: httpx>=0.28.1
10
- Requires-Dist: rdflib>=7.1.4
10
+ Requires-Dist: pyoxigraph>=0.4.10
11
+ Provides-Extra: sparqlwrapper
12
+ Requires-Dist: sparqlwrapper>=2.0.0; extra == "sparqlwrapper"
11
13
  Dynamic: license-file
12
14
 
13
15
  # 🐍 rdf4j-python
@@ -60,6 +62,7 @@ async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
60
62
  Literal("test_object"),
61
63
  )
62
64
  await repo.get_statements(subject=IRI("http://example.com/subject"))
65
+ results = await repo.query("SELECT * WHERE { ?s ?p ?o }")
63
66
  ```
64
67
 
65
68
  For more detailed examples, refer to the [examples](https://github.com/odysa/rdf4j-python/tree/main/examples) directory.
@@ -0,0 +1,23 @@
1
+ rdf4j_python/__init__.py,sha256=E8gojaWuLHo2AfNn5HBc5cF7K8_dK2jOBcZaH_qoZs4,347
2
+ rdf4j_python/_client/__init__.py,sha256=L5q5RTHXCNyHp2WNP4xTemGXNntUW4RF_QJPoCWciUQ,98
3
+ rdf4j_python/_client/_client.py,sha256=JfHFudRDVkzmb_jWx1u2meqqFONImBQHuaoYkb4mWPc,7390
4
+ rdf4j_python/_driver/__init__.py,sha256=au0r15mQBVaJkqBknw9CoVswe7_rPPFs1wFWI_ttdy4,224
5
+ rdf4j_python/_driver/_async_named_graph.py,sha256=BqJRpN-JzGpvlSnWY2RrM5TrnIHg6W4PortZ0y-4mgw,2685
6
+ rdf4j_python/_driver/_async_rdf4j_db.py,sha256=POJ2-5EiyFOjX6ykjxbm0RH7yjtU6mXCY2PlVYidLDI,4497
7
+ rdf4j_python/_driver/_async_repository.py,sha256=sW52MvZfbPeqJciFk4bgTHcDpxlZpXSikEsYflAmYHQ,15251
8
+ rdf4j_python/exception/__init__.py,sha256=PFdUyIMsHIL5e2P2z33Qr2pwlUAJVI0G5T8114W4-1A,83
9
+ rdf4j_python/exception/repo_exception.py,sha256=WXlfIYzOYfNU8LpwtOct9fAZADR-P3cZx4jAX9v_HaA,704
10
+ rdf4j_python/model/__init__.py,sha256=wHboqZX2bN3AubXvWRwKOWwnrefpeiiB_nnry2Ba_a4,176
11
+ rdf4j_python/model/_namespace.py,sha256=6iOvPc2Z6XFY44wmVucQCrjZbFuxdBtoTfDq_bSHJS0,3854
12
+ rdf4j_python/model/_repository_info.py,sha256=fdKwjoQz6_D95Q8uZEuEYhXEUeqElsdBkHRCRRNxjzM,2010
13
+ rdf4j_python/model/repository_config.py,sha256=6s-b0NPVILOLbmhAdTYR2xia7ErACvWvCUrAYcvZZng,56702
14
+ rdf4j_python/model/term.py,sha256=JBxndQESR2KEY6y9s6TqoELUQaegKcIUO0ctR818QaA,508
15
+ rdf4j_python/model/vocabulary.py,sha256=Yam0F_YNlO-7wDi2fc0DkAqIKB4ZqCpqq56wKRrFAcw,307
16
+ rdf4j_python/utils/__init__.py,sha256=LAyzkmO5QOIjJogQE1m4Eszwb2cCU8ytKRfhjAGoraw,34
17
+ rdf4j_python/utils/const.py,sha256=HKH9ZGe7m_dvMx1RwT6zhu2HUkvwOX2Y4e8vQFs3uE8,849
18
+ rdf4j_python/utils/helpers.py,sha256=4ubvrx3OV_0Y2_YECNIJhkJUB-JthdCJA8d6Hz_G_kE,506
19
+ rdf4j_python-0.1.4.dist-info/licenses/LICENSE,sha256=sGjA7CzoCG1LVlkh0ZB76ZdgWHVpUFegLU41YYDkGIA,1499
20
+ rdf4j_python-0.1.4.dist-info/METADATA,sha256=wdaugJ9Oxn4-fgfwifMaIlK3bplUxHJan54ciVAtZKo,3011
21
+ rdf4j_python-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
+ rdf4j_python-0.1.4.dist-info/top_level.txt,sha256=Lf2K8d8WcEkmvo5giLGuZ3gl20rNEwMssyAFBeVzbCs,13
23
+ rdf4j_python-0.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,48 +0,0 @@
1
- from abc import ABC
2
- from typing import Mapping, Optional
3
-
4
- from rdflib.term import Identifier, Literal, URIRef, Variable
5
-
6
-
7
- class _BaseModel(ABC):
8
- """Abstract base class providing utility methods for parsing RDF query results."""
9
-
10
- @staticmethod
11
- def get_literal(
12
- result: Mapping[Variable, Identifier],
13
- var_name: str,
14
- default: Optional[str] = None,
15
- ) -> Optional[str]:
16
- """
17
- Extracts a literal value from a SPARQL query result.
18
-
19
- Args:
20
- result (Mapping[Variable, Identifier]): A mapping of variable bindings from a query result.
21
- var_name (str): The variable name to extract.
22
- default (Optional[str], optional): The value to return if the variable is not found or is not a Literal. Defaults to None.
23
-
24
- Returns:
25
- Optional[str]: The Python representation of the literal, or the default value.
26
- """
27
- val = result.get(Variable(var_name))
28
- return val.toPython() if isinstance(val, Literal) else default
29
-
30
- @staticmethod
31
- def get_uri(
32
- result: Mapping[Variable, Identifier],
33
- var_name: str,
34
- default: Optional[str] = None,
35
- ) -> Optional[str]:
36
- """
37
- Extracts a URI value from a SPARQL query result.
38
-
39
- Args:
40
- result (Mapping[Variable, Identifier]): A mapping of variable bindings from a query result.
41
- var_name (str): The variable name to extract.
42
- default (Optional[str], optional): The value to return if the variable is not found or is not a URIRef. Defaults to None.
43
-
44
- Returns:
45
- Optional[str]: The URI string, or the default value.
46
- """
47
- val = result.get(Variable(var_name))
48
- return str(val) if isinstance(val, URIRef) else default
@@ -1,38 +0,0 @@
1
- from rdflib import Dataset as _Dataset
2
-
3
- from rdf4j_python.model.term import IRI
4
-
5
-
6
- class RDF4JDataSet(_Dataset):
7
- """
8
- An RDFLib Dataset subclass with RDF4J-specific utility methods.
9
- """
10
-
11
- def as_list(self) -> list[tuple]:
12
- """
13
- Converts all quads in the dataset to a list of 4-tuples.
14
-
15
- Replaces the RDF4J default context IRI ("urn:x-rdflib:default") with None.
16
-
17
- Returns:
18
- list[tuple]: A list of (subject, predicate, object, context) quads.
19
- """
20
- return [
21
- (s, p, o, ctx if ctx != IRI("urn:x-rdflib:default") else None)
22
- for s, p, o, ctx in self.quads((None, None, None, None))
23
- ]
24
-
25
- @staticmethod
26
- def from_raw_text(text: str) -> "RDF4JDataSet":
27
- """
28
- Parses a string of N-Quads RDF data into an RDF4JDataSet.
29
-
30
- Args:
31
- text (str): The RDF data in N-Quads format.
32
-
33
- Returns:
34
- RDF4JDataSet: A populated dataset.
35
- """
36
- ds = RDF4JDataSet()
37
- ds.parse(data=text, format="nquads")
38
- return ds
@@ -1,25 +0,0 @@
1
- rdf4j_python/__init__.py,sha256=E8gojaWuLHo2AfNn5HBc5cF7K8_dK2jOBcZaH_qoZs4,347
2
- rdf4j_python/_client/__init__.py,sha256=L5q5RTHXCNyHp2WNP4xTemGXNntUW4RF_QJPoCWciUQ,98
3
- rdf4j_python/_client/_client.py,sha256=JfHFudRDVkzmb_jWx1u2meqqFONImBQHuaoYkb4mWPc,7390
4
- rdf4j_python/_driver/__init__.py,sha256=au0r15mQBVaJkqBknw9CoVswe7_rPPFs1wFWI_ttdy4,224
5
- rdf4j_python/_driver/_async_named_graph.py,sha256=zpYr6x_9aI2wHH0Pj71LlCKkHFFanz7G77Tz5azXlg4,2642
6
- rdf4j_python/_driver/_async_rdf4j_db.py,sha256=u6r4A4_CTp4JMEswl0I5rMjsuWnMkQV_TJrvF6u9R94,4403
7
- rdf4j_python/_driver/_async_repository.py,sha256=NKM9IFLTNMepVCx_UeWc7h0BTxHMKfDnUcThz97pVCs,14075
8
- rdf4j_python/exception/__init__.py,sha256=PFdUyIMsHIL5e2P2z33Qr2pwlUAJVI0G5T8114W4-1A,83
9
- rdf4j_python/exception/repo_exception.py,sha256=WXlfIYzOYfNU8LpwtOct9fAZADR-P3cZx4jAX9v_HaA,704
10
- rdf4j_python/model/__init__.py,sha256=eUvfFEPgDsbq37eIpd_dlvjpQPGuRwkKWNfqa0c2QwM,231
11
- rdf4j_python/model/_base_model.py,sha256=PyhvLhaseKaFuRU70xord8EgIfO88-UVcllkuRobE14,1780
12
- rdf4j_python/model/_dataset.py,sha256=-nYTm8Fz1CGsLL2ykmtGEJ9Jv4u8FC2Dgl_31LeoGhM,1065
13
- rdf4j_python/model/_namespace.py,sha256=yaH-MjMFsUfCFadlo25MgHf9zaRbk-wkn_BgtmemVo4,3259
14
- rdf4j_python/model/_repository_info.py,sha256=zSL3o_QWL06xYbnpFtXIg-PqFiRbwDFPb1aiy2JufYQ,1668
15
- rdf4j_python/model/repository_config.py,sha256=WPXJAbZ2pM594Uh_r3zI6N1fqObSsk74ArVZTTdqPks,55012
16
- rdf4j_python/model/term.py,sha256=FkK8-HG6h79dAYO_qiTYTxvu8t-d5zVY5FtgJrW997o,352
17
- rdf4j_python/model/vocabulary.py,sha256=R9k9dzDPwRBEgwjIF6sNZh3hL41R7GZ1eSJKb8w7IaY,247
18
- rdf4j_python/utils/__init__.py,sha256=LAyzkmO5QOIjJogQE1m4Eszwb2cCU8ytKRfhjAGoraw,34
19
- rdf4j_python/utils/const.py,sha256=HKH9ZGe7m_dvMx1RwT6zhu2HUkvwOX2Y4e8vQFs3uE8,849
20
- rdf4j_python/utils/helpers.py,sha256=xnMB_imsybGQ2GiHvXK4wEpcs4ADiqZ4ez0yop_ko8E,577
21
- rdf4j_python-0.1.2.dist-info/licenses/LICENSE,sha256=sGjA7CzoCG1LVlkh0ZB76ZdgWHVpUFegLU41YYDkGIA,1499
22
- rdf4j_python-0.1.2.dist-info/METADATA,sha256=7V13OG7A4fxFPLcwbIUjsqUCVDwC1dlqXE5YSHw7PbU,2852
23
- rdf4j_python-0.1.2.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
24
- rdf4j_python-0.1.2.dist-info/top_level.txt,sha256=Lf2K8d8WcEkmvo5giLGuZ3gl20rNEwMssyAFBeVzbCs,13
25
- rdf4j_python-0.1.2.dist-info/RECORD,,