Welcome to sqlalchemyseed’s documentation!#
SQLAlchemy seeder that supports nested relationships with an easy to read text files.
Introduction#
sqlalchemyseed is a SQLAlchemy seeder that supports nested relationships with an easy to read text files.
Supported file types :
json
yaml
csv
Installation#
Default installation
pip install sqlalchemyseed
When using yaml to load entities from yaml files, execute this command to install necessary dependencies
pip install sqlalchemyseed[yaml]
Dependencies#
- Required dependencies:
SQAlchemy>=1.4.0
- Optional dependencies:
yaml: PyYAML>=5.4.0
Quickstart#
Here’s a simple snippet to get started from main.py
file.
from sqlalchemyseed import load_entities_from_json
from sqlalchemyseed import Seeder
from db import session
# load entities
entities = load_entities_from_json('data.json')
# Initializing Seeder
seeder = Seeder(session)
# Seeding
seeder.seed(entities)
# Committing
session.commit() # or seeder.session.commit()
And the data.json
file.
{
"model": "models.Person",
"data": [
{
"name": "John March",
"age": 23
},
{
"name": "Juan Dela Cruz",
"age": 21
}
]
}
Seeding#
Seeder vs. HybridSeeder#
Features & Options |
Seeder |
HybridSeeder |
---|---|---|
Support |
✔️ |
✔️ |
Support |
❌ |
✔️ |
Optional argument |
✔️ |
❌ |
When to use HybridSeeder and ‘filter’ key field?#
Assuming that Child(age=5)
exists in the database or session,
then we should use filter
instead of data
key.
The values from filter
will query from the database or session,
and get the result then assign it to the Parent.child
from sqlalchemyseed import HybridSeeder
from db import session
data = {
"model": "models.Parent",
"data": {
"!child": { # '!' is the reference prefix
"model": "models.Child",
"filter": {
"age": 5
}
}
}
}
# When seeding instances that has 'filter' key,
# then use HybridSeeder, otherwise use Seeder.
seeder = HybridSeeder(session, ref_prefix='!')
seeder.seed(data)
session.commit() # or seeder.sesssion.commit()
Note
filter
key is dependent to HybridSeeder in order to perform correctly.
Referencing Relationships#
To add reference attribute, add prefix to the attribute to differentiate reference attribute from normal ones.
{
"model": "models.Employee",
"data": {
"name": "John Smith",
"!company": {
"model": "models.Company",
"data": {
"name": "MyCompany"
}
}
}
}
Base on the example above, name is a normal attribute and !company is a reference attribute
which translates to Employee.name
and Employee.company
, respectively.
Note
The default reference prefix is !
and can be customized.
Customizing reference prefix#
If you want @
as prefix,
you can just specify it to what seeder you use by
assigning value of Seeder.ref_prefix
or HybridSeeeder.ref_prefix
.
Default value is !
seeder = Seeder(session, ref_prefix='@')
# or
seeder = Seeder(session)
seeder.ref_prefix = '@'
Types of reference attributes#
Reference attribute types:
foreign key attribute
relationship attribute
You can reference a foreign key and relationship attribute in the same way. For example:
from sqlalchemyseed import HybridSeeder
from db import session
instance = {
'model': 'tests.models.Employee',
'data': [
{
'name': 'John Smith',
'!company_id': { # this is the foreign key attribute
'model': 'tests.models.Company',
'filter': {
'name': 'MyCompany'
}
}
},
{
'name': 'Juan Dela Cruz',
'!company': { # this is the relationship attribute
'model': 'tests.models.Company',
'filter': {
'name': 'MyCompany'
}
}
]
}
seeder = HybridSeeder(session)
seeder.seed(instance)
seeder.session.commit()
Note
model
can be removed if the attribute is a reference attribute like this:
{
"model": "models.Employee",
"data": {
"name": "Juan Dela Cruz",
"!company": {
"data": {
"name": "Juan's Company"
}
}
}
}
Notice above that model
is removed in !company
.
Examples#
json#
{
"model": "models.Person",
"data": [
{
"name": "John March",
"age": 23
},
{
"name": "Juan Dela Cruz",
"age": 21
}
]
}
yaml#
model: models.Person
data:
- name: John March
age: 23
- name: Juan Dela Cruz
age: 21
csv#
In line one, name and age, are attributes of a model that will be specified when loading the file.
name, age
John March, 23
Juan Dela Cruz, 21
To load a csv file
# second argument, model, accepts class
load_entities_from_csv("people.csv", models.Person)
# or string
load_entities_from_csv("people.csv", "models.Person")
Note
csv does not support referencing relationships.
No Relationship#
[
{
"model": "models.Person",
"data": {
"name": "You",
"age": 18
}
},
{
"model": "models.Person",
"data": [
{
"name": "You",
"age": 18
},
{
"name": "Still You But Older",
"age": 40
}
]
}
]
One to One Relationship#
[
{
"model": "models.Person",
"data": {
"name": "John",
"age": 18,
"!job": {
"model": "models.Job",
"data": {
"job_name": "Programmer",
}
}
}
},
{
"model": "models.Person",
"data": {
"name": "Jeniffer",
"age": 18,
"!job": {
"model": "models.Job",
"filter": {
"job_name": "Programmer",
}
}
}
}
]
One to Many Relationship#
[
{
"model": "models.Person",
"data": {
"name": "John",
"age": 18,
"!items": [
{
"model": "models.Item",
"data": {
"name": "Pencil"
}
},
{
"model": "models.Item",
"data": {
"name": "Eraser"
}
}
]
}
}
]
Nested Relationships
{
"model": "models.Parent",
"data": {
"name": "John Smith",
"!children": [
{
"model": "models.Child",
"data": {
"name": "Mark Smith",
"!children": [
{
"model": "models.GrandChild",
"data": {
"name": "Alice Smith"
}
}
]
}
}
]
}
}
API Reference#
This page contains auto-generated API reference documentation [1].
sqlalchemyseed
#
SQLAlchemy seeder that supports nested relationships with an easy to read text files.
Submodules#
sqlalchemyseed.attribute
#
attribute module containing helper functions for instrumented attribute.
Module Contents#
- sqlalchemyseed.attribute.attr_is_column(instrumented_attr: sqlalchemy.orm.attributes.InstrumentedAttribute)#
Check if instrumented attribute property is a ColumnProperty
- sqlalchemyseed.attribute.attr_is_relationship(instrumented_attr: sqlalchemy.orm.attributes.InstrumentedAttribute)#
Check if instrumented attribute property is a RelationshipProperty
- sqlalchemyseed.attribute.foreign_key_column(instrumented_attr: sqlalchemy.orm.attributes.InstrumentedAttribute)#
Returns the table name of the first foreignkey.
- sqlalchemyseed.attribute.instrumented_attribute(class_or_instance, key: str)#
Returns instrumented attribute from the class or instance.
- sqlalchemyseed.attribute.referenced_class(instrumented_attr: sqlalchemy.orm.attributes.InstrumentedAttribute)#
Returns class that the attribute is referenced to.
- sqlalchemyseed.attribute.set_instance_attribute(instance, key, value)#
Set attribute value of instance
sqlalchemyseed.constants
#
Module Contents#
- sqlalchemyseed.constants.DATA_KEY = 'data'#
- sqlalchemyseed.constants.FILTER_KEY = 'filter'#
- sqlalchemyseed.constants.MODEL_KEY = 'model'#
- sqlalchemyseed.constants.SOURCE_KEYS#
sqlalchemyseed.dynamic_seeder
#
Module Contents#
- class sqlalchemyseed.dynamic_seeder.DynamicSeeder#
DynamicSeeder class
sqlalchemyseed.errors
#
Module Contents#
- exception sqlalchemyseed.errors.ClassNotFoundError#
Bases:
Exception
Raised when the class is not found
- exception sqlalchemyseed.errors.EmptyDataError#
Bases:
Exception
Raised when data is empty
- exception sqlalchemyseed.errors.InvalidKeyError#
Bases:
Exception
Raised when an invalid key is invoked
- exception sqlalchemyseed.errors.InvalidModelPath#
Bases:
Exception
Raised when an invalid model path is invoked
- exception sqlalchemyseed.errors.InvalidTypeError#
Bases:
Exception
Raised when a type of data is not accepted
- exception sqlalchemyseed.errors.MaxLengthExceededError#
Bases:
Exception
Raised when maximum length of data exceeded
- exception sqlalchemyseed.errors.MissingKeyError#
Bases:
Exception
Raised when a required key is missing
- exception sqlalchemyseed.errors.NotInModuleError#
Bases:
Exception
Raised when a value is not found in module
- exception sqlalchemyseed.errors.ParseError#
Bases:
Exception
Raised when parsing string fails
- exception sqlalchemyseed.errors.UnsupportedClassError#
Bases:
Exception
Raised when an unsupported class is invoked
sqlalchemyseed.json
#
Module Contents#
- class sqlalchemyseed.json.JsonWalker(json: list | dict = None)#
JsonWalker class
- property current_key: int | str#
Returns the key of the current json
- property json#
Returns current json
- property json_is_dict#
Returns true if current json is dict
- property json_is_list#
Returns true if current json is list
- backward()#
Revert current json to its parent. Returns reverted current json
- exec_func_iter(func: Callable)#
Executes function when iterating
- find_from_current(keys: List[int | str])#
Find item from current json that correlates list of keys
- find_from_root(keys: List[int | str])#
Find item from the root json that correlates list of keys
- forward(keys: List[int | str])#
Move and replace current json forward. Returns current json.
- iter_as_dict_items()#
Iterates current as dict. Yields key and value.
Raises TypeError if current json is not dict
- iter_as_list()#
Iterates current as list. Yields index and value.
Raises TypeError if current json is not list
- keys()#
Returns list of keys either str or int
- reset(root=None)#
Resets to initial state. If root argument is supplied, self.root will be replaced.
- sqlalchemyseed.json.sort_json(json: list | dict, reverse=False)#
Sort json function
sqlalchemyseed.loader
#
Text file loader module
Module Contents#
- sqlalchemyseed.loader.load_entities_from_csv(csv_filepath: str, model) dict #
Load entities from csv file
- Parameters:
csv_filepath – string csv file path
model – either str or class
- Returns:
dict of entities
- sqlalchemyseed.loader.load_entities_from_json(json_filepath) dict #
Get entities from json
- sqlalchemyseed.loader.load_entities_from_yaml(yaml_filepath)#
Get entities from yaml
sqlalchemyseed.seeder
#
Seeder module
Module Contents#
- class sqlalchemyseed.seeder.AbstractSeeder#
Bases:
abc.ABC
AbstractSeeder class
- abstract property instances#
Seeded instances
- abstract seed(entities)#
Seed data
- class sqlalchemyseed.seeder.DynamicSeeder#
DynamicSeeder class
- class sqlalchemyseed.seeder.HybridSeeder(session: sqlalchemy.orm.Session, ref_prefix: str = '!')#
Bases:
AbstractSeeder
HybridSeeder class. Accepts ‘filter’ key for referencing children.
- property instances#
Seeded instances
- get_model_class(entity, parent: InstanceAttributeTuple)#
- seed(entities)#
Seed data
- class sqlalchemyseed.seeder.InstanceAttributeTuple#
Bases:
NamedTuple
Instrance and attribute name tuple
- attr_name: str#
- instance: object#
- class sqlalchemyseed.seeder.Seeder(session: sqlalchemy.orm.Session = None, ref_prefix='!')#
Basic Seeder class
- property instances: tuple#
Returns instances of the seeded entities
- seed(entities: list | dict, add_to_session=True)#
Seed method
- sqlalchemyseed.seeder.filter_kwargs(kwargs: dict, class_, ref_prefix)#
Filters kwargs
sqlalchemyseed.util
#
Utility functions
Module Contents#
- sqlalchemyseed.util.find_item(json: Iterable, keys: list)#
Finds item of json from keys
- sqlalchemyseed.util.generate_repr(instance: object) str #
Generate repr of object instance
- sqlalchemyseed.util.get_model_class(path: str)#
Get sqlalchemy model class from path
- sqlalchemyseed.util.is_model(class_)#
Check if class is a sqlalchemy model
- sqlalchemyseed.util.is_supported_class(class_)#
Check if it is a class and supports sqlalchemy
- sqlalchemyseed.util.iter_kwargs_with_prefix(kwargs: dict, prefix: str)#
Iterate kwargs(dict) that has the specified prefix.
- sqlalchemyseed.util.iter_non_ref_kwargs(kwargs: dict, ref_prefix: str)#
Iterate kwargs, skipping item with name prefix or references
- sqlalchemyseed.util.iter_ref_kwargs(kwargs: dict, ref_prefix: str)#
Iterate kwargs with name prefix or references
- sqlalchemyseed.util.iterate_json(json: dict, key_prefix: str)#
Iterate through json that has matching key prefix
- sqlalchemyseed.util.iterate_json_no_prefix(json: dict, key_prefix: str)#
Iterate through json that has no matching key prefix
sqlalchemyseed.validator
#
Validator module.
Module Contents#
- class sqlalchemyseed.validator.Key(name: str, type_)#
- classmethod data()#
- classmethod filter()#
- is_valid_type(entity)#
- classmethod model()#
- class sqlalchemyseed.validator.SchemaValidator(source_keys, ref_prefix)#
- check_attributes(source_data: dict)#
- validate(entities)#
- sqlalchemyseed.validator.check_max_length(entity: dict)#
- sqlalchemyseed.validator.check_model_key(entity: dict, entity_is_parent: bool)#
- sqlalchemyseed.validator.hybrid_validate(entities, ref_prefix='!')#
- sqlalchemyseed.validator.validate(entities, ref_prefix='!')#