Distillery
distillery
is another factory_girl like library for python
ORMs.
Installation
pip install distillery
Distilleries
Each distillery has a __model__
and a set of attributes and
methods. The __model__
is the ORM model class from which instance
will be produced:
class UserDistillery(MyOrmDistillery):
__model__ = User
Attributes
A distillery class attribute defines default values for specific model field:
class UserDistillery(MyOrmDistillery):
__model__ = User
username = "defaultusername"
The distillery's attribute values act as defaults. If a User
object is created using this distillery, its username
attribute
will default to "defaultusername"
.
Lazy attributes
Using the lazy
decorator, you can provide dynamic attributes.
from distillery import lazy
class UserDistillery(MyOrmDistillery):
__model__ = User
username = "defaultusername"
@lazy
def email_address(cls, instance, sequence):
return "%s@%s" % (instance.username, instance.company.domain)
All new User
created from UserDistillery
will have an
email_address
computed from his username and his company domain.
Note: all lazies received an instance
and a sequence
that are
the object instance and an auto-incremented sequence, respectively.
Hooks
A distillery can provide an _after_create
class method to hook
into the factory machinery.
class UserDistillery(MyOrmDistillery):
__model__ = User
username = "defaultusername"
@classmethod
def _after_create(cls, instance):
# Do stuff after instance creation
# ...
Distillery.init()
The init()
method creates and populates a new instance.
user = UserDistillery.init()
assert user.username == "defaultusername"
assert user.id is None
user = UserDistillery.create(username="overriddenusername")
assert user.username == "overriddenusername"
assert user.id is None
Distillery.create()
The create()
method initializes the object using init()
and
subsequently saves it.
user = UserDistillery.create()
assert user.username == "defaultusername"
assert user.id is not None
Distillery.bulk()
Creates instances in bulk.
users = UserDistillery.bulk(12, username="user_%(i)%")
assert users[7].username = 'user_7'
Sets
The distillery.Set
class acts as a fixture container.
It's required to define a __distillery__
attribute which is used
to create objects.
from distillery import Set
class UserSet(Set):
__distillery__ = UserDistillery
class jeanphix:
username = 'jeanphix'
To create the fixtures, simply instantiate the set.
users = UserSet()
assert users.jeanphix.username == 'jeanphix'
Importantly, as long as a reference to the instantiated set is held
(e.g. the users
variable in this example), the set can be called
again and the same instance is returned:
assert UserSet() is UserSet()
You can reference other sets, too. Note that you must reference using the class, or use a lazy attribute (described later):
from distillery import Set
class CompanySet(Set):
__distillery__ = CompanyDistillery
class my_company:
name = 'My company'
class UserSet(Set):
__distillery__ = UserDistillery
class jeanphix:
username = 'jeanphix'
company = CompanySet.company
users = UserSet()
assert users.jeanphix.company == 'My company'
In addition to classes, methods can be defined; each will result in an object which is added to the set.
class ProfileSet(Set)
class __distillery__:
__model__ = Profile
admin = lambda s: UserDistillery.create(username='admin').profile
This functionality extends to class-based references. Note that the reference must be resolvable at the point of creation; circular relationships are currently not supported.
class UserSet(Set):
class peter:
friend = None
class paul:
friend = classmethod(lambda c: UserSet.peter)
If the on_demand
flag is set, objects are created only when first
accessed.
users = UserSet(on_demand=True)
users.jeanphix # jeanphix will be created here.
Finally, sets can be nested.
class fixtures(Set):
users = UserSet
assert fixtures().users.jeanphix.username == 'jeanphix'
Hooks
Each fixture in a set can provide an _after_create
listener:
class ProfileSet(Set):
class __distillery__:
__model__ = Profile
class admin:
@classmethod
def _after_create(cls, profile):
profile.name = 'Full name'
assert ProfileSet().admin.name == 'Full name'
ORMs
Both Django and SQLAlchemy are supported.
Django
Django models could be distilled using DjangoDistillery
that only
requires a __model__
class member:
from distillery import DjangoDistillery
from django.auth.models import User
class UserDistillery(DjangoDistillery):
__model__ = User
# ...
SQLAlchemy
SQLAlchemy distilleries require both the __model__
and
__session__
attributes.
from distillery import SQLAlchemyDistillery
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite://', echo=False)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()
Base = declarative_base()
class User(Base):
# ...
class UserDistillery(SQLAlchemyDistillery):
__model__ = User
__session__ = session
# ...