Installation¶
The version is pinned because it is a beta
pip install snake-orm on its own installs NOTHING: pip does not pick up a preliminary
version unless it is asked for by name or with --pre. That is the point of publishing a
beta — nobody upgrades into it by accident while the API is still moving.
pip install snakeorm does not work either, and the two names are not a typo.
pyproject.toml declares name = "snake-orm" — the distribution name, the one you
install — while the package you import is snakeorm, the import name. The whole story is
in the release process.
From a checkout of the repository, to work on the ORM itself:
Needs Python 3.11+: deep typing uses dataclass_transform (PEP 681) and the X | None syntax
in annotations.
Your engine's driver¶
Three engines, all three first class: PostgreSQL, MySQL/MariaDB and SQLite. You pair a dialect with a driver; only MySQL needs an extra install:
from snakeorm import MySQLDialect, PyMySQLDriver
driver = PyMySQLDriver.connect(
host="localhost", user="user", password="pass", database="mydb"
)
dialect = MySQLDialect()
MySQL takes connection arguments, not a one-piece DSN. That's the engine's shape, and the driver doesn't invent a DSN parser to hide it.
PyMySQL is pure Python, so it installs anywhere without a C toolchain. mysqlclient is faster
and works just as well: it speaks the same %s placeholders, so the dialect does not change.
The same, asynchronously¶
Generating SQL has no color — it doesn't execute — so the dialect doesn't change. Only the driver
does, and the session you pair it with (AsyncSession instead of SnakeSession):
There is no extra just for asynchronous MySQL
Two extras buy a driver: async (psycopg 3) and mysql (PyMySQL). Only PostgreSQL has a native asynchronous driver, and that is what async buys.
MySQL and SQLite serve their synchronous driver from a thread of their own, so they need nothing
beyond what you already installed.
Why the driver is your job
They are two distinct axes: the dialect decides how the SQL is WRITTEN (placeholders,
quoting, LIMIT); the driver decides how it is EXECUTED. Making them parameters and not a
magic factory is what lets you wrap the driver with a logger or a pool without the rest noticing.
See dialects.
Configuration¶
Connections are read from environment variables or a .env:
SNAKEORM_DSN and the classic DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASSWORD also
work. For several databases at once, see multiple databases.
Check that it works¶
from snakeorm import PostgresDialect, PsycopgDriver, SnakeSession, SnakeRow, snake_row
@snake_row
class Version(SnakeRow):
value: str
dsn = "postgresql://user:pass@localhost/mydb"
session = SnakeSession(PsycopgDriver.connect(dsn), PostgresDialect())
print(session.raw("SELECT version() AS value", into=Version)[0].value)
The tools this project takes for granted¶
Everything that sets this ORM apart lives in the type-checker. Both live in the dev group, so
the sync above already brought them:
Without them, the deep typing that sets this ORM apart is invisible.
Next: your first model.