Skip to main content

rdfmapper

rdfmapper is a declarative Object-RDF Mapper for Python. It lets you map Python classes to RDF graphs using decorators, inspired by ORM frameworks such as JPA and SQLAlchemy, without requiring you to write SPARQL or manipulate triples manually.

Tests PyPI License: MIT Python


Features

  • Declarative mapping of Python classes to RDF types and predicates via decorators
  • Support for one-to-one and one-to-many relationships
  • Automatic serialization and deserialization between Python objects and RDF graphs
  • Dynamic query repository (find_by_*, count_by_*, group_by_count) powered by SPARQL
  • Automatic SHACL shape generation and validation from class metadata
  • Circular reference detection during serialization and deserialization
  • Type-aware literal conversion (int, float, bool, date, datetime)

Installation

pip install rdfmapper-py

Or install from source:

git clone https://github.com/lambdageo/rdfmapper.git
cd rdfmapper
pip install -e ".[dev]"

Quick start

from rdflib import Namespace
from rdfmapper import RDFMapper, RDFRepository

EX = Namespace("http://example.org/")
FOAF = Namespace("http://xmlns.com/foaf/0.1/")

mapper = RDFMapper()


@mapper.rdf_entity(EX.Person)
class Person:
    def __init__(self, uri, name: str, age: int = None):
        self.uri = uri
        self._name = name
        self._age = age

    @mapper.rdf_property(FOAF.name, minCount=1)
    def name(self): pass

    @mapper.rdf_property(FOAF.age)
    def age(self): pass


# Serialize to RDF
person = Person(uri=EX["person/1"], name="Felipe", age=25)
graph = mapper.to_rdf(person)
print(graph.serialize(format="turtle"))

# Deserialize back to Python
restored = mapper.from_rdf(graph, Person, str(EX["person/1"]))
print(restored.name)  # Felipe

# Query with repository
repo = RDFRepository(mapper, graph, Person)
results = repo.find_by_name(name="Felipe")
count = repo.count_by_name(name="Felipe")

Relationships

@mapper.rdf_entity(EX.Address)
class Address:
    def __init__(self, uri, city: str):
        self.uri = uri
        self._city = city

    @mapper.rdf_property(EX.city)
    def city(self): pass


@mapper.rdf_entity(EX.Person)
class Person:
    def __init__(self, uri, name: str, address=None, phones=None):
        self.uri = uri
        self._name = name
        self._address = address
        self._phones = phones or []

    @mapper.rdf_property(FOAF.name)
    def name(self): pass

    @mapper.rdf_one_to_one(EX.address, target_class=lambda: Address)
    def address(self): pass

    @mapper.rdf_one_to_many(EX.phone, target_class=lambda: Phone)
    def phones(self): pass

SHACL validation

# Auto-generate SHACL shape from class metadata
shacl_graph = mapper.to_shacl(Person)

# Validate an RDF graph
conforms, _, report = mapper.validate(graph, entity_class=Person)
print("Conforms:", conforms)
print(report)

Dynamic repository queries

repo = RDFRepository(mapper, graph, Person)

# Exact match
repo.find_by_name(name="Felipe")

# Regex match
repo.find_by_name_like(name="Fel")

# Compound filter
repo.find_by_name_and_age(name="Felipe", age=25)

# Pagination
repo.find_by_name(name="Felipe", limit=10, offset=0)

# Count
repo.count_by_name(name="Felipe")

# Aggregation
repo.group_by_count(Person, "name", order="DESC")

Examples

See the examples/ directory for complete runnable scripts:


Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Type checking
mypy src/

Citation

If you use rdfmapper in your research, please cite:

@software{goiabeira2025pyrdm,
  author    = {Goiabeira, Felipe dos Santos and Costa, Sergio Souza},
  title     = {rdfmapper: A Declarative Object-RDF Mapper for Python},
  year      = {2025},
  publisher = {GitHub},
  url       = {https://github.com/lambdageo/rdfmapper}
}

License

MIT — see LICENSE.


Acknowledgements

rdfmapper was originally developed as part of a Bachelor's thesis at the Federal University of Maranhão (UFMA) by Felipe dos Santos Goiabeira, advised by Prof. Dr. Sergio Souza Costa, LambdaGeo Research Group.

Release files for rdfmapper 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rdfmapper 0.2.1
File Size Uploaded
rdfmapper-0.2.1.tar.gz 13.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rdfmapper 0.2.1
File Interpreter ABI Platform
rdfmapper-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 22.8 kB

Release files / rdfmapper-0.2.1.tar.gz

Download URL rdfmapper-0.2.1.tar.gz
Size 13.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e4f1534943c9f297a8c8bfbd1fb7182db6ba69ce71c666dc18a1815620d5b239
BLAKE2b-256 checksum
How to use checksums
f5df698e9a2f5a719cab85c7ab9823b9b07204fbb42d1b35d87abe93768aafc7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / rdfmapper-0.2.1-py3-none-any.whl

Download URL rdfmapper-0.2.1-py3-none-any.whl
Size 9.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
63aa01516bfa912e1c23e80fd74d7ed12cf3e28c4fa8b7fcd2c9e4f0730503cc
BLAKE2b-256 checksum
How to use checksums
f94f75d3fa578e7f461505253e6d0f6d6d44eb85497a1310b7d7a087aad9bf37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.2.2

2 release files

This release

0.2.1 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page