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 +3 -3
- rdf4j_python/_driver/__init__.py +4 -4
- rdf4j_python/_driver/_async_rdf4j_db.py +10 -8
- rdf4j_python/_driver/_async_repository.py +66 -8
- rdf4j_python/exception/repo_exception.py +9 -0
- rdf4j_python/model/__init__.py +16 -0
- rdf4j_python/model/_namespace.py +56 -0
- rdf4j_python/model/_repository_config.py +899 -0
- rdf4j_python/model/{repository.py → _repository_info.py} +3 -3
- rdf4j_python-0.1.1a0.dist-info/METADATA +77 -0
- rdf4j_python-0.1.1a0.dist-info/RECORD +19 -0
- {rdf4j_python-0.1.0.dist-info → rdf4j_python-0.1.1a0.dist-info}/WHEEL +1 -1
- rdf4j_python-0.1.1a0.dist-info/licenses/LICENSE +28 -0
- rdf4j_python-0.1.0.dist-info/METADATA +0 -8
- rdf4j_python-0.1.0.dist-info/RECORD +0 -15
- {rdf4j_python-0.1.0.dist-info → rdf4j_python-0.1.1a0.dist-info}/top_level.txt +0 -0
rdf4j_python/__init__.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from ._client import AsyncApiClient, SyncApiClient
|
|
2
|
-
from ._driver import
|
|
2
|
+
from ._driver import AsyncRdf4j, AsyncRdf4JRepository
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
5
|
"AsyncApiClient",
|
|
6
6
|
"SyncApiClient",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"AsyncRdf4j",
|
|
8
|
+
"AsyncRdf4JRepository",
|
|
9
9
|
]
|
rdf4j_python/_driver/__init__.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from ._async_rdf4j_db import
|
|
2
|
-
from ._async_repository import
|
|
1
|
+
from ._async_rdf4j_db import AsyncRdf4j
|
|
2
|
+
from ._async_repository import AsyncRdf4JRepository
|
|
3
3
|
|
|
4
4
|
__all__ = [
|
|
5
|
-
"
|
|
6
|
-
"
|
|
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.
|
|
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
|
|
14
|
+
from ._async_repository import AsyncRdf4JRepository
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class
|
|
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[
|
|
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
|
-
|
|
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) ->
|
|
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
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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,
|
|
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
|