sillyorm package¶
Submodules¶
sillyorm.registry module¶
- class sillyorm.registry.Registry(create_engine_url: str, create_engine_kwargs: dict[str, Any] | None = None)¶
Bases:
object
sillyORM Model Registry - keeps track of models and handles model inheritance
- Variables:
engine – The SQLAlchemy database engine
metadata – The SQLAlchemy MetaData
- Parameters:
create_engine_url (str) – The URL passed to sqlalchemy.create_engine
create_engine_kwargs (dict[str, Any]) – keyword arguments passed to sqlalchemy.create_engine
- environment(autocommit: bool = False) Generator[Environment, None, None] ¶
Context manager for environments, will close the environment for you when you are done.
- Parameters:
autocommit (bool, optional) – Whether to automatically run commit after each database transaction that requires it (and rollback on error)
- get_environment(autocommit: bool = False) Environment ¶
Returns a new environment object (will also grab a new connection from the connection pool)
- Parameters:
autocommit (bool, optional) – Whether to automatically run commit after each database transaction that requires it (and rollback on error)
- Returns:
The new Environment object
- Return type:
- get_schema_diffs() Any ¶
Asks Alembic for the differences between the metadata in the registry and the current DB state are
- init_db_tables(automigrate: Literal['ignore', 'none', 'safe'] = 'safe') None ¶
Initializes database tables.
- register_model(model: type[Model]) None ¶
Registers a model class in the Registry (for later initialization)
The order in which this function is called on each model matters! It determines the exact inheritance!
- reset() None ¶
Reset the registry object, minus the models that have been registered
- reset_full() None ¶
Fully Reset the registry object, including the models that have been registered
- resolve_tables() None ¶
Resolve model inheritance and build the models table in the registry
sillyorm.environment module¶
- class sillyorm.environment.Environment(models: dict[str, type[Model]], connection: sqlalchemy.Connection, registry: Registry, autocommit: bool = False)¶
Bases:
object
This class is meant for keeping track of
models
registered in it, some settings and the database connection (SQLAlchemy Connection object).Once registered, models in the environment can be accessed using the index operator. When a model is accessed this way, it will return an empty recordset.
it is not meant to be initialized directly by the user
- Variables:
connection (sqlalchemy.Connection) – The database Connection
registry (
sillyorm.registry.Registry
) – The registry this environment object was created fromautocommit (bool) – Whether to automatically run commit after each database transaction that requires it (and rollback on error)
- Parameters:
models – The database cursor that will be passed to all models
connection (sqlalchemy.Connection) – The database connection
registry (
sillyorm.registry.Registry
) – The registry this environment object was created fromautocommit (bool, optional) – Whether to automatically run commit after each database transaction that requires it (and rollback on error)
- close() None ¶
Close this environment object, close it’s connection If it has an active transaction that will be rolled back.
- managed_transaction() Generator[None, None, None] ¶
Context manager for transactions, this is mostly for internal use and will do not do _anything_ without autocommit being set!
- transaction() Generator[None, None, None] ¶
Context manager for transactions, this will start a transaction and roll it back on error
sillyorm.exceptions module¶
- exception sillyorm.exceptions.SillyORMException¶
Bases:
Exception
Generic sillyORM Exceptions
sillyorm.fields module¶
- class sillyorm.fields.Boolean(required: bool = False, unique: bool = False)¶
Bases:
Field
Boolean field. Can represent either True or False.
class ExampleModel(sillyorm.model.Model): _name = "example_bool" field = sillyorm.fields.Boolean() env = reinit_env([ExampleModel]) record = env["example_bool"].create({"field": True}) print(record.field) record.field = False print(record.field) record.field = None print(record.field)
True False None
- sql_type: TypeEngine = Boolean()¶
- class sillyorm.fields.Date(required: bool = False, unique: bool = False)¶
Bases:
Field
Date field. Represents a python date object.
import datetime class ExampleModel(sillyorm.model.Model): _name = "example3" field = sillyorm.fields.Date() env = reinit_env([ExampleModel]) record = env["example3"].create({"field": datetime.date(1970, 1, 1)}) print(record.field) record.field += datetime.timedelta(days=1) print(record.field) record.field = None print(record.field)
1970-01-01 1970-01-02 None
- sql_type: TypeEngine = Date()¶
- class sillyorm.fields.Datetime(tzinfo: tzinfo | None, required: bool = False, unique: bool = False)¶
Bases:
Field
Datetime field. Represents a python datetime object.
A timezone (or the value None - which means it’s naive) must be provided because in the database this field may not store any timzeone-related information. Mixing timezones would be fatal so this field takes care of that for you.
- Parameters:
tzinfo (datetime.tzinfo | None) – time zone of the date stored - None means it’s a naive datetime object
import datetime class ExampleModel(sillyorm.model.Model): _name = "example_datetime" field = sillyorm.fields.Datetime(None) env = reinit_env([ExampleModel]) record = env["example_datetime"].create({"field": datetime.datetime(1970, 1, 1, 1, 2, 3)}) print(record.field) record.field += datetime.timedelta(days=1, hours=2, minutes=6) print(record.field) record.field = None print(record.field)
1970-01-01 01:02:03 1970-01-02 03:08:03 None
- sql_type: TypeEngine = DateTime()¶
- class sillyorm.fields.Field(required: bool = False, unique: bool = False)¶
Bases:
object
Base descriptor class for
BaseModel
fields- Variables:
sql_type (
sqlalchemy.types.TypeEngine
) – SQL type of the fieldmaterialize (bool) – Whether the field actually exists as a column in the database table
constraints (list[sqlalchemy.schema.Constraint | tuple[str, Any]]) – SQL constraints of the field
name (str) – column name of the field
required (bool) – If the field must be set (checked via SQL constraints and runtime checks)
unique (bool) – If the field’s value should be unique in the column (checked via SQL constraints)
- Parameters:
required (bool) – If the field must be set (checked via SQL constraints and runtime checks)
unique (bool) – If the field’s value should be unique in the column (checked via SQL constraints)
- Default required:
False
- Default unique:
False
- materialize = True¶
- name: str = None¶
- sql_type: TypeEngine = None¶
- class sillyorm.fields.Float(required: bool = False, unique: bool = False)¶
Bases:
Field
Float field. Can represent floating point numbers from at least
-1.2e-38
to3.4e+38
(may be significantly more depending on the dbms used).class ExampleModel(sillyorm.model.Model): _name = "example_float" field = sillyorm.fields.Float() env = reinit_env([ExampleModel]) record = env["example_float"].create({"field": 32768.123321}) print(record.field) record.field = -0.000000000000000000000000000000000000012 print(record.field) record.field = 340000000000000000000000000000000000000.0 print(record.field) record.field = None print(record.field)
32768.123321 -1.2e-38 3.4e+38 None
- sql_type: TypeEngine = Float()¶
- class sillyorm.fields.Id(required: bool = False, unique: bool = False)¶
Bases:
Integer
Special ID field used as PRIMARY KEY in model tables. It’s value cannot be changed.
class ExampleModel(sillyorm.model.Model): _name = "example1" # Each model automatically has an ID field env = reinit_env([ExampleModel]) record = env["example1"].create({}) record2 = env["example1"].create({}) print(record.id) print(record2.id)
1 2
- class sillyorm.fields.Integer(required: bool = False, unique: bool = False)¶
Bases:
Field
Integer field. Can represent numbers from at least
-32768
to32767
(may be significantly more depending on the dbms used).class ExampleModel(sillyorm.model.Model): _name = "example0" field = sillyorm.fields.Integer() env = reinit_env([ExampleModel]) record = env["example0"].create({"field": 5}) print(record.field) record.field = -32768 print(record.field) record.field = 32767 print(record.field) record.field = None print(record.field)
5 -32768 32767 None
- sql_type: TypeEngine = Integer()¶
- class sillyorm.fields.Many2one(foreign_model: str, required: bool = False, unique: bool = False)¶
Bases:
Integer
Many to one relational field. Represents a single record of another model.
When read this field returns a recordset. When written it expects an integer (the ID of a foreign record).
class ExampleModel1(sillyorm.model.Model): _name = "example4" field = sillyorm.fields.String() class ExampleModel2(sillyorm.model.Model): _name = "example5" many2one_field = sillyorm.fields.Many2one("example4") env = reinit_env([ExampleModel1, ExampleModel2]) other_record = env["example4"].create({"field": "Hello world!"}) record = env["example5"].create({"many2one_field": other_record.id}) print(other_record.field) print(record.many2one_field) print(record.many2one_field.field) record.many2one_field.field = "test" print(other_record.field) record.many2one_field = None print(record.many2one_field)
Hello world! example4[1] Hello world! test None
- Parameters:
foreign_model (str) – Foreign model name
- class sillyorm.fields.One2many(foreign_model: str, foreign_field: str, required: bool = False, unique: bool = False)¶
Bases:
Field
One to many relational field. It’s the inverse of a
Many2one
field. Represents multiple records of another model. This field does not exist in the database table.When read this field returns a recordset. It cannot be written.
class ExampleModel1(sillyorm.model.Model): _name = "example6" field = sillyorm.fields.String() one2many_field = sillyorm.fields.One2many("example7", "many2one_field") class ExampleModel2(sillyorm.model.Model): _name = "example7" many2one_field = sillyorm.fields.Many2one("example6") env = reinit_env([ExampleModel1, ExampleModel2]) other_record = env["example6"].create({}) record = env["example7"].create({"many2one_field": other_record.id}) record2 = env["example7"].create({"many2one_field": other_record.id}) print(record.many2one_field) print(record2.many2one_field) print(other_record.one2many_field)
example6[1] example6[1] example7[1, 2]
- Parameters:
foreign_model (str) – Foreign model name
foreign_field (str) – Foreign
Many2one
field name
- materialize = False¶
- class sillyorm.fields.Selection(options: list[str], length: int = 255, required: bool = False, unique: bool = False)¶
Bases:
String
Selection field. Basically just a string field with a little logic around it that allows you to choose between multiple different predefined options.
class ExampleModel(sillyorm.model.Model): _name = "example_selection" field = sillyorm.fields.Selection(["option1", "option2"]) env = reinit_env([ExampleModel]) record = env["example_selection"].create({"field": "option1"}) print(record.field) record.field = "option2" print(record.field) record.field = None print(record.field)
option1 option2 None
- Parameters:
options (list[str]) – List of possible selection options
length (int, optional) – Maximum selection length, defaults to 255
- class sillyorm.fields.String(length: int = 255, required: bool = False, unique: bool = False)¶
Bases:
Field
String field. Represents a string of at most
length
charactersclass ExampleModel(sillyorm.model.Model): _name = "example2" field = sillyorm.fields.String() env = reinit_env([ExampleModel]) record = env["example2"].create({"field": "hello"}) print(record.field) record.field += " world!" print(record.field) record.field = None print(record.field)
hello hello world! None
- Parameters:
length (int, optional) – Maximum string length, defaults to 255
- class sillyorm.fields.Text(required: bool = False, unique: bool = False)¶
Bases:
Field
Text field. Represents a large string of text
class ExampleModel(sillyorm.model.Model): _name = "example_text" field = sillyorm.fields.Text() env = reinit_env([ExampleModel]) record = env["example_text"].create({"field": "hello"}) print(record.field) record.field += " world!" print(record.field) largestring = "0123456789" * 100000 # 1MB of data record.field = largestring print(record.field == largestring) record.field = None print(record.field)
hello hello world! True None
sillyorm.model module¶
- class sillyorm.model.AbstractModel(env: Environment, ids: list[int])¶
Bases:
BaseModel
Use this as the base for any Abstract Models. Won’t create a database table. See
sillyorm.model.BaseModel
for docs
- class sillyorm.model.BaseModel(env: Environment, ids: list[int])¶
Bases:
object
Each model represents a single table in the database. A model can have fields which represent columns in the database table.
The _name attribute specifies the name of the database table the model represents and the name of the model in the environment.
An instance of the model class (or a subclass instance) represents a recordset.
Warning
You should never call the constructor of the model class yourself. Get an empty recordset via the environment and interact with the model from there.
class ExampleModel(sillyorm.model.Model): _name = "example0" field = sillyorm.fields.String() registry.register_model(ExampleModel) registry.resolve_tables() registry.init_db_tables() env = registry.get_environment() record = env["example0"].create({"field": "Hello world!"}) print(record.field)
Hello world!
- Variables:
env (
sillyorm.environment.Environment
) – The environment- Parameters:
env (list[int]) – The environment
ids – list of id’s the recordset should have
- __getitem__(key: int) Self ¶
- __iter__() Iterator[Self] ¶
- browse(ids: list[int] | int) None | Self ¶
Returns a recordset for the ids provided.
Warning
The order of the ids in the recordset returned may not be the same as the ids provided as input
- Parameters:
ids – The ids or id
- Returns:
A recordset with the ids provided. None if none of the ids could be found
- Return type:
None | Self
- create(vals: dict[str, Any]) Self ¶
Creates a recordset with the values provided.
- Parameters:
vals (dict[str, Any]) – The values to write into the new recordset. The keys represent the field names and the values the values for the fields
- Returns:
The recordset that was created (containing one record)
- Return type:
Self
- delete() None ¶
Deletes all records in the recordset
- ensure_one() Self ¶
Makes sure the recordset contains exactly one record. Raises an exception otherwise
- Raises:
SillyORMException – If the recordset does not contain exactly one record
- id¶
Special
sillyorm.fields.Id
field used as PRIMARY KEY
- read(field_names: list[str]) list[dict[str, Any]] ¶
Reads the specified fields of the recordset.
- Parameters:
field_names (list[str]) – The fields to read
- Returns:
The fields read as a list of dictionaries.
- Return type:
list[dict[str, Any]]
- search(domain: list[str | tuple[str, str, Any]], order_by: str | None = None, order_asc: bool = True, offset: int | None = None, limit: int | None = None) Self ¶
Searches records.
Search domains are closely tied to the SQL WHERE statement.
[ "(", ("test2", "=", "test2"), "&", ("test", "=", "hello world!"), ")", "|", ("test2", "=", "2 Hii!!"), ]
This search domain will result in SQL code that looks something like this:
SELECT "id" FROM "test_model" WHERE ( "test2" = 'test2' AND "test" = 'hello world!' ) OR "test2" = '2 Hii!!';
Search operators:
= Equals to
!= not equal
> greater than
>= greater than or equal
< less than
<= less than or equal
=ilike matches against the pattern provided (case-insentitive), _ in the pattern matches any single character and % matches any string of zero or more characters
ilike similar to =ilike but will wrap the pattern provided in %
Usage example:
class ExampleModel(sillyorm.model.Model): _name = "example1" field = sillyorm.fields.String() registry.register_model(ExampleModel) registry.resolve_tables() registry.init_db_tables() env = registry.get_environment() record1 = env["example1"].create({"field": "test1"}) record2 = env["example1"].create({"field": "test2"}) record3 = env["example1"].create({"field": "test3"}) print(record1.id, record2.id, record3.id) print(env["example1"].search([ ("field", "=", "test1"), "|", ("field", "!=", "test2"), ]))
1 2 3 example1[1, 3]
- Parameters:
domain (list[str | tuple[str, str, Any]]) – The search domain.
order_by (str | None) – The column to order by
order_asc (bool) – Wether the order is ascending or not
offset (int | None) – The row offset to use
limit (int | None) – The maximum amount of rows to return
- Returns:
A recordset with the records found. An empty recordset if nothing could be found
- Return type:
Self
- search_count(domain: list[str | tuple[str, str, Any]]) int ¶
Counts the total amount of records that match a domain.
The domain is the same format as for the search function.
Usage example:
class ExampleModel(sillyorm.model.Model): _name = "example_msc1" field = sillyorm.fields.String() registry.register_model(ExampleModel) registry.resolve_tables() registry.init_db_tables() env = registry.get_environment() record1 = env["example_msc1"].create({"field": "test1"}) record2 = env["example_msc1"].create({"field": "test1"}) record3 = env["example_msc1"].create({"field": "test2"}) print(env["example_msc1"].search_count([ ("field", "=", "test1"), ])) print(env["example_msc1"].search_count([ ("field", "=", "test2"), ]))
2 1
- Parameters:
domain (list[str | tuple[str, str, Any]]) – The search domain.
- Returns:
The amount of records that match the provided domain
- Return type:
int
- write(vals: dict[str, Any]) None ¶
Writes the specified fields into all records contained in the recordset.
- Parameters:
vals (dict[str, Any]) – The values to write. The keys represent the field names and the values the values for the fields
- class sillyorm.model.Model(env: Environment, ids: list[int])¶
Bases:
BaseModel
Use this as the base for any normal Models. Will create a database table. See
sillyorm.model.BaseModel
for docs
sillyorm.migration_helpers module¶
- sillyorm.migration_helpers.helper_do_migrate(revision: str = 'head', downgrade: bool = False) None ¶
Runs migration scripts up to revision
- sillyorm.migration_helpers.helper_gen_migrations(message: str | Callable[[], str], revid: str | None = None, head: str = 'head') bool ¶
Checks for difference of the Registry metadata to the DB autogenerates a migration script, returns True if a migration was generated, False otherwise
- sillyorm.migration_helpers.helper_init(registry: Registry, migration_folder_path: str, script_template_path: str | None = None, version_table: str = 'alembic_version') None ¶
Initialize the migration helper. This must be called before using any of the helper functions!
Will also initialize the migration folder in case it isn’t initialized yet