{"id":28916940,"url":"https://github.com/odysa/rdf4j-python","last_synced_at":"2026-03-03T21:04:43.030Z","repository":{"id":292272320,"uuid":"973723715","full_name":"odysa/rdf4j-python","owner":"odysa","description":"Python client for Eclipse RDF4J — interact with RDF4J repositories, execute SPARQL queries, and manage RDF data seamlessly in Python.","archived":false,"fork":false,"pushed_at":"2026-02-28T17:50:12.000Z","size":231,"stargazers_count":4,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-28T20:09:33.597Z","etag":null,"topics":["database","rag","rdf","sementic","sparql"],"latest_commit_sha":null,"homepage":"https://rdf4j-python.readthedocs.io/en/stable/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/odysa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-27T15:52:22.000Z","updated_at":"2026-02-28T17:50:14.000Z","dependencies_parsed_at":"2025-05-30T02:28:13.784Z","dependency_job_id":"b7e7dde7-c408-4015-a8d0-7db224fb6005","html_url":"https://github.com/odysa/rdf4j-python","commit_stats":null,"previous_names":["odysa/rdf4j-python"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/odysa/rdf4j-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/odysa%2Frdf4j-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/odysa%2Frdf4j-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/odysa%2Frdf4j-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/odysa%2Frdf4j-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/odysa","download_url":"https://codeload.github.com/odysa/rdf4j-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/odysa%2Frdf4j-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30060749,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T18:21:05.932Z","status":"ssl_error","status_checked_at":"2026-03-03T18:20:59.341Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","rag","rdf","sementic","sparql"],"created_at":"2025-06-22T00:09:31.653Z","updated_at":"2026-03-03T21:04:43.025Z","avatar_url":"https://github.com/odysa.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rdf4j-python\n\n[![PyPI version](https://badge.fury.io/py/rdf4j-python.svg)](https://badge.fury.io/py/rdf4j-python)\n[![Python Versions](https://img.shields.io/pypi/pyversions/rdf4j-python.svg)](https://pypi.org/project/rdf4j-python/)\n[![CI](https://github.com/odysa/rdf4j-python/actions/workflows/ci.yaml/badge.svg)](https://github.com/odysa/rdf4j-python/actions/workflows/ci.yaml)\n[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\n[![Documentation](https://img.shields.io/badge/docs-sphinx-blue.svg)](https://github.com/odysa/rdf4j-python/tree/main/docs)\n\n**A modern Python client for the Eclipse RDF4J framework, enabling seamless RDF data management and SPARQL operations from Python applications.**\n\nrdf4j-python bridges the gap between Python and the robust [Eclipse RDF4J](https://rdf4j.org/) ecosystem, providing a clean, async-first API for managing RDF repositories, executing SPARQL queries, and handling semantic data with ease.\n\n## Features\n\n- **Async-First Design**: Native support for async/await with synchronous fallback\n- **Repository Management**: Create, access, and manage RDF4J repositories programmatically\n- **SPARQL Support**: Execute SELECT, ASK, CONSTRUCT, and UPDATE queries effortlessly\n- **SPARQL Query Builder**: Fluent, programmatic query construction with method chaining\n- **Transaction Support**: Atomic operations with commit/rollback and isolation levels\n- **Flexible Data Handling**: Add, retrieve, and manipulate RDF triples and quads\n- **File Upload**: Upload RDF files (Turtle, N-Triples, N-Quads, RDF/XML, JSON-LD, TriG, N3) directly to repositories\n- **Multiple Formats**: Support for various RDF serialization formats\n- **Repository Types**: Memory stores, native stores, HTTP repositories, and more\n- **Named Graph Support**: Work with multiple graphs within repositories\n- **Inferencing**: Built-in support for RDFS and custom inferencing rules\n\n## Installation\n\n### Prerequisites\n\n- Python 3.11 or higher\n- RDF4J Server (for remote repositories) or embedded usage\n\n### Install from PyPI\n\n```bash\npip install rdf4j-python\n```\n\n### Install with Optional Dependencies\n\n```bash\n# Include SPARQLWrapper integration\npip install rdf4j-python[sparqlwrapper]\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/odysa/rdf4j-python.git\ncd rdf4j-python\nuv sync --group dev\n```\n\n## Usage\n\n### Quick Start\n\n```python\nimport asyncio\nfrom rdf4j_python import AsyncRdf4j\nfrom rdf4j_python.model.repository_config import RepositoryConfig, MemoryStoreConfig, SailRepositoryConfig\nfrom rdf4j_python.model.term import IRI, Literal\n\nasync def main():\n    # Connect to RDF4J server\n    async with AsyncRdf4j(\"http://localhost:19780/rdf4j-server\") as db:\n        # Create an in-memory repository\n        config = RepositoryConfig(\n            repo_id=\"my-repo\",\n            title=\"My Repository\",\n            impl=SailRepositoryConfig(sail_impl=MemoryStoreConfig(persist=False))\n        )\n        repo = await db.create_repository(config=config)\n        \n        # Add some data\n        await repo.add_statement(\n            IRI(\"http://example.com/person/alice\"),\n            IRI(\"http://xmlns.com/foaf/0.1/name\"),\n            Literal(\"Alice\")\n        )\n        \n        # Query the data\n        results = await repo.query(\"SELECT * WHERE { ?s ?p ?o }\")\n        for result in results:\n            print(f\"Subject: {result['s']}, Predicate: {result['p']}, Object: {result['o']}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n### SPARQL Query Builder\n\nBuild queries programmatically with method chaining instead of writing raw SPARQL strings:\n\n```python\nfrom rdf4j_python import select, ask, construct, describe, GraphPattern, Namespace\n\nex = Namespace(\"ex\", \"http://example.org/\")\nfoaf = Namespace(\"foaf\", \"http://xmlns.com/foaf/0.1/\")\n\n# SELECT with typed terms — IRIs serialize automatically\nquery = (\n    select(\"?person\", \"?name\")\n    .where(\"?person\", foaf.type, ex.Person)\n    .where(\"?person\", foaf.name, \"?name\")\n    .optional(\"?person\", foaf.email, \"?email\")\n    .filter(\"?name != 'Bob'\")\n    .order_by(\"?name\")\n    .limit(10)\n    .build()\n)\n\n# Or use string-based prefixed names\nquery = (\n    select(\"?name\")\n    .prefix(\"foaf\", \"http://xmlns.com/foaf/0.1/\")\n    .where(\"?person\", \"a\", \"foaf:Person\")\n    .where(\"?person\", \"foaf:name\", \"?name\")\n    .build()\n)\n\n# GROUP BY with aggregation\nquery = (\n    select(\"?city\", \"(COUNT(?person) AS ?count)\")\n    .where(\"?person\", ex.city, \"?city\")\n    .group_by(\"?city\")\n    .having(\"COUNT(?person) \u003e 1\")\n    .order_by(\"DESC(?count)\")\n    .build()\n)\n\n# ASK, CONSTRUCT, and DESCRIBE\nask_query = ask().where(\"?s\", ex.name, \"?name\").build()\n\nconstruct_query = (\n    construct((\"?s\", ex.fullName, \"?name\"))\n    .where(\"?s\", ex.firstName, \"?fname\")\n    .bind(\"CONCAT(?fname, ' ', ?lname)\", \"?name\")\n    .build()\n)\n\ndescribe_query = describe(ex.alice).build()\n```\n\nThe query builder supports FILTER, OPTIONAL, UNION, BIND, VALUES, sub-queries, DISTINCT, ORDER BY, GROUP BY, HAVING, LIMIT, and OFFSET. Both raw strings and typed objects (`IRI`, `Variable`, `Literal`, `Namespace`) work as terms.\n\n### Working with Multiple Graphs\n\n```python\nfrom rdf4j_python.model.term import Quad\n\nasync def multi_graph_example():\n    async with AsyncRdf4j(\"http://localhost:19780/rdf4j-server\") as db:\n        repo = await db.get_repository(\"my-repo\")\n        \n        # Add data to specific graphs\n        statements = [\n            Quad(\n                IRI(\"http://example.com/person/bob\"),\n                IRI(\"http://xmlns.com/foaf/0.1/name\"),\n                Literal(\"Bob\"),\n                IRI(\"http://example.com/graph/people\")\n            ),\n            Quad(\n                IRI(\"http://example.com/person/bob\"),\n                IRI(\"http://xmlns.com/foaf/0.1/age\"),\n                Literal(\"30\", datatype=IRI(\"http://www.w3.org/2001/XMLSchema#integer\")),\n                IRI(\"http://example.com/graph/demographics\")\n            )\n        ]\n        await repo.add_statements(statements)\n        \n        # Query specific graph\n        graph_query = \"\"\"\n        SELECT * WHERE {\n            GRAPH \u003chttp://example.com/graph/people\u003e {\n                ?person ?property ?value\n            }\n        }\n        \"\"\"\n        results = await repo.query(graph_query)\n```\n\n### Advanced Repository Configuration\n\nHere's a more comprehensive example showing repository creation with different configurations:\n\n```python\nasync def advanced_example():\n    async with AsyncRdf4j(\"http://localhost:19780/rdf4j-server\") as db:\n        # Memory store with persistence\n        persistent_config = RepositoryConfig(\n            repo_id=\"persistent-repo\",\n            title=\"Persistent Memory Store\",\n            impl=SailRepositoryConfig(sail_impl=MemoryStoreConfig(persist=True))\n        )\n        \n        # Create and populate repository\n        repo = await db.create_repository(config=persistent_config)\n        \n        # Bulk data operations\n        data = [\n            (IRI(\"http://example.com/alice\"), IRI(\"http://xmlns.com/foaf/0.1/name\"), Literal(\"Alice\")),\n            (IRI(\"http://example.com/alice\"), IRI(\"http://xmlns.com/foaf/0.1/email\"), Literal(\"alice@example.com\")),\n            (IRI(\"http://example.com/bob\"), IRI(\"http://xmlns.com/foaf/0.1/name\"), Literal(\"Bob\")),\n        ]\n        \n        statements = [\n            Quad(subj, pred, obj, IRI(\"http://example.com/default\"))\n            for subj, pred, obj in data\n        ]\n        await repo.add_statements(statements)\n        \n        # Query with the fluent query builder\n        from rdf4j_python import select\n        from rdf4j_python.model._namespace import Namespace\n\n        foaf = Namespace(\"foaf\", \"http://xmlns.com/foaf/0.1/\")\n        query = (\n            select(\"?name\", \"?email\")\n            .where(\"?person\", foaf.name, \"?name\")\n            .optional(\"?person\", foaf.email, \"?email\")\n            .order_by(\"?name\")\n            .build()\n        )\n        results = await repo.query(query)\n```\n\n### Uploading RDF Files\n\n```python\nimport pyoxigraph as og\n\nasync def upload_example():\n    async with AsyncRdf4j(\"http://localhost:19780/rdf4j-server\") as db:\n        repo = await db.get_repository(\"my-repo\")\n\n        # Upload a Turtle file (format auto-detected from extension)\n        await repo.upload_file(\"data.ttl\")\n\n        # Upload to a specific named graph\n        await repo.upload_file(\"data.ttl\", context=IRI(\"http://example.com/graph\"))\n\n        # Upload with explicit format\n        await repo.upload_file(\"data.txt\", rdf_format=og.RdfFormat.N_TRIPLES)\n\n        # Upload with base URI for relative URIs\n        await repo.upload_file(\"data.ttl\", base_uri=\"http://example.com/\")\n```\n\n### Using Transactions\n\n```python\nfrom rdf4j_python import IsolationLevel\n\nasync def transaction_example():\n    async with AsyncRdf4j(\"http://localhost:19780/rdf4j-server\") as db:\n        repo = await db.get_repository(\"my-repo\")\n\n        # Atomic operations with auto-commit/rollback\n        async with repo.transaction() as txn:\n            await txn.add_statements([\n                Quad(IRI(\"http://example.com/alice\"), IRI(\"http://xmlns.com/foaf/0.1/name\"), Literal(\"Alice\")),\n                Quad(IRI(\"http://example.com/bob\"), IRI(\"http://xmlns.com/foaf/0.1/name\"), Literal(\"Bob\")),\n            ])\n            await txn.delete_statements([old_quad])\n            # Commits automatically on success, rolls back on exception\n\n        # With specific isolation level\n        async with repo.transaction(IsolationLevel.SERIALIZABLE) as txn:\n            await txn.update(\"\"\"\n                DELETE { ?s \u003chttp://example.com/status\u003e \"draft\" }\n                INSERT { ?s \u003chttp://example.com/status\u003e \"published\" }\n                WHERE { ?s \u003chttp://example.com/status\u003e \"draft\" }\n            \"\"\")\n```\n\nFor more detailed examples, see the [examples](examples/) directory.\n\n## Development\n\n### Setting up Development Environment\n\n1. **Clone the repository**:\n   ```bash\n   git clone https://github.com/odysa/rdf4j-python.git\n   cd rdf4j-python\n   ```\n\n2. **Install development dependencies**:\n   ```bash\n   uv sync --group dev\n   ```\n\n3. **Start RDF4J Server** (for integration tests):\n   ```bash\n   # Using Docker\n   docker run -p 19780:8080 eclipse/rdf4j:latest\n   ```\n\n4. **Run tests**:\n   ```bash\n   pytest tests/\n   ```\n\n5. **Run linting**:\n   ```bash\n   ruff check .\n   ruff format .\n   ```\n\n### Project Structure\n\n```\nrdf4j_python/\n├── _driver/          # Core async driver implementation\n├── model/            # Data models and configurations\n├── query/            # SPARQL query builder\n├── exception/        # Custom exceptions\n└── utils/           # Utility functions\n\nexamples/            # Usage examples\ntests/              # Test suite\ndocs/               # Documentation\n```\n\n## Contributing\n\nWe welcome contributions! Here's how to get involved:\n\n1. Fork the repository on GitHub\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes and add tests\n4. Run the test suite to ensure everything works\n5. Commit your changes (`git commit -m 'Add amazing feature'`)\n6. Push to your branch (`git push origin feature/amazing-feature`)\n7. Open a Pull Request\n\n### Running Examples\n\n```bash\n# Make sure RDF4J server is running on localhost:19780\npython examples/complete_workflow.py\npython examples/query.py\n```\n\n## License\n\nThis project is licensed under the BSD 3-Clause License. See the [LICENSE](LICENSE) file for details.\n\nCopyright (c) 2025, Chengxu Bian\n\n## Support\n\n- **Issues \u0026 Bug Reports**: [GitHub Issues](https://github.com/odysa/rdf4j-python/issues)\n- **Documentation**: [docs/](https://github.com/odysa/rdf4j-python/tree/main/docs)\n- **Questions**: Feel free to open a discussion or issue\n\nIf you find this project useful, please consider starring the repository!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fodysa%2Frdf4j-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fodysa%2Frdf4j-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fodysa%2Frdf4j-python/lists"}