Skip to content

Repository ORM

Actions Status Actions Status Coverage Status

Library to persist Pydantic models into different storage backends following the repository pattern.


pip install repository-orm

A Simple Example

from repository_orm import Entity, load_repository

class Author(Entity):
    first_name: str
    last_name: str
    country: str

repo = load_repository()

author = Author(first_name="Brandon", last_name="Sanderson", country="US")

# Add entities

# Retrieve entities by their ID
brandon = repo.get(0, Author)
assert brandon == author

# Search entities
brandon ={"first_name": "Brandon"}, Author)[0]
assert brandon == author

# Delete entities
assert len(repo.all(Author)) == 0

# Close the connection

Repository pattern theory

The repository pattern is an abstraction over persistent storage, allowing you to decouple the model layer from the data layer. It hides the boring details of data access by pretending that all of our data is in memory.

It has the following advantages:

  • Give a simple interface, which you control, between persistent storage and our domain model.
  • It's easy to make a fake version of the repository for unit testing, or to swap out different storage solutions, because the model is fully decoupled from the infrastructure.
  • Writing the domain model before thinking about persistence helps focus on the problem at hand. If we need to change our approach, we can do that in our model, without needing to worry about foreign keys or migrations until later.
  • Our database schema is simple because we have complete control over how we map our object to tables.
  • Speeds up and makes more clean the business logic tests.
  • It's easy to implement.

But the following disadvantages:

  • An ORM already buys you some decoupling. Changing foreign keys might be hard, but it should be pretty easy to swap between MySQL and PostgreSQL if you ever need to.
  • Maintaining ORM mappings by hand requires extra work and extra code.
  • An extra layer of abstraction is introduced, and although we may hope it will reduce complexity overall, it does add complexity locally. Furthermore it adds the WTF factor for Python programmers who've never seen this pattern before.

repository-orm aims to mitigate the last ones by:

  • Supplying classes that already have the common operations for different storage solutions.
  • Supplying test classes and fixtures so extending the provided repositories is easy.


There are two kinds of repositories:

Projects using repository-orm

If you want to see the library being used in a simple project, check pynbox code. Other projects using repository-orm are:

  • clinv: A DevSecOps command line asset inventory tool.
  • pydo: A free software command line task manager built in Python.

If you use the library and want to be listed here, open an issue.


As most open sourced programs, repository-orm is standing on the shoulders of giants, namely:

Used for the Entities definition.
Used to search strings in complex objects in the FakeRepository.
Used to interact with the NoSQL database in the TinyDBRepository
Used to build the SQL queries in the PypikaRepository.
Used to manage the schema changes of the PypikaRepository.
Testing framework, enhanced by the awesome pytest-cases library that made the parametrization of the tests a lovely experience.
Python static type checker.
Python linter with lots of checks.
Python formatter to keep a nice style without effort.
Python formatter to automatically fix wrong import statements.
Python formatter to order the import statements.
Command line tool to manage the dependencies.
To build this documentation site, with the Material theme.
To check the installed dependencies for known security vulnerabilities.
To finds common security issues in Python code.
YAML fixer.


For guidance on setting up a development environment, and how to make a contribution to repository-orm, see Contributing to repository-orm.

Last update: 2022-08-12