Generic БД/ORM-инфраструктура на SQLAlchemy 2.0: диалект-нейтральный движок из DB-URL, Repository + UnitOfWork + DIP-протоколы. 0 завязок на конкретное приложение.
Project description
s-ormkit
Generic БД/ORM-инфраструктура для экосистемы S-kits на SQLAlchemy 2.0: диалект-нейтральный движок из DB-URL, Repository + UnitOfWork + DIP-протоколы.
Версия: 0.0.1 (первый релиз)
Лицензия: MIT
Зависимости: SQLAlchemy>=2.0 (и ничего больше)
Кит НЕ знает ни о каком приложении. Прикладная логика получает БД-слой через ORM так,
что не зависит от sqlite/диалекта: движок конфигурируется через DB-URL и заменяется на
postgresql://.../mysql://... без изменения кода.
Что входит
Declarative-база и миксины (base.py)
Base— общий declarative base для моделей-наследниковIntPkMixin— целочисленный автоинкрементный первичный ключTimestampMixin—created_at/updated_atчерезfunc.now()(диалект-нейтрально)
Движок из DB-URL (engine.py)
make_engine— резолв URL (аргумент → env → default), для sqlite включаетPRAGMA foreign_keys=ON;create_engineленив (postgres-URL создаётся без коннекта)make_session_factory—sessionmaker(expire_on_commit=False)init_schema/drop_schema— создать/удалить таблицыdispose_engine— освободить пул соединений
Repository-паттерн (repository.py)
BaseRepository[TModel, TDomain]— generic CRUD:add / get / get_or_none / list / update / remove / count- Маппинг ORM <-> domain через переопределяемые хуки
to_domain/to_orm - Не коммитит сам (это делает
UnitOfWork) — толькоflushдля получения id
Транзакционная граница (unit_of_work.py)
UnitOfWork— контекст-менеджер: rollback при исключении,closeвсегда,commitявный
DIP-контракты (protocols.py)
RepositoryProtocol/UnitOfWorkProtocol— чтобы сервисы зависели от абстракций, а не отBaseRepository/ SQLAlchemy
Быстрый старт
Кит generic — вы объявляете свои модели поверх Base и миксинов:
from dataclasses import dataclass
from sqlalchemy import String
from sqlalchemy.orm import Mapped, mapped_column
from ormkit import (
Base, IntPkMixin, TimestampMixin,
BaseRepository, UnitOfWork,
make_engine, make_session_factory, init_schema,
)
# 1. Свои ORM-модели
class User(Base, IntPkMixin, TimestampMixin):
__tablename__ = "users"
name: Mapped[str] = mapped_column(String(100))
# 2. Свой доменный объект (dataclass / pydantic / dict — кит не знает тип)
@dataclass
class UserDTO:
name: str
id: int | None = None
# 3. Свой репозиторий — переопределяем ТОЛЬКО хуки маппинга
class UserRepository(BaseRepository[User, UserDTO]):
def to_domain(self, obj: User) -> UserDTO:
return UserDTO(id=obj.id, name=obj.name)
def to_orm(self, domain: UserDTO) -> User:
return User(name=domain.name)
Конфигурация движка через DB-URL
# sqlite по умолчанию (для локали / тестов), FK enforcement включён автоматически
engine = make_engine("sqlite:///app.db")
# та же строка кода на проде — просто другой URL, коду всё равно:
engine = make_engine(default="postgresql://user:pass@host/db")
# или через переменную окружения ORMKIT_DB_URL:
engine = make_engine()
init_schema(engine)
session_factory = make_session_factory(engine)
Работа через UnitOfWork
with UnitOfWork(session_factory) as uow:
repo = UserRepository(uow.session, User)
saved = repo.add(UserDTO(name="Алиса")) # flush -> id проставлен
found = repo.get(saved.id) # NotFoundError, если нет
everyone = repo.list() # фильтр: repo.list(name="Алиса")
repo.update(saved.id, name="Алиса Смит")
total = repo.count()
uow.commit() # без commit транзакция не персистится
# исключение в блоке -> автоматический rollback; сессия всегда закрывается
DIP: сервис зависит от абстракции
from ormkit import RepositoryProtocol
def register_user(repo: RepositoryProtocol[UserDTO], name: str) -> UserDTO:
return repo.add(UserDTO(name=name))
# в проде — UserRepository, в тестах — in-memory фейк, реализующий тот же протокол
Архитектура
ormkit/
├── __init__.py # Public API + __version__
├── exceptions.py # OrmKitError, NotFoundError
├── base.py # Base, IntPkMixin, TimestampMixin
├── engine.py # make_engine, make_session_factory, init/drop_schema, dispose
├── repository.py # BaseRepository[TModel, TDomain]
├── unit_of_work.py # UnitOfWork
└── protocols.py # RepositoryProtocol, UnitOfWorkProtocol
Тестирование
uv sync --extra dev
uv run pytest -q # зелёный, coverage >= 80%
uv run ruff check . # чисто
Тесты объявляют собственные демо-модели (_User, _Post) прямо в conftest.py —
это доказывает, что кит generic и не тянет никакого приложения.
Диалект-нейтральность
- Один код — любая СУБД. Меняется только DB-URL:
sqlite://↔postgresql://↔mysql://. Прикладной код не трогается. - sqlite FK enforcement. Для sqlite
make_engineнавешиваетPRAGMA foreign_keys=ON(иначе sqlite молча игнорирует внешние ключи). Отключается флагомforeign_keys=False. - Временные метки.
TimestampMixinиспользуетfunc.now(), работающий и в sqlite, и в postgres/mysql. - Ленивое создание.
make_engine("postgresql://...")не коннектится — движок создаётся без живого сервера.
Лицензия
MIT
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 s_ormkit-0.0.1.tar.gz.
File metadata
- Download URL: s_ormkit-0.0.1.tar.gz
- Upload date:
- Size: 45.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f0d56b8afc4a985718c2797736b6b023e068a6931f7868264145ef62842a148
|
|
| MD5 |
ed4c9846fecbe591a2c5144e1ba87064
|
|
| BLAKE2b-256 |
6c252dec2d169119e46689dc536f0db740abc32cc1fa39c3eda55ace288489d6
|
File details
Details for the file s_ormkit-0.0.1-py3-none-any.whl.
File metadata
- Download URL: s_ormkit-0.0.1-py3-none-any.whl
- Upload date:
- Size: 12.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a350e84328bf5e7b930785e296b343de99815f94d8583d296bb8346234345ecb
|
|
| MD5 |
decf207fae1874a8d60595bf97f41d69
|
|
| BLAKE2b-256 |
5fa3de17d5647a04dc7d36b6d6818da95e7a8e75d8518b03acc8ca400a294d70
|