ysaqml
Overview
ysaqml provides a YAML-backed persistence layer for SQLAlchemy. Tables live in
memory inside SQLite for fast queries, while their contents are loaded from –
and saved back to – .yaml files using the blazing-fast naay
parser/dumper.
Why?
- Keep relational workflows while still committing plain-text fixtures.
- Edit data in YAML, rely on SQLite for constraints and transactions.
- Round-trip friendly thanks to naay's strict string-only subset.
Installation
pip install -e .
This pulls in SQLAlchemy and naay. Tests rely on pytest (install with
pip install -e .[test]).
Usage
Context-managed workflow
from pathlib import Path
from sqlalchemy import Column, Integer, MetaData, String, Table, select
from ysaqml import YamlSqliteEngine
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String, nullable=False),
)
data_dir = Path("./data")
with YamlSqliteEngine(metadata, data_dir) as backend:
engine = backend.engine
with engine.begin() as conn:
conn.execute(users.insert().values(id=1, name="Ada"))
result = conn.execute(select(users)).mappings().all()
print(result)
# context manager flushes SQLite rows back into data/users.yaml
Each SQLAlchemy table is materialized to <data_dir>/<table_name>.yaml. When
entering the context the engine wipes any existing rows in the in-memory
database, rehydrates them from YAML if the file exists, and on successful
exit dumps the SQLite contents back to YAML.
Custom dialect / engine helper
ysaqml also registers a SQLAlchemy dialect so you can build engines with
ysaqml:/// URLs. The convenience helper wires up the required engine plugin
and disposes the engine when you are done:
from contextlib import closing
from pathlib import Path
from sqlalchemy import Column, Integer, MetaData, String, Table, select
from ysaqml import create_yaml_engine
metadata = MetaData()
users = Table(
"users",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String, nullable=False),
)
data_dir = Path("./data")
with closing(create_yaml_engine(metadata, data_dir)) as engine:
with engine.begin() as conn:
conn.execute(users.insert().values(id=1, name="Ada"))
print(conn.execute(select(users)).mappings().all())
# exiting the context disposes the engine and writes YAML files
Under the hood this builds an in-memory SQLite engine using the ysaqml dialect
and attaches an engine plugin that loads YAML files immediately and saves them
back when the engine is disposed. If you manage the engine manually, make sure
to call engine.dispose() to persist your changes.
File format
Every YAML document uses the following schema:
_naay_version: "1.0"
rows:
- id: "1"
name: "Ada"
_naay_versionis validated but not enforced – it defaults toysaqml.DEFAULT_NAAY_VERSIONand is kept intact when re-saving.rowsis an ordered list of dictionaries where every value is a string.
ysaqml serializes Python None values as the sentinel string __NULL__. When
loading back, that string becomes None again, so avoid storing it as a
literal value.
Testing
pytest
The tests create temporary directories and exercise the full load → mutate → dump loop.
License
Released under the GNU LGPL-3.0-or-later.
Metadata
Release files for ysaqml 2025.12.6.post4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ysaqml-2025.12.6.post4.tar.gz | 31.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ysaqml-2025.12.6.post4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.7 kB
Release files / ysaqml-2025.12.6.post4.tar.gz
| Download URL | ysaqml-2025.12.6.post4.tar.gz |
|---|---|
| Size | 31.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
686f66fd54743eed50eee08752e4b1b698ecc372947d7fea874e710a703ab1d7
|
|
BLAKE2b-256 checksum How to use checksums |
c0b713237d383be66913e9a42d0abdd2e872f3712f11c51f51563912e85de0fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 6, 2025.
Transparency logRelease files / ysaqml-2025.12.6.post4-py3-none-any.whl
| Download URL | ysaqml-2025.12.6.post4-py3-none-any.whl |
|---|---|
| Size | 13.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1aee12303d7e5e9e4af1ed4bd75980b65042172be36fa5d33b7bcda3abd7c85e
|
|
BLAKE2b-256 checksum How to use checksums |
bfd400c371bfdf85cef3cd53edc8cea79a33a795c44fabde7ce4b6250aec93e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Dec 6, 2025.
Transparency log