rdf4j-python 0.1.0__py3-none-any.whl → 0.1.1a0__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/__init__.py CHANGED
@@ -1,9 +1,9 @@
1
1
  from ._client import AsyncApiClient, SyncApiClient
2
- from ._driver import AsyncRdf4jDB, AsyncRepository
2
+ from ._driver import AsyncRdf4j, AsyncRdf4JRepository
3
3
 
4
4
  __all__ = [
5
5
  "AsyncApiClient",
6
6
  "SyncApiClient",
7
- "AsyncRdf4jDB",
8
- "AsyncRepository",
7
+ "AsyncRdf4j",
8
+ "AsyncRdf4JRepository",
9
9
  ]
@@ -1,7 +1,7 @@
1
- from ._async_rdf4j_db import AsyncRdf4jDB
2
- from ._async_repository import AsyncRepository
1
+ from ._async_rdf4j_db import AsyncRdf4j
2
+ from ._async_repository import AsyncRdf4JRepository
3
3
 
4
4
  __all__ = [
5
- "AsyncRdf4jDB",
6
- "AsyncRepository",
5
+ "AsyncRdf4j",
6
+ "AsyncRdf4JRepository",
7
7
  ]
@@ -8,13 +8,13 @@ from rdf4j_python.exception.repo_exception import (
8
8
  RepositoryCreationException,
9
9
  RepositoryDeletionException,
10
10
  )
11
- from rdf4j_python.model.repository import RepositoryInfo
11
+ from rdf4j_python.model._repository_info import RepositoryMetadata
12
12
  from rdf4j_python.utils.const import Rdf4jContentType
13
13
 
14
- from ._async_repository import AsyncRepository
14
+ from ._async_repository import AsyncRdf4JRepository
15
15
 
16
16
 
17
- class AsyncRdf4jDB:
17
+ class AsyncRdf4j:
18
18
  _client: AsyncApiClient
19
19
  _base_url: str
20
20
 
@@ -33,7 +33,7 @@ class AsyncRdf4jDB:
33
33
  response.raise_for_status()
34
34
  return response.text
35
35
 
36
- async def list_repositories(self) -> list[RepositoryInfo]:
36
+ async def list_repositories(self) -> list[RepositoryMetadata]:
37
37
  """
38
38
  List all RDF4J repositories.
39
39
 
@@ -48,24 +48,25 @@ class AsyncRdf4jDB:
48
48
  )
49
49
 
50
50
  return [
51
- RepositoryInfo.from_rdflib_binding(binding) for binding in result.bindings
51
+ RepositoryMetadata.from_rdflib_binding(binding)
52
+ for binding in result.bindings
52
53
  ]
53
54
 
54
- async def get_repository(self, repository_id: str) -> AsyncRepository:
55
+ async def get_repository(self, repository_id: str) -> AsyncRdf4JRepository:
55
56
  """
56
57
  Get an AsyncRepository instance for the specified repository ID.
57
58
 
58
59
  :param repository_id: The ID of the repository.
59
60
  :return: An instance of AsyncRepository.
60
61
  """
61
- return AsyncRepository(self._client, repository_id)
62
+ return AsyncRdf4JRepository(self._client, repository_id)
62
63
 
63
64
  async def create_repository(
64
65
  self,
65
66
  repository_id: str,
66
67
  rdf_config_data: str,
67
68
  content_type: Union[Rdf4jContentType, str] = Rdf4jContentType.TURTLE,
68
- ):
69
+ ) -> AsyncRdf4JRepository:
69
70
  """
70
71
  Create a new RDF4J repository.
71
72
 
@@ -86,6 +87,7 @@ class AsyncRdf4jDB:
86
87
  raise RepositoryCreationException(
87
88
  f"Repository creation failed: {response.status_code} - {response.text}"
88
89
  )
90
+ return AsyncRdf4JRepository(self._client, repository_id)
89
91
 
90
92
  async def delete_repository(self, repository_id: str):
91
93
  """
@@ -1,8 +1,17 @@
1
+ import httpx
2
+ import rdflib
3
+
1
4
  from rdf4j_python import AsyncApiClient
5
+ from rdf4j_python.exception.repo_exception import (
6
+ NamespaceException,
7
+ RepositoryInternalException,
8
+ RepositoryNotFoundException,
9
+ )
10
+ from rdf4j_python.model._namespace import Namespace
2
11
  from rdf4j_python.utils.const import Rdf4jContentType
3
12
 
4
13
 
5
- class AsyncRepository:
14
+ class AsyncRdf4JRepository:
6
15
  def __init__(self, client: AsyncApiClient, repository_id: str):
7
16
  self._client = client
8
17
  self._repository_id = repository_id
@@ -17,6 +26,7 @@ class AsyncRepository:
17
26
  params = {"query": sparql_query, "infer": str(infer).lower()}
18
27
  headers = {"Accept": accept.value}
19
28
  response = await self._client.get(path, params=params, headers=headers)
29
+ self._handle_repo_not_found_exception(response)
20
30
  if "json" in response.headers.get("Content-Type", ""):
21
31
  return response.json()
22
32
  return response.text
@@ -25,6 +35,7 @@ class AsyncRepository:
25
35
  path = f"/repositories/{self._repository_id}/statements"
26
36
  headers = {"Content-Type": Rdf4jContentType.SPARQL_UPDATE.value}
27
37
  response = await self._client.post(path, data=sparql_update, headers=headers)
38
+ self._handle_repo_not_found_exception(response)
28
39
  response.raise_for_status()
29
40
 
30
41
  async def replace_statements(
@@ -33,19 +44,66 @@ class AsyncRepository:
33
44
  path = f"/repositories/{self._repository_id}/statements"
34
45
  headers = {"Content-Type": content_type.value}
35
46
  response = await self._client.put(path, data=rdf_data, headers=headers)
47
+ self._handle_repo_not_found_exception(response)
36
48
  response.raise_for_status()
37
49
 
38
50
  async def get_namespaces(self):
39
51
  path = f"/repositories/{self._repository_id}/namespaces"
40
- response = await self._client.get(path)
41
- if Rdf4jContentType.SPARQL_RESULTS_JSON in response.headers.get(
42
- "Content-Type", ""
43
- ):
44
- return response.json()
45
- return response.text
52
+ headers = {"Accept": Rdf4jContentType.SPARQL_RESULTS_JSON}
53
+ response = await self._client.get(path, headers=headers)
54
+
55
+ result = rdflib.query.Result.parse(
56
+ response, format=Rdf4jContentType.SPARQL_RESULTS_JSON
57
+ )
58
+ self._handle_repo_not_found_exception(response)
59
+ return [Namespace.from_rdflib_binding(binding) for binding in result.bindings]
46
60
 
47
61
  async def set_namespace(self, prefix: str, namespace: str):
48
62
  path = f"/repositories/{self._repository_id}/namespaces/{prefix}"
49
63
  headers = {"Content-Type": Rdf4jContentType.NTRIPLES.value}
50
- response = await self._client.put(path, data=namespace, headers=headers)
64
+ response = await self._client.put(path, content=namespace, headers=headers)
65
+ self._handle_repo_not_found_exception(response)
66
+ if response.status_code != httpx.codes.NO_CONTENT:
67
+ raise NamespaceException(f"Failed to set namespace: {response.text}")
68
+
69
+ async def get_namespace(self, prefix: str) -> Namespace:
70
+ path = f"/repositories/{self._repository_id}/namespaces/{prefix}"
71
+ headers = {"Accept": Rdf4jContentType.NTRIPLES.value}
72
+ response = await self._client.get(path, headers=headers)
73
+ self._handle_repo_not_found_exception(response)
74
+
75
+ if response.status_code != httpx.codes.OK:
76
+ raise NamespaceException(f"Failed to get namespace: {response.text}")
77
+
78
+ return Namespace(prefix, response.text)
79
+
80
+ async def delete_namespace(self, prefix: str):
81
+ path = f"/repositories/{self._repository_id}/namespaces/{prefix}"
82
+ response = await self._client.delete(path)
83
+ self._handle_repo_not_found_exception(response)
84
+ response.raise_for_status()
85
+
86
+ async def size(self) -> int:
87
+ path = f"/repositories/{self._repository_id}/size"
88
+ response = await self._client.get(path)
89
+ self._handle_repo_not_found_exception(response)
90
+
91
+ if response.status_code != httpx.codes.OK:
92
+ raise RepositoryInternalException(f"Failed to get size: {response.text}")
93
+
94
+ return int(response.text.strip())
95
+
96
+ async def add_statement(self, subject: str, predicate: str, object: str):
97
+ path = f"/repositories/{self._repository_id}/statements"
98
+ headers = {"Content-Type": Rdf4jContentType.NTRIPLES.value}
99
+ response = await self._client.post(
100
+ path, data=f"{subject} {predicate} {object}.", headers=headers
101
+ )
102
+ self._handle_repo_not_found_exception(response)
51
103
  response.raise_for_status()
104
+
105
+ def _handle_repo_not_found_exception(self, response: httpx.Response):
106
+ if response.status_code == httpx.codes.NOT_FOUND:
107
+ raise RepositoryNotFoundException(
108
+ f"Repository {self._repository_id} not found"
109
+ )
@@ -2,3 +2,12 @@ class RepositoryCreationException(Exception): ...
2
2
 
3
3
 
4
4
  class RepositoryDeletionException(Exception): ...
5
+
6
+
7
+ class NamespaceException(Exception): ...
8
+
9
+
10
+ class RepositoryNotFoundException(Exception): ...
11
+
12
+
13
+ class RepositoryInternalException(Exception): ...
@@ -0,0 +1,16 @@
1
+ from ._namespace import IRI, Namespace
2
+ from ._repository_config import (
3
+ MemoryStoreConfig,
4
+ NativeStoreConfig,
5
+ RepositoryConfig,
6
+ )
7
+ from ._repository_info import RepositoryMetadata
8
+
9
+ __all__ = [
10
+ "IRI",
11
+ "Namespace",
12
+ "RepositoryConfig",
13
+ "MemoryStoreConfig",
14
+ "NativeStoreConfig",
15
+ "RepositoryMetadata",
16
+ ]
@@ -0,0 +1,56 @@
1
+ from typing import Mapping
2
+
3
+ from rdflib import URIRef
4
+ from rdflib.namespace import Namespace as RdflibNamespace
5
+ from rdflib.term import Identifier, Variable
6
+
7
+ from ._base_model import _BaseModel
8
+
9
+
10
+ class IRI(URIRef): ...
11
+
12
+
13
+ class Namespace:
14
+ _prefix: str
15
+ _namespace: RdflibNamespace
16
+
17
+ def __init__(self, prefix: str, namespace: str):
18
+ self._prefix = prefix
19
+ self._namespace = RdflibNamespace(namespace)
20
+
21
+ @classmethod
22
+ def from_rdflib_binding(cls, binding: Mapping[Variable, Identifier]) -> "Namespace":
23
+ prefix = _BaseModel.get_literal(binding, "prefix", "")
24
+ namespace = _BaseModel.get_literal(binding, "namespace", "")
25
+ return cls(
26
+ prefix=prefix,
27
+ namespace=namespace,
28
+ )
29
+
30
+ def __str__(self):
31
+ return f"{self._prefix}: {self._namespace}"
32
+
33
+ def __repr__(self):
34
+ return f"Namespace(prefix={self._prefix}, namespace={self._namespace})"
35
+
36
+ def __contains__(self, item: str) -> bool:
37
+ return item in self._namespace
38
+
39
+ def term(self, name: str) -> IRI:
40
+ return IRI(self._namespace.term(name))
41
+
42
+ def __getitem__(self, item: str) -> IRI:
43
+ return self.term(item)
44
+
45
+ def __getattr__(self, item: str) -> IRI:
46
+ if item.startswith("__"):
47
+ raise AttributeError
48
+ return self.term(item)
49
+
50
+ @property
51
+ def namespace(self) -> IRI:
52
+ return IRI(self._namespace)
53
+
54
+ @property
55
+ def prefix(self) -> str:
56
+ return self._prefix