Skip to main content

ForkMixer -- A fork of Mixer, a fixtures replacement. Supported Django ORM, SqlAlchemy ORM, Mongoengine ODM and custom python objects.

Project description

https://raw.github.com/paulchubatyy/forkmixer/main/docs/_static/logo.png

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:

License

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 Mixer
by manual: Mixer(fake=False)
By default Mixer saves the generated objects in a database. If you want to disable
this, 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

License

Licensed under a BSD license.

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

forkmixer-2.0.0.tar.gz (51.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

forkmixer-2.0.0-py3-none-any.whl (39.5 kB view details)

Uploaded Python 3

File details

Details for the file forkmixer-2.0.0.tar.gz.

File metadata

  • Download URL: forkmixer-2.0.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

Hashes for forkmixer-2.0.0.tar.gz
Algorithm Hash digest
SHA256 b5e6d422f7a81dd9f6709938d20955c5eea2b5873581ec1540010893c6a327b7
MD5 08ef51eafa1ef271350b74bd0d979d8d
BLAKE2b-256 33603d589f6b9df5171aa2c7ff0435d61c7fd0185b451a83c070d1dec09af01d

See more details on using hashes here.

Provenance

The following attestation bundles were made for forkmixer-2.0.0.tar.gz:

Publisher: release.yml on paulchubatyy/forkmixer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file forkmixer-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: forkmixer-2.0.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

Hashes for forkmixer-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f731cce202f44c3718b522ac2725cfa50e6b87b802783a69fa7b310b8ac78e7a
MD5 b4f4c41e3927f5f0b964a6378328bb7d
BLAKE2b-256 397aabdfca7e2d2c80e10e02bd33adc0fe4fc2e3f9fb6b9f0f57f43128807c4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for forkmixer-2.0.0-py3-none-any.whl:

Publisher: release.yml on paulchubatyy/forkmixer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page