Skip to main content

Mixit

A lightweight and flexible mixin system for Python that allows dynamic composition of functionality through mixins.

Features

  • Dynamic mixin composition at runtime
  • Method export system with conflict detection
  • Optional initialization through mix_init
  • Clean mixin coordination through mixer access
  • Simple and intuitive API

Installation

pip install git+https://github.com/joshms123/mixit.git

Quick Start

from mixit import Mixer, Mixin, export

# Define a mixin
class LoggerMixin(Mixin):
    def __init__(self):
        super().__init__()
        self.logs = []
        self.prefix = ""
    
    def mix_init(self, prefix: str = "", **kwargs):
        self.prefix = prefix
    
    @export
    def log(self, message: str):
        self.logs.append(f"{self.prefix}{message}")
        return len(self.logs)

# Create a mixer and add the mixin
mixer = Mixer()
mixer.add_mixin("logger", LoggerMixin, prefix="[INFO] ")

# Use the exported method
mixer.log("Hello world!")  # Returns: 1
print(mixer.logger.logs)   # Prints: ['[INFO] Hello world!']

Auto-derived names (v0.7+)

You can omit the explicit name. The mixer derives one by converting the class name to snake_case:

mixer = Mixer()
mixer.add_mixin(LoggerMixin, prefix="[INFO] ")  # registered as "logger_mixin"
mixer.log("Hello!")
print(mixer.logger_mixin.logs)

For batches of plain mixins (no mix_init kwargs), add_mixins registers them in order:

mixer.add_mixins(CounterMixin, MathMixin, LoggerMixin)
mixer.add_mixin(DatabaseMixin, dsn="...")  # use add_mixin for kwarg cases
mixer.add_mixins(CacheMixin, MetricsMixin)

Core Concepts

Mixins

Mixins are classes that inherit from Mixin and provide functionality that can be mixed into a Mixer instance. Methods can be marked for export using the @export decorator, making them directly accessible from the mixer instance.

class CounterMixin(Mixin):
    def __init__(self):
        super().__init__()
        self.value = 0
    
    @export
    def increment(self):
        self.value += 1
        return self.value

Initialization

Mixins can define an optional mix_init method that will be called when the mixin is added to a mixer. Any additional keyword arguments passed to add_mixin will be forwarded to mix_init.

class MathMixin(Mixin):
    def __init__(self):
        super().__init__()
        self.precision = 2
    
    def mix_init(self, precision: int = 2, **kwargs):
        self.precision = precision
    
    @export
    def add(self, a: float, b: float) -> float:
        return round(a + b, self.precision)

mixer.add_mixin("math", MathMixin, precision=3)

Method Export

Methods marked with @export are made available directly on the mixer instance. If multiple mixins try to export methods with the same name, only the first one is exported and conflicts are tracked.

# Method available directly on mixer
result = mixer.add(1.23, 4.56)

# Access through mixin instance
result = mixer.math.add(1.23, 4.56)

# Check for conflicts
conflicts = mixer.get_conflicts()

Mixin Coordination

Mixins can coordinate with each other through the mixer instance. By default, the mixer is accessible via the mixer property, but you can customize this name to avoid conflicts or improve readability:

# Using default 'mixer' attribute
class WorkerMixin(Mixin):
    @export
    def do_work(self):
        self.mixer.log("Starting work")  # Use another mixin's exported method
        result = self.perform_work()
        self.mixer.logger.log("Done!")   # Access mixin instance directly
        return result

# Using custom mixer attribute name
class DatabaseMixin(Mixin, mixer_attr='app'):
    @export
    def query(self, sql: str):
        # Access mixer through custom name
        logger = self.app.logger
        logger.log(f"Executing: {sql}")
        return self.execute_query(sql)

API Reference

Mixer

  • add_mixin(mixin_class: Type[Mixin], **kwargs) -> Mixin — auto-derives the registration name from the class name.
  • add_mixin(name: str, mixin_class: Type[Mixin], **kwargs) -> Mixin — explicit name.
  • add_mixin_instance(instance: Mixin) -> Mixin — auto-derives the name; for pre-built instances.
  • add_mixin_instance(name: str, instance: Mixin) -> Mixin — explicit name.
  • add_mixins(*mixin_classes: Type[Mixin]) -> List[Mixin] — bulk-register plain mixins in order, no kwargs.
  • remove_mixin(name: str) -> None
  • get_mixin(name: str) -> Mixin
  • get_mixins() -> Dict[str, Mixin]
  • get_conflicts() -> Dict[str, List[str]]
  • call_all_mixins(func_name: str, *args, **kwargs) -> Dict[str, Any]

Helpers

  • derive_mixin_name(cls: Type[Mixin]) -> str — exported helper that converts a class name to its snake_case registration key.

Mixin

  • mix_init(**kwargs) -> None - Optional initialization method
  • cleanup() -> None - Clean up resources when removed
  • mixer property - Default access to mixer instance
  • mixer_attr class parameter - Customize mixer attribute name (e.g. class MyMixin(Mixin, mixer_attr='app'))

Decorators

  • @export - Mark a method for export to the mixer namespace

License

MIT License

Metadata

Release files for mixit 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mixit 0.7.0
File Size Uploaded
mixit-0.7.0.tar.gz 10.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mixit 0.7.0
File Interpreter ABI Platform
mixit-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.9 kB

Release files / mixit-0.7.0.tar.gz

Download URL mixit-0.7.0.tar.gz
Size 10.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e389ba3bd81a9565e7ed57eaf255a0e4881a177122d28f3326dad67e8ac6e237
BLAKE2b-256 checksum
How to use checksums
152490a0547efe05b6d4da542c7dcd605d8b112b9286759eb0b6b1db20b64277
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 26, 2026.

Transparency log

Release files / mixit-0.7.0-py3-none-any.whl

Download URL mixit-0.7.0-py3-none-any.whl
Size 9.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b8352c1d2dc83645193685c5b02652432413ab0ce05bb7e991a2ac90fae6415
BLAKE2b-256 checksum
How to use checksums
011b250fc376f5ccab4a98489ee32f9c2417676a854f5aebcd040d42b7e0ad04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page