rdf4j-python 0.1.3__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.
@@ -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
- 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}
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.
@@ -97,6 +127,7 @@ class AsyncRdf4JRepository:
97
127
  query_solutions = og.parse_query_results(
98
128
  response.text, format=og.QueryResultsFormat.JSON
99
129
  )
130
+ assert isinstance(query_solutions, og.QuerySolutions)
100
131
  return [
101
132
  Namespace.from_sparql_query_solution(query_solution)
102
133
  for query_solution in query_solutions
@@ -59,12 +59,12 @@ class RepositoryConfig:
59
59
  """
60
60
  return self._title
61
61
 
62
- def to_turtle(self) -> str:
62
+ def to_turtle(self) -> bytes | None:
63
63
  """
64
64
  Serializes the Repository configuration to Turtle syntax using .
65
65
 
66
66
  Returns:
67
- 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.
68
68
  The serialization includes the repository ID, optional human-readable title,
69
69
  and nested repository implementation configuration if available.
70
70
 
@@ -909,7 +909,7 @@ class SchemaCachingRDFSInferencerConfig(SailConfig):
909
909
  """
910
910
  sail_node = super().add_to_graph(graph)
911
911
  delegate_node = self.config_params["delegate"].to_rdf(graph)
912
- graph.add((sail_node, CONFIG.delegate, delegate_node))
912
+ graph.add(Quad(sail_node, CONFIG.delegate, delegate_node, None))
913
913
  return sail_node
914
914
 
915
915
  class Builder:
@@ -1002,7 +1002,7 @@ class DirectTypeHierarchyInferencerConfig(SailConfig):
1002
1002
  """
1003
1003
  sail_node = super().add_to_graph(graph)
1004
1004
  delegate_node = self.config_params["delegate"].to_rdf(graph)
1005
- graph.add((sail_node, CONFIG["delegate"], delegate_node))
1005
+ graph.add(Quad(sail_node, CONFIG["delegate"], delegate_node, None))
1006
1006
  return sail_node
1007
1007
 
1008
1008
  class Builder:
@@ -1175,7 +1175,7 @@ class SHACLSailConfig(SailConfig):
1175
1175
  """
1176
1176
  sail_node = super().add_to_graph(graph) # Get the basic node
1177
1177
  delegate_node = self.config_params["delegate"].to_rdf(graph)
1178
- graph.add((sail_node, CONFIG.delegate, delegate_node))
1178
+ graph.add(Quad(sail_node, CONFIG.delegate, delegate_node, None))
1179
1179
 
1180
1180
  # Add SHACL-specific parameters
1181
1181
  for key, value in self.config_params.items():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rdf4j-python
3
- Version: 0.1.3
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
@@ -8,6 +8,8 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: httpx>=0.28.1
10
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.
@@ -3,21 +3,21 @@ rdf4j_python/_client/__init__.py,sha256=L5q5RTHXCNyHp2WNP4xTemGXNntUW4RF_QJPoCWc
3
3
  rdf4j_python/_client/_client.py,sha256=JfHFudRDVkzmb_jWx1u2meqqFONImBQHuaoYkb4mWPc,7390
4
4
  rdf4j_python/_driver/__init__.py,sha256=au0r15mQBVaJkqBknw9CoVswe7_rPPFs1wFWI_ttdy4,224
5
5
  rdf4j_python/_driver/_async_named_graph.py,sha256=BqJRpN-JzGpvlSnWY2RrM5TrnIHg6W4PortZ0y-4mgw,2685
6
- rdf4j_python/_driver/_async_rdf4j_db.py,sha256=LkeLwLhp_lSYhrJVY98LHv9V4jkxF0U5RWQiZmVI9zw,4435
7
- rdf4j_python/_driver/_async_repository.py,sha256=E6DfW05LFh5KY2X081tW9gg1ksr7DyiM90_j29v71VQ,14212
6
+ rdf4j_python/_driver/_async_rdf4j_db.py,sha256=POJ2-5EiyFOjX6ykjxbm0RH7yjtU6mXCY2PlVYidLDI,4497
7
+ rdf4j_python/_driver/_async_repository.py,sha256=sW52MvZfbPeqJciFk4bgTHcDpxlZpXSikEsYflAmYHQ,15251
8
8
  rdf4j_python/exception/__init__.py,sha256=PFdUyIMsHIL5e2P2z33Qr2pwlUAJVI0G5T8114W4-1A,83
9
9
  rdf4j_python/exception/repo_exception.py,sha256=WXlfIYzOYfNU8LpwtOct9fAZADR-P3cZx4jAX9v_HaA,704
10
10
  rdf4j_python/model/__init__.py,sha256=wHboqZX2bN3AubXvWRwKOWwnrefpeiiB_nnry2Ba_a4,176
11
11
  rdf4j_python/model/_namespace.py,sha256=6iOvPc2Z6XFY44wmVucQCrjZbFuxdBtoTfDq_bSHJS0,3854
12
12
  rdf4j_python/model/_repository_info.py,sha256=fdKwjoQz6_D95Q8uZEuEYhXEUeqElsdBkHRCRRNxjzM,2010
13
- rdf4j_python/model/repository_config.py,sha256=Uawni9kTjUpH3gCXQxh026NJaGVaJxDd5M-A5U9Ho_4,56654
13
+ rdf4j_python/model/repository_config.py,sha256=6s-b0NPVILOLbmhAdTYR2xia7ErACvWvCUrAYcvZZng,56702
14
14
  rdf4j_python/model/term.py,sha256=JBxndQESR2KEY6y9s6TqoELUQaegKcIUO0ctR818QaA,508
15
15
  rdf4j_python/model/vocabulary.py,sha256=Yam0F_YNlO-7wDi2fc0DkAqIKB4ZqCpqq56wKRrFAcw,307
16
16
  rdf4j_python/utils/__init__.py,sha256=LAyzkmO5QOIjJogQE1m4Eszwb2cCU8ytKRfhjAGoraw,34
17
17
  rdf4j_python/utils/const.py,sha256=HKH9ZGe7m_dvMx1RwT6zhu2HUkvwOX2Y4e8vQFs3uE8,849
18
18
  rdf4j_python/utils/helpers.py,sha256=4ubvrx3OV_0Y2_YECNIJhkJUB-JthdCJA8d6Hz_G_kE,506
19
- rdf4j_python-0.1.3.dist-info/licenses/LICENSE,sha256=sGjA7CzoCG1LVlkh0ZB76ZdgWHVpUFegLU41YYDkGIA,1499
20
- rdf4j_python-0.1.3.dist-info/METADATA,sha256=Qo5X3u9Mw5r3ABzTmHzlUEEfO01DEsFm_BL2tyfWmAU,2857
21
- rdf4j_python-0.1.3.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
22
- rdf4j_python-0.1.3.dist-info/top_level.txt,sha256=Lf2K8d8WcEkmvo5giLGuZ3gl20rNEwMssyAFBeVzbCs,13
23
- rdf4j_python-0.1.3.dist-info/RECORD,,
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