The Python client for RDF4J
Project description
rdf4j-python
A modern Python client for the Eclipse RDF4J framework, enabling seamless RDF data management and SPARQL operations from Python applications.
rdf4j-python bridges the gap between Python and the robust Eclipse RDF4J ecosystem, providing a clean, async-first API for managing RDF repositories, executing SPARQL queries, and handling semantic data with ease.
Features
- Async-First Design: Native support for async/await with synchronous fallback
- Repository Management: Create, access, and manage RDF4J repositories programmatically
- SPARQL Support: Execute SELECT, ASK, CONSTRUCT, and UPDATE queries effortlessly
- Transaction Support: Atomic operations with commit/rollback and isolation levels
- Flexible Data Handling: Add, retrieve, and manipulate RDF triples and quads
- File Upload: Upload RDF files (Turtle, N-Triples, N-Quads, RDF/XML, JSON-LD, TriG, N3) directly to repositories
- Multiple Formats: Support for various RDF serialization formats
- Repository Types: Memory stores, native stores, HTTP repositories, and more
- Named Graph Support: Work with multiple graphs within repositories
- Inferencing: Built-in support for RDFS and custom inferencing rules
Installation
Prerequisites
- Python 3.11 or higher
- RDF4J Server (for remote repositories) or embedded usage
Install from PyPI
pip install rdf4j-python
Install with Optional Dependencies
# Include SPARQLWrapper integration
pip install rdf4j-python[sparqlwrapper]
Development Installation
git clone https://github.com/odysa/rdf4j-python.git
cd rdf4j-python
uv sync --group dev
Usage
Quick Start
import asyncio
from rdf4j_python import AsyncRdf4j
from rdf4j_python.model.repository_config import RepositoryConfig, MemoryStoreConfig, SailRepositoryConfig
from rdf4j_python.model.term import IRI, Literal
async def main():
# Connect to RDF4J server
async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
# Create an in-memory repository
config = RepositoryConfig(
repo_id="my-repo",
title="My Repository",
impl=SailRepositoryConfig(sail_impl=MemoryStoreConfig(persist=False))
)
repo = await db.create_repository(config=config)
# Add some data
await repo.add_statement(
IRI("http://example.com/person/alice"),
IRI("http://xmlns.com/foaf/0.1/name"),
Literal("Alice")
)
# Query the data
results = await repo.query("SELECT * WHERE { ?s ?p ?o }")
for result in results:
print(f"Subject: {result['s']}, Predicate: {result['p']}, Object: {result['o']}")
if __name__ == "__main__":
asyncio.run(main())
Working with Multiple Graphs
from rdf4j_python.model.term import Quad
async def multi_graph_example():
async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
repo = await db.get_repository("my-repo")
# Add data to specific graphs
statements = [
Quad(
IRI("http://example.com/person/bob"),
IRI("http://xmlns.com/foaf/0.1/name"),
Literal("Bob"),
IRI("http://example.com/graph/people")
),
Quad(
IRI("http://example.com/person/bob"),
IRI("http://xmlns.com/foaf/0.1/age"),
Literal("30", datatype=IRI("http://www.w3.org/2001/XMLSchema#integer")),
IRI("http://example.com/graph/demographics")
)
]
await repo.add_statements(statements)
# Query specific graph
graph_query = """
SELECT * WHERE {
GRAPH <http://example.com/graph/people> {
?person ?property ?value
}
}
"""
results = await repo.query(graph_query)
Advanced Repository Configuration
Here's a more comprehensive example showing repository creation with different configurations:
async def advanced_example():
async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
# Memory store with persistence
persistent_config = RepositoryConfig(
repo_id="persistent-repo",
title="Persistent Memory Store",
impl=SailRepositoryConfig(sail_impl=MemoryStoreConfig(persist=True))
)
# Create and populate repository
repo = await db.create_repository(config=persistent_config)
# Bulk data operations
data = [
(IRI("http://example.com/alice"), IRI("http://xmlns.com/foaf/0.1/name"), Literal("Alice")),
(IRI("http://example.com/alice"), IRI("http://xmlns.com/foaf/0.1/email"), Literal("alice@example.com")),
(IRI("http://example.com/bob"), IRI("http://xmlns.com/foaf/0.1/name"), Literal("Bob")),
]
statements = [
Quad(subj, pred, obj, IRI("http://example.com/default"))
for subj, pred, obj in data
]
await repo.add_statements(statements)
# Complex SPARQL query
query = """
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name ?email WHERE {
?person foaf:name ?name .
OPTIONAL { ?person foaf:email ?email }
}
ORDER BY ?name
"""
results = await repo.query(query)
Uploading RDF Files
import pyoxigraph as og
async def upload_example():
async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
repo = await db.get_repository("my-repo")
# Upload a Turtle file (format auto-detected from extension)
await repo.upload_file("data.ttl")
# Upload to a specific named graph
await repo.upload_file("data.ttl", context=IRI("http://example.com/graph"))
# Upload with explicit format
await repo.upload_file("data.txt", rdf_format=og.RdfFormat.N_TRIPLES)
# Upload with base URI for relative URIs
await repo.upload_file("data.ttl", base_uri="http://example.com/")
Using Transactions
from rdf4j_python import IsolationLevel
async def transaction_example():
async with AsyncRdf4j("http://localhost:19780/rdf4j-server") as db:
repo = await db.get_repository("my-repo")
# Atomic operations with auto-commit/rollback
async with repo.transaction() as txn:
await txn.add_statements([
Quad(IRI("http://example.com/alice"), IRI("http://xmlns.com/foaf/0.1/name"), Literal("Alice")),
Quad(IRI("http://example.com/bob"), IRI("http://xmlns.com/foaf/0.1/name"), Literal("Bob")),
])
await txn.delete_statements([old_quad])
# Commits automatically on success, rolls back on exception
# With specific isolation level
async with repo.transaction(IsolationLevel.SERIALIZABLE) as txn:
await txn.update("""
DELETE { ?s <http://example.com/status> "draft" }
INSERT { ?s <http://example.com/status> "published" }
WHERE { ?s <http://example.com/status> "draft" }
""")
For more detailed examples, see the examples directory.
Development
Setting up Development Environment
-
Clone the repository:
git clone https://github.com/odysa/rdf4j-python.git cd rdf4j-python
-
Install development dependencies:
uv sync --group dev
-
Start RDF4J Server (for integration tests):
# Using Docker docker run -p 19780:8080 eclipse/rdf4j:latest
-
Run tests:
pytest tests/ -
Run linting:
ruff check . ruff format .
Project Structure
rdf4j_python/
├── _driver/ # Core async driver implementation
├── model/ # Data models and configurations
├── exception/ # Custom exceptions
└── utils/ # Utility functions
examples/ # Usage examples
tests/ # Test suite
docs/ # Documentation
Contributing
We welcome contributions! Here's how to get involved:
- Fork the repository on GitHub
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests
- Run the test suite to ensure everything works
- Commit your changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Open a Pull Request
Running Examples
# Make sure RDF4J server is running on localhost:19780
python examples/complete_workflow.py
python examples/query.py
License
This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.
Copyright (c) 2025, Chengxu Bian
Support
- Issues & Bug Reports: GitHub Issues
- Documentation: docs/
- Questions: Feel free to open a discussion or issue
If you find this project useful, please consider starring the repository!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rdf4j_python-0.2.0.tar.gz.
File metadata
- Download URL: rdf4j_python-0.2.0.tar.gz
- Upload date:
- Size: 35.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.29 {"installer":{"name":"uv","version":"0.9.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8684b848e781c0c91cb35ba21b13f285cf56a546eaafd7d0f8d345b2074a144f
|
|
| MD5 |
b93d8b31c887df6fbe55ad841ae8ecc1
|
|
| BLAKE2b-256 |
644153d0ac54672dd66f88ae08e05afcb6e9c120b98a289fab0cae30241760a7
|
File details
Details for the file rdf4j_python-0.2.0-py3-none-any.whl.
File metadata
- Download URL: rdf4j_python-0.2.0-py3-none-any.whl
- Upload date:
- Size: 28.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.29 {"installer":{"name":"uv","version":"0.9.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f55572cf22252aeb9138f00fa640c93e614b6efce635e169277f23ec0660a4c2
|
|
| MD5 |
9c3d1698f96e5c9e867c85a66ec386b4
|
|
| BLAKE2b-256 |
a56f82fe846cf49f2c1d473c9ef48d92b42b0d85b487ab387b95bb1876ecf669
|