mixinforge#
A collection of Python mixins, metaclasses, utility functions, and CLI tools for building robust, configurable classes.
What Is It?#
mixinforge is a lightweight library providing four key areas of
functionality:
Mixins & Metaclasses — Reusable components for parameter management, cache control, initialization contracts, thread safety, singleton pattern, and pickle prevention
Utility Functions — Tools for JSON serialization, nested collection processing, and dictionary operations
Context Managers — Helpers for temporary state/behavior changes
CLI Tools — Command-line utilities for project analysis and maintenance
Quick Example#
Here’s an example showing thread safety enforcement:
from mixinforge import SingleThreadEnforcerMixin
class DatabaseConnection(SingleThreadEnforcerMixin):
def __init__(self, connection_string: str):
super().__init__()
self.connection_string = connection_string
self.connection = self._connect()
def _connect(self):
return f"Connected to {self.connection_string}"
def query(self, sql: str):
self._restrict_to_single_thread() # Enforces thread safety
return f"Executing: {sql}"
# Works fine on the owner thread
db = DatabaseConnection("localhost:5432")
result = db.query("SELECT * FROM users")
# Calling from another thread raises RuntimeError
import threading
threading.Thread(
target=lambda: db.query("SELECT *")
).start() # Raises RuntimeError!
Installation#
The source code is hosted on GitHub.
Binary installers for the latest released version are available at the Python Package Index (PyPI).
Using uv:
uv add mixinforge
Using pip:
pip install mixinforge
Requirements#
Python >= 3.11
Runtime dependencies:
tabulate
For development:
pytest (optional)
API Overview#
Mixins & Metaclasses#
Component |
Description |
|---|---|
|
Base class for parameterizable objects with JSON serialization |
|
Base class for immutable objects with customizable identity keys |
|
Immutable objects with params-based identity |
|
Auto discovery and invalidation of |
|
Prevents pickling/unpickling of objects |
|
Strict initialization control with lifecycle hooks |
|
Enforces single-threaded execution |
|
Ensures each subclass has exactly one instance |
Utility Functions#
Function |
Description |
|---|---|
|
Serialize object to JSON string |
|
Deserialize JSON string to object |
|
Update params in JSON |
|
Extract params from JSON |
|
Sort dictionary keys alphabetically |
|
Find atomics in nested collections |
|
Find instances of type(s) in composite |
|
Transform instances of type(s) in composite |
|
Detect if running in Jupyter/IPython notebook |
|
Install a Python package from PyPI at runtime |
|
Check if a Python package is currently installed |
|
Remove a Python package from the environment |
Context Managers#
Component |
Description |
|---|---|
|
Captures stdout, stderr, and logging output while preserving display |
|
Suppresses stdout and stderr output by redirecting to /dev/null |
CLI Tools#
Command |
Description |
|---|---|
|
Analyze project metrics and generate reports |
|
Remove Python cache files and directories |
|
Remove distribution artifacts (dist/ directory) |
Mixins & Metaclasses#
ParameterizableMixin#
A base class for objects with configuration parameters, which enables standardized parameter access and JSON serialization.
Key features:
get_params()— Returns all parameters as a dictionaryget_default_params()— Class method to get default parameter values from__init__signatureget_essential_params()— Returns only essential configuration parametersget_auxiliary_params()— Returns auxiliary parameters (logging, verbosity, etc.)essential_param_names— Property to specify which parameters are core to the object’s identityget_jsparams()— Get parameters as JSON stringget_essential_jsparams()/get_auxiliary_jsparams()— Get filtered parameters as JSONWorks seamlessly with
dumpjs()andloadjs()for full object serialization
ImmutableMixin#
A base class for creating immutable objects with customizable identity
keys. Provides immutability guarantees through the GuardedInitMeta
metaclass and enables value-based hashing and equality.
Key features:
identity_key()— Abstract method that subclasses override to define what makes an object unique__hash__/__eq__— Implements identity-based hashing and equality using cached identity keysGuardedInitMeta— Uses guarded initialization to prevent hash computation on uninitialized objects__copy__/__deepcopy__— Returns self since immutable objects don’t need copyingFlexible design allows any hashable value as identity key (strings, tuples, JSON, etc.)
ImmutableParameterizableMixin#
A mixin combining ParameterizableMixin and ImmutableMixin for
creating immutable objects defined by their parameters. Uses
JSON-serialized parameters as the identity key.
Key features:
Inherits from both
ParameterizableMixinandImmutableMixinAutomatically uses JSON-serialized parameters for hashing and equality
Enables parameter-based identity for dictionary keys and set membership
Combines parameter management with immutability guarantees
CacheablePropertiesMixin#
A mixin for managing functools.cached_property attributes with
automatic discovery and invalidation across the class hierarchy.
Key methods:
_get_all_cached_properties_status()— Check which cached properties are currently cached (returns dict)_get_cached_property_status(name)— Check if a specific property is cached_get_all_cached_properties()— Retrieve all currently cached values_get_cached_property(name)— Get a specific cached value_set_cached_properties(**kwargs)— Manually set cached values (useful for testing/restoration)_invalidate_cache()— Clear all cached properties across the entire class hierarchy_all_cached_properties_names— Property returning all cached property names
Automatically discovers cached properties from all classes in the MRO, including decorator-wrapped properties, making it reliable for complex inheritance structures.
NotPicklableMixin#
A mixin that explicitly prevents objects from being pickled or unpickled. Useful for objects that hold non-serializable resources like database connections, file handles, or network sockets.
Raises TypeError on any pickling attempt, providing clear error
messages about why serialization is blocked.
GuardedInitMeta#
A metaclass that enforces strict initialization control and provides
lifecycle hooks. It ensures that _init_finished is False during
__init__ and automatically sets it to True afterward, enabling
reliable initialization state checks.
Key features:
Automatic
_init_finishedflag management (False during init, True after)__post_init__()hook — Called automatically after__init__completes__post_setstate__()hook — Called after unpickling when restoring object stateAutomatic
__setstate__wrapping for proper unpickling behaviorValidates
_init_finished=Falsein pickled state to prevent corruptionCompatible with
ABCMetafor abstract base classesPrevents use with dataclasses (incompatible)
Validates single GuardedInitMeta base in multiple inheritance
Enforces initialization contracts and provides clear error messages when contracts are violated, making initialization bugs easier to catch.
SingleThreadEnforcerMixin#
A mixin to enforce single-threaded execution with multi-process support. Ensures methods are called only from the thread that first instantiated the object, while automatically supporting process-based parallelism through fork detection.
Key method:
_restrict_to_single_thread()— Call this at the start of methods that need thread enforcement
Automatically detects process forks and resets ownership, making it safe for multiprocessing workflows.
SingletonMixin#
A mixin for implementing the singleton pattern. Ensures each subclass maintains exactly one instance that is returned on every instantiation attempt.
Useful for classes that should have only a single instance throughout the application lifetime, such as configuration managers or resource coordinators. Each subclass gets its own singleton instance.
Utility Functions#
JSON Serialization#
mixinforge provides a complete JSON serialization system for Python objects:
dumpjs(obj) — Serialize any Python object (including classes, instances, nested structures) to a JSON string
loadjs(js) — Deserialize a JSON string back to its original Python object
update_jsparams(js, **kwargs) — Modify parameters in serialized JSON without full deserialization
access_jsparams(js, *names) — Extract specific parameters from serialized JSON
This system handles complex objects including class hierarchies,
__slots__, nested collections, and maintains object identity; it
seamlessly integrates with ParameterizableMixin.
Nested Collection Processing#
Tools for working with nested data structures:
flatten_nested_collection(obj) — Recursively find all atomic-type objects (primitives, strings, etc.) within nested collections (returns iterator)
find_instances_inside_composite_object(obj, classinfo, deep_search=True) — Recursively find all instances of the specified type(s) within composite structures (returns iterator). Accepts a single type or tuple of types, like
isinstance(). Setdeep_search=Falseto stop traversal at matched instances.transform_instances_inside_composite_object(obj, classinfo, transform_fn) — Transform all instances of the specified type(s) within composite structures, reconstructing the object graph with transformed instances (returns transformed object). Accepts a single type or tuple of types, like
isinstance().
These functions handle arbitrary nesting depths and complex object graphs including cyclic references. Each object is visited only once (deduplication by identity), making them safe for graphs with cycles or shared references. Useful for introspection, validation, and structural transformations.
Dictionary Utilities#
sort_dict_by_keys(d) — Returns a new dictionary with keys sorted alphabetically, useful for consistent serialization and comparison
Package Management#
Tools for runtime package installation, checking, and removal:
install_package(package_name, upgrade=False, version=None, use_uv=True, import_name=None, verify_import=True) — Install a Python package from PyPI into the current environment. Supports version pinning, upgrade mode, and handles packages where PyPI name differs from import name (e.g., “Pillow” vs “PIL”). Uses
uvby default for speed, falling back topipwhen needed.is_package_installed(package_name) — Check if a Python package is currently installed in the environment. Returns
Trueif installed,Falseotherwise. Handles package name variations (hyphens, underscores, capitalization) through canonicalization for reliable detection.uninstall_package(package_name, use_uv=True, import_name=None, verify_uninstall=True) — Remove a Python package from the current environment. Protects critical package managers (pip, uv) from accidental removal. Verifies complete removal by default.
These functions automatically bootstrap missing package managers and invalidate Python’s import caches after operations to ensure the import system reflects filesystem changes.
Context Managers#
OutputCapturer#
A context manager that simultaneously captures and displays stdout, stderr, and logging output. Uses a “tee” strategy where output is duplicated: sent to both the original destination (for normal display) and to an internal buffer (for storage).
Key features:
Captures
sys.stdout,sys.stderr, andloggingoutputPreserves normal output behavior (output is still visible in console)
get_output()— Retrieve all captured output as a single stringIdeal for testing CLI tools or logging execution traces without suppressing output
OutputSuppressor#
A context manager that suppresses stdout and stderr by redirecting them to
the system null device (os.devnull). Useful for silencing noisy operations
in background processes or tests.
Key features:
Suppresses both
sys.stdoutandsys.stderrUses
contextlib.ExitStackfor reliable cleanup even on exceptionsAutomatically restores original streams when exiting the context
Ideal for background workers, batch processing, or tests that need silence
CLI Tools#
mixinforge provides two command-line tools for project analysis and maintenance.
mf-get-stats#
Analyzes Python projects and generates comprehensive code metrics.
Usage:
# Analyze current directory
mf-get-stats
# Analyze specific directory
mf-get-stats /path/to/project
# Specify custom output filename
mf-get-stats --output my_metrics.md
Features:
Generates markdown report with detailed statistics:
Lines of Code (LOC) and Source Lines of Code (SLOC)
Class and function counts
File counts
Breakdown by main code vs. unit tests
Displays formatted summary table in console
Auto-updates
README.mdand Sphinx documentation if special markers are present:<!-- MIXINFORGE_STATS_START -->and<!-- MIXINFORGE_STATS_END -->for markdown.. MIXINFORGE_STATS_STARTand.. MIXINFORGE_STATS_ENDfor reStructuredText
Returns list of updated files for CI/CD integration
This tool is ideal for tracking project growth, maintaining documentation, and integrating metrics into automated workflows.
mf-clear-cache#
Removes all Python cache files and directories from a project.
Usage:
# Clean current directory
mf-clear-cache
# Clean specific directory
mf-clear-cache /path/to/project
# Specify custom report filename
mf-clear-cache --output cleanup_report.md
What it removes:
__pycache__directories.pycand.pyocompiled bytecode filesCache directories from:
pytest (
.pytest_cache)mypy (
.mypy_cache)ruff (
.ruff_cache)hypothesis (
.hypothesis)tox (
.tox)coverage (
.coverage,htmlcov)
Generates a detailed markdown report categorizing removed items. Useful for cleaning build artifacts before commits or releases.
mf-clear-dist#
Removes distribution artifacts (the dist/ directory) created by build tools.
Usage:
# Clean current directory
mf-clear-dist
# Clean specific directory
mf-clear-dist /path/to/project
What it removes:
dist/directory containing:Source distributions (
.tar.gz)Wheel files (
.whl)Any other build artifacts
This tool is useful for cleaning up after uv build, python -m build,
or similar build commands. It reports the number of files removed and
total size freed.
Full API Documentation#
API Documentation:
Project Statistics#
Metric |
Main code |
Unit Tests |
Total |
|---|---|---|---|
Lines Of Code (LOC) |
4941 |
12286 |
17227 |
Source Lines Of Code (SLOC) |
2222 |
7141 |
9363 |
Classes |
20 |
211 |
231 |
Functions / Methods |
170 |
1030 |
1200 |
Files |
27 |
85 |
112 |
Development#
Run tests:
With pytest:
pytestOr via Python:
python -m pytest
Supported Python versions: 3.11+
Contributing#
Contributions are welcome! Please see the contributing guide for details on:
Setting up the development environment
Running tests
Code style guidelines
Commit message conventions
Submitting pull requests
Additional guidelines:
License#
mixinforge is licensed under the MIT License.
See the LICENSE file for details.
Resources#
GitHub: pythagoras-dev/mixinforge
Documentation: https://mixinforge.readthedocs.io/
Contact#
Maintainer: Vlad (Volodymyr) Pavlov
Email: vlpavlov@ieee.org