ForkMixer -- A fork of Mixer, a fixtures replacement. Supported Django ORM, SqlAlchemy ORM, Mongoengine ODM and custom python objects.
Project description
ForkMixer
ForkMixer is a fork of the original Mixer project, a helper to generate instances of Django or SQLAlchemy models. It’s useful for testing and fixture replacement. Fast and convenient test-data generation.
ForkMixer supports:
Pony;
Custom schemes;
Repository: https://github.com/paulchubatyy/forkmixer
Original Mixer Documentation: https://mixer.readthedocs.org/
Requirements
Python 3.7+
Django (5.1+) for Django ORM support;
Flask-SQLALchemy for SQLAlchemy ORM support and integration as Flask application;
Faker >= 0.7.3
Mongoengine for Mongoengine ODM support;
SQLAlchemy for SQLAlchemy ORM support;
Peewee ORM support;
Installation
ForkMixer should be installed using pip:
pip install forkmixer
Or using uv (recommended):
uv add forkmixer
Development
For development, it’s recommended to use uv for fast dependency management.
Setup development environment:
# Install uv if you haven't already curl -LsSf https://astral.sh/uv/install.sh | sh # Clone the repository git clone https://github.com/paulchubatyy/forkmixer cd forkmixer # Install dependencies (creates .venv and installs all dependencies) uv sync --all-extras # Or use make make install
Run tests:
uv run pytest tests/ # Or use make make t
Run specific tests:
uv run pytest tests/test_main.py
Usage
By default Mixer tries to generate fake (human-friendly) data.If you want to randomize the generated values initialize the Mixerby manual: Mixer(fake=False)By default Mixer saves the generated objects in a database. If you want to disablethis, initialize the Mixer by manual like Mixer(commit=False)
Django workflow
Quick example:
from forkmixer.backend.django import mixer
from customapp.models import User, UserMessage
# Generate a random user
user = mixer.blend(User)
# Generate an UserMessage
message = mixer.blend(UserMessage, user=user)
# Generate an UserMessage and an User. Set username for generated user to 'testname'.
message = mixer.blend(UserMessage, user__username='testname')
# Generate SomeModel from SomeApp and select FK or M2M values from db
some = mixer.blend('someapp.somemodel', somerelation=mixer.SELECT)
# Generate SomeModel from SomeApp and force a value of money field from default to random
some = mixer.blend('someapp.somemodel', money=mixer.RANDOM)
# Generate SomeModel from SomeApp and skip the generation of money field
some = mixer.blend('someapp.somemodel', money=mixer.SKIP)
# Generate 5 SomeModel's instances and take company field's values from custom generator
some_models = mixer.cycle(5).blend('somemodel', company=(name for name in company_names))
Flask, Flask-SQLAlchemy
Quick example:
from forkmixer.backend.flask import mixer
from models import User, UserMessage
mixer.init_app(self.app)
# Generate a random user
user = mixer.blend(User)
# Generate an userMessage
message = mixer.blend(UserMessage, user=user)
# Generate an UserMessage and an User. Set username for generated user to 'testname'.
message = mixer.blend(UserMessage, user__username='testname')
# Generate SomeModel and select FK or M2M values from db
some = mixer.blend('project.models.SomeModel', somerelation=mixer.SELECT)
# Generate SomeModel from SomeApp and force a value of money field from default to random
some = mixer.blend('project.models.SomeModel', money=mixer.RANDOM)
# Generate SomeModel from SomeApp and skip the generation of money field
some = mixer.blend('project.models.SomeModel', money=mixer.SKIP)
# Generate 5 SomeModel's instances and take company field's values from custom generator
some_models = mixer.cycle(5).blend('project.models.SomeModel', company=(company for company in companies))
Support for Flask-SQLAlchemy models that have __init__ arguments
For support this scheme, just create your own mixer class, like this:
from forkmixer.backend.sqlalchemy import Mixer
class MyOwnMixer(Mixer):
def populate_target(self, values):
target = self.__scheme(**values)
return target
mixer = MyOwnMixer()
SQLAlchemy workflow
Example of initialization:
from forkmixer.backend.sqlalchemy import Mixer
ENGINE = create_engine('sqlite:///:memory:')
BASE = declarative_base()
SESSION = sessionmaker(bind=ENGINE)
mixer = Mixer(session=SESSION(), commit=True)
role = mixer.blend('package.models.Role')
Also, see Flask, Flask-SQLAlchemy.
Mongoengine workflow
Example usage:
from forkmixer.backend.mongoengine import mixer
class User(Document):
created_at = DateTimeField(default=datetime.datetime.now)
email = EmailField(required=True)
first_name = StringField(max_length=50)
last_name = StringField(max_length=50)
username = StringField(max_length=50)
class Post(Document):
title = StringField(max_length=120, required=True)
author = ReferenceField(User)
tags = ListField(StringField(max_length=30))
post = mixer.blend(Post, author__username='foo')
Marshmallow workflow
Example usage:
from forkmixer.backend.marshmallow import mixer
import marshmallow as ma
class User(ma.Schema):
created_at = ma.fields.DateTime(required=True)
email = ma.fields.Email(required=True)
first_name = ma.fields.String(required=True)
last_name = ma.fields.String(required=True)
username = ma.fields.String(required=True)
class Post(ma.Schema):
title = ma.fields.String(required=True)
author = ma.fields.Nested(User, required=True)
post = mixer.blend(Post, author__username='foo')
Common usage
Quick example:
from forkmixer.main import mixer
class Test:
one = int
two = int
name = str
class Scheme:
name = str
money = int
male = bool
prop = Test
scheme = mixer.blend(Scheme, prop__one=1)
DB commits
By default ‘django’, ‘flask’, ‘mongoengine’ backends tries to save objects in database. For preventing this behavior init mixer manually:
from forkmixer.backend.django import Mixer
mixer = Mixer(commit=False)
Or you can temporary switch context use the mixer as context manager:
from forkmixer.backend.django import mixer
# Will be save to db
user1 = mixer.blend('auth.user')
# Will not be save to db
with mixer.ctx(commit=False):
user2 = mixer.blend('auth.user')
Custom fields
The mixer allows you to define generators for fields by manually. Quick example:
from forkmixer.main import mixer
class Test:
id = int
name = str
mixer.register(Test,
name=lambda: 'John',
id=lambda: str(mixer.faker.small_positive_integer())
)
test = mixer.blend(Test)
test.name == 'John'
isinstance(test.id, str)
# You could pinned just a value to field
mixer.register(Test, name='Just John')
test = mixer.blend(Test)
test.name == 'Just John'
Also, you can make your own factory for field types:
from forkmixer.backend.django import Mixer, GenFactory
def get_func(*args, **kwargs):
return "Always same"
class MyFactory(GenFactory):
generators = {
models.CharField: get_func
}
mixer = Mixer(factory=MyFactory)
Middlewares
You can add middleware layers to process generation:
from forkmixer.backend.django import mixer
# Register middleware to model
@mixer.middleware('auth.user')
def encrypt_password(user):
user.set_password('test')
return user
You can add several middlewares. Each middleware should get one argument (generated value) and return them.
It’s also possible to unregister a middleware:
mixer.unregister_middleware(encrypt_password)
Locales
By default mixer uses ‘en’ locale. You could switch mixer default locale by creating your own mixer:
from forkmixer.backend.django import Mixer
mixer = Mixer(locale='it')
mixer.faker.name() ## u'Acchisio Conte'
At any time you could switch mixer current locale:
mixer.faker.locale = 'cz'
mixer.faker.name() ## u'Miloslava Urbanov\xe1 CSc.'
mixer.faker.locale = 'en'
mixer.faker.name() ## u'John Black'
# Use the mixer context manager
mixer.faker.phone() ## u'1-438-238-1116'
with mixer.ctx(locale='fr'):
mixer.faker.phone() ## u'08 64 92 11 79'
mixer.faker.phone() ## u'1-438-238-1116'
Bug tracker
If you have any suggestions, bug reports or annoyances please report them to the issue tracker at https://github.com/klen/mixer/issues
Contributing
Development of mixer happens at Github: https://github.com/klen/mixer
Contributors
Antoine Bertin (https://github.com/Diaoul)
Benjamin Port (https://github.com/bport)
Dmitriy Moseev (https://github.com/DmitriyMoseev)
Eelke Hermens (https://github.com/eelkeh)
Esteban J. G. Gabancho (https://github.com/egabancho)
Felix Dreissig (https://github.com/F30)
Illia Volochii (https://github.com/illia-v)
Jannis (https://github.com/jnns)
Kirill Pavlov (https://github.com/pavlov99)
Kwok-kuen Cheung (https://github.com/cheungpat)
Mahdi Yusuf (https://github.com/myusuf3)
Marek Baczyński (https://github.com/imbaczek)
Marigold (https://github.com/Marigold)
Matt Caldwell (https://github.com/mattcaldwell)
Mikhail Porokhovnichenko (https://github.com/marazmiki)
Skylar Saveland (https://github.com/skyl)
Suriya Subramanian (https://github.com/suriya)
Gram (https://github.com/orsinium)
Joshua (https://github.com/jomasti)
Lucas Rangel Cezimbra (https://github.com/lucasrcezimbra)
avi-pomicell (https://github.com/avi-pomicell)
Jochen Brissier (https://github.com/jbrissier)
License
Licensed under a BSD license.
Project details
Release history Release notifications | RSS feed
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 forkmixer-0.1.0.tar.gz.
File metadata
- Download URL: forkmixer-0.1.0.tar.gz
- Upload date:
- Size: 51.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccd760080f4ab36367574d6b1d6c89575502051c4e477aa4fc3a65e9accca8db
|
|
| MD5 |
370253060080e10ac16b65188cf06d3e
|
|
| BLAKE2b-256 |
72a05d41b6d8e9cf4278dd302758c774168558d7caaccc80f16dd94112486865
|
Provenance
The following attestation bundles were made for forkmixer-0.1.0.tar.gz:
Publisher:
release.yml on paulchubatyy/forkmixer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forkmixer-0.1.0.tar.gz -
Subject digest:
ccd760080f4ab36367574d6b1d6c89575502051c4e477aa4fc3a65e9accca8db - Sigstore transparency entry: 584105117
- Sigstore integration time:
-
Permalink:
paulchubatyy/forkmixer@83de02749569163d5be8e6f2d574742e139ddf82 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/paulchubatyy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83de02749569163d5be8e6f2d574742e139ddf82 -
Trigger Event:
workflow_run
-
Statement type:
File details
Details for the file forkmixer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: forkmixer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
139858e6ef24814c930dcedb2a6d441a4b7d191457d408281755228f6e2c4dd0
|
|
| MD5 |
8ca54cb0072dbf4daa17faf4d8169187
|
|
| BLAKE2b-256 |
179925a53a321afde59a540761932ccfd4d6356ebceab21478733af8537fabb6
|
Provenance
The following attestation bundles were made for forkmixer-0.1.0-py3-none-any.whl:
Publisher:
release.yml on paulchubatyy/forkmixer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forkmixer-0.1.0-py3-none-any.whl -
Subject digest:
139858e6ef24814c930dcedb2a6d441a4b7d191457d408281755228f6e2c4dd0 - Sigstore transparency entry: 584105118
- Sigstore integration time:
-
Permalink:
paulchubatyy/forkmixer@83de02749569163d5be8e6f2d574742e139ddf82 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/paulchubatyy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@83de02749569163d5be8e6f2d574742e139ddf82 -
Trigger Event:
workflow_run
-
Statement type: