This module provides a lightweight sqlite3 ORM for normal dataclasses.
Project description
dataclassdb [BETA]
This module provides a lightweight sqlite3 ORM for dataclasses.
| docs |
|
|---|
Installation
To install dataclassdb, simply use 'pip:
pip install dataclassdb
Requirements
Minimum Python version supported by dataclassdb is 3.11. The only dependency is dacite.
Quick Start
from dataclassdb import DataclassDb
from types import Annotated
from dataclasses import dataclass, Annotated
@dataclass
class Foo:
id: Annotated[int, "PRIMARY KEY"]
bar: str
baz: list[int]
with DataclassDb(Foo, "example.db") as db:
# Insert and get
db.insert(Foo(0, "x", [1, 2, 3]))
foo = db.get(0)
# Arbitrary SQL
db.SELECT("bar").FROM(FOO).WHERE("id").eq("?")
selection = db.execute_one(0) # Replaces ? with 0
Overview
- Uses
@dataclassclasses to generate and interact with database files usingsqlite3. No "Model" super class required. - SQL table columns are inferred by the dataclass field annotation.
- Codecs(Encoder/Decoder) translate Python to SQL and back.
- Build in QueryBuilder with every SQL statement and function for easy query writing
- Built in DbEngine context manager for managing the db connection, creating tables, and executing queries.
Deeper Dive
- Each
@dataclassfields' SQL type is inferred by the python type or by override. By default, undefined mapping are set to "TEXT". - A Codec (Encoder/Decoder) is used to translate between python and SQL. The following are supported:
- Basic Types:
int,str,float,bool - Enums:
Enum,StrEnum - Dates:
datetime -> INTEGER (unix time),datetime -> TEXT (ISO 8601) - Json:
list,dict,@dataclass(If all elements are json encodable) - Pickle (Bytes): Any
pythonobject. Notablysets are not json encodable. Pickle is not safe and should be used with caution**. - Any user defined Codec
- Basic Types:
- Constraints
such as
PRIMARY KEYorUNIQUEcan be added astyping.Annotatedmetadata without affecting the base type. - Dataclass field defaults are encoded
- "NOT NULL" field status is inferred by the
Column type is inferred by the python type and SQL type.
- The column type is inferred by the python type but can be overridden as the first annotation.
- This package does not attempt to abstract away SQL behavior. It's simply a lightweight wrapper around sqlite3.
Motivation
1. Easier to write than plaintext
- All sqlite keywords and functions are supported
- Queries can be written written without filler words.
- Lists and args are handled how you'd expect them to be handled.
2. Easier to write than SqlAlchemy, SqlModel, and other more complex abstractions
- No required imports QueryBuilder
- Minimal package specific syntax or abstractions to learn
3. Abstracts away Non-SQL, sqlite3, actions
- Creating connection
- Executing the query
- Returning the result as a list or dictionary
Features
- DataclassDb: Maps dataclass class into a sqlite3 table.
- QueryBuilder: Specialized StringBuilder with methods for each sqlite3 keywords and functions. Note that DataclassDb inherits from QueryBuilder.
- DbEngine:
- Codec: Protocol
DataclassDb
Column Definition
col_name: Annotated(Type, ? [SQL Type], *[Constraints], [Codec])
- Type: The python type for the dataclass field
- SQL Type: Override the default mapped SQL type (see next section)
- Constraints: SQL constraints as text
- Codec: Overrides the default codec. Any object that is a Codec (has an encode and decode method)
Examples:
| Python Field | Sqlite Col Definition |
|---|---|
id: Annotated[int, "PRIMARY KEY"] |
id INTEGER PRIMARY KEY NOT NULL |
username: Annotated[str, "UNIQUE"] |
username TEXT UNIQUE NOT NULL |
email: str = "" |
email TEXT NOT NULL DEFAULT "" |
Python type to SQL type resolution
Because sqlite has a limited amount of supported types: (INTEGER, TEXT, REAL, NUMERICAL, BLOB), we must map between python types and SQL types.
The "easiest" way to do this is by converting our python object into binary using pickle and storing it as a BLOB. However, there are a few issues with this approach.
- Pickle is unsafe (bad actors can run arbitrary code on decode.)
- This data cannot be read without decoding.
- This data cannot be used in queries without decoding.
This package approaches this issue by using Codecs (Encoder/Decoder) to handle the python -> sqlite -> python conversions. If no SQL type is declared in the Annotated column definition, first checks the below mapping.
If no mapping is found, the column is assumed to be json encodable. This setting can be overridden by either providing a custom Codec or setting the type to "BLOB".
| SQL Type | python type | Codec |
|---|---|---|
| TEXT | datetime | DatetimeTextCodec |
| TEXT | str | IdentityCodec |
| TEXT | default | JsonCodec |
| INTEGER | datetime | DatetimeIntCodec |
| INTEGER | bool | BoolCodec |
| INTEGER | int | IdentityCodec |
| REAL | float | IdentityCodec |
| BLOB | @dataclass | DataclassPickleCodec |
| BLOB | default | PickleCodec |
Query Builder
qb = QueryBuilder() # str(qb)
qb.SELECT # = SELECT
qb("a", "b").Group_concat("c") # = SELECT a b group_concat(c)
- All SQL statement keywords, such as
SELECT,FROM, etc. are available as chainable properties of Query buildersquery.SELECTor as standalone variablesdb.SELECT. See StatementBuilder or SQL enum - Similarly, all SQL functions, such as
count,sum,group_concatare available as chainable functionsquery.SELECT.Count("type")or as standalone functionsdb.Count("type"). See QueryBuilder or SQL_FUNC enum - QueryBuilders
__call__adds provided arguments to the string as a list, with optional quote and parenthesis options.
QueryBuilder is a fancy SQL flavored String Builder which the following goals:
Convention breaking weirdness
SQL statements leverage a totally legal but questionable hack. Each statement is a @property that returns self. The
__call__ handles the case where the object is called directly. Note that SQL functions are NOT properties.
So to for the Query qb.SELECT("a","b")
qb.SELECT: Calls the propertySELECTwhich adds"SELECT"to the string. It returns self.qb.SELECT("a", "b")calls__call__function instead ofSELECTfunction.
Comparing QueryBuilder, plain sqlite3 and sqlAlchemy
QueryBuilder
query = QueryBuilder("example.db").
query.SELECT("name").FROM("sqlite_master").WHERE("name='spam'")
result = query.execute()
Sqlite3
#sqlite3
con = sqlite3.connect("example.db")
cur = con.cursor()
res = cur.execute("SELECT name FROM sqlite_master WHERE name='spam'")
sqlAlchemy
engine = create_engine("sqlite:///example.db")
with engine.connect() as conn:
query = text("SELECT name FROM sqlite_master WHERE name='spam'")
res = conn.execute(query)
Bonus functions
placeholders(n)adds string "(? ... n)"show()prints the query at its current statebrnewlinelpar"("rpar")"rpar")"comma","execute(*args): Executes the command with the provided args replacing the placeholders.
Created By
Stuart (@stuarts_art)
- Washed dev who now makes furry art
- I branched this out of ArtRefSync, a pure python desktop ui to sync reference art from SFW and NSFW image boards.
- It uses client provided api keys to ethically get data while respecting usage rules
- User defined black list to avoid the scourge of AI art
- Is not using excessive ram to spy on you (plus memory is expensive)
Project details
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 dataclassdb-0.1.6.tar.gz.
File metadata
- Download URL: dataclassdb-0.1.6.tar.gz
- Upload date:
- Size: 35.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
549802edc63221e43f6cc1e4c397abf9404524f9ee7140f120bc824248c0af05
|
|
| MD5 |
0bed5ac00feab9ecd99af80d3f8c57be
|
|
| BLAKE2b-256 |
6411fd05ec16a8864336b981ff4c473d6b658c3a1c100d8ba06a0a94693b2518
|
File details
Details for the file dataclassdb-0.1.6-py3-none-any.whl.
File metadata
- Download URL: dataclassdb-0.1.6-py3-none-any.whl
- Upload date:
- Size: 26.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2245fdbd1edc8dcd746321b40f177673b0e4290fd09f58de966a0ddc640ccb83
|
|
| MD5 |
dcdd7128ad0ce42159f01e27ef6dbec6
|
|
| BLAKE2b-256 |
21e6f063acf6b9258cfcbedca9c63fbc4f142e768523aa1ab5f3e0df2672176f
|