mixinforge package#
Tools for working with mixinforge classes.
This package provides reusable mixins, context managers, and utility functions that help you build well-structured Python classes. It offers tools for parameter management, cache management, initialization control, thread safety, pickle prevention, JSON serialization, nested collection processing, dictionary utilities, output capturing, and runtime package management.
Public API: - ParameterizableMixin: Base class for parameterizable objects with JSON serialization. - ImmutableMixin: Base class for immutable objects with customizable identity keys. - ImmutableParameterizableMixin: Immutable objects with params-based identity. - CacheablePropertiesMixin: Automatic discovery and invalidation of cached_property attributes. - NotPicklableMixin: Mixin that prevents pickling/unpickling. - SingleThreadEnforcerMixin: Enforces single-threaded execution with multi-process support. - GuardedInitMeta: Metaclass for strict initialization control and lifecycle hooks. - SingletonMixin: Ensures each subclass maintains exactly one instance. - OutputCapturer: Context manager that captures stdout, stderr, and logging output. - OutputSuppressor: Context manager that suppresses stdout and stderr output. - sort_dict_by_keys: Sort a dictionary by its keys alphabetically. - dumpjs: Serialize an object (or parameters) into a JSON string. - loadjs: Deserialize a JSON string produced by dumpjs back into a Python object. - update_jsparams: Update parameters in a JSON-serialized string. - access_jsparams: Access parameters in a JSON-serialized string. - JsonSerializedObject: NewType alias for JSON strings produced by dumpjs. - flatten_nested_collection: Find all atomic objects in nested collections (handles cycles). - find_instances_inside_composite_object: Find instances of type(s) in composite structures (handles cycles). Supports deep or shallow search. - transform_instances_inside_composite_object: Transform instances of type(s) in composite structures. Supports deep (handles cycles) or shallow search. - is_executed_in_notebook: Detect if running in Jupyter/IPython notebook. - reset_notebook_detection: Clear cached notebook detection result. - is_valid_env_name: Validate environment variable names using a strict, portable rule. - install_package: Install a Python package from PyPI into the current environment. - is_package_installed: Check if a Python package is currently installed. - uninstall_package: Remove a Python package from the current environment.
- class mixinforge.CacheablePropertiesMixin[source]#
Bases:
objectMixin class for automatic management of cached properties.
Provides methods to discover all functools.cached_property attributes in the class hierarchy and to inspect, set, and invalidate their cached values. This enables efficient cache management without manual tracking of individual cached properties.
Note
This class is not thread-safe and should not be used with dynamically modified classes.
Subclasses using __slots__ MUST include ‘__dict__’ to support functools.cached_property, as enforced by _ensure_cache_storage_supported().
- class mixinforge.GuardedInitMeta(name, bases, namespace, /, **kwargs)[source]#
Bases:
ABCMetaMetaclass for strict initialization control and lifecycle hooks.
Enforces a contract where _init_finished is False during initialization and only becomes True after all initialization code completes. This ensures that properties and methods can reliably check initialization state.
The metaclass automatically: - Injects _init_finished = False before __init__ runs - Sets _init_finished = True after __init__ completes - Wraps __setstate__ to maintain the same contract during unpickling - Invokes __post_init__ and __post_setstate__ hooks when defined
- Contract:
The metaclass sets _init_finished = False before __init__ runs.
The metaclass sets _init_finished = True after __init__ returns (but before __post_init__, if defined).
Subclasses must NOT set _init_finished = True in __init__.
__setstate__ is wrapped to ensure _init_finished becomes True after full state restoration (but before __post_setstate__, if defined).
Note
If a class uses __slots__ without __dict__, it must include ‘_init_finished’ in its __slots__ declaration.
- __init__(name, bases, dct)[source]#
Initialize the class and inject lifecycle enforcement.
Wraps __setstate__ to ensure proper initialization state after unpickling and validates that the class is compatible with the GuardedInitMeta contract.
- Parameters:
name – The class name.
bases – Base classes.
dct – Class dictionary.
- Raises:
TypeError – If class is a dataclass, has multiple GuardedInitMeta bases, or uses __slots__ without declaring _init_finished.
- class mixinforge.ImmutableMixin(*args: Any, **kwargs: Any)[source]#
Bases:
objectBase mixin for objects that never change after initialization.
Provides value-based identity semantics with optimized hashing and equality comparisons. Instead of using object identity (id), instances are compared based on a customizable identity key that represents their immutable state. This enables efficient use in sets and dictionaries while supporting value equality semantics.
The mixin caches the hash value for O(1) lookups and uses hash-based short-circuiting in equality checks to avoid expensive comparisons. This is particularly beneficial for complex objects with many fields.
Note that this mixin does not enforce immutability; subclasses are responsible for ensuring their instances truly never change after initialization.
Subclasses must override get_identity_key() to return a hashable value that uniquely defines the object’s identity based on its immutable state.
- get_identity_key()[source]#
Return a hashable value defining this object’s identity.
Subclasses must override this method to specify what makes an instance unique. The returned value is used for hashing and equality comparisons, enabling value-based semantics. Common implementations return a tuple of the object’s immutable fields.
The returned value must be hashable and must remain constant for the object’s lifetime to maintain hash consistency.
- Return type:
- Returns:
A hashable value uniquely identifying this object based on its immutable state.
- Raises:
NotImplementedError – If not overridden by subclass.
- property identity_key: Any#
Cached identity key for consistent hashing and equality checks.
Caches the result of get_identity_key() to ensure the same value is used throughout the object’s lifetime. This guarantees hash stability and enables efficient repeated comparisons without recomputing the identity key.
- Returns:
The cached identity key.
- Raises:
RuntimeError – If called before initialization completes.
- class mixinforge.ImmutableParameterizableMixin(*args: Any, **kwargs: Any)[source]#
Bases:
ParameterizableMixin,ImmutableMixinImmutable objects with parameter-based identity and hashing.
Combines ParameterizableMixin’s parameter management with ImmutableMixin’s immutability support. Objects use JSON-serialized essential parameters as their identity key, enabling parameter-based equality comparisons and hashing.
This design ensures that two instances with identical essential parameters are considered equal and have the same hash, regardless of when or where they were created. This makes it possible to use parameterizable objects as dictionary keys and set members.
Note that the mixin does not enforce immutability; subclasses are responsible for ensuring their instances truly never change after initialization.
- get_identity_key()[source]#
Return JSON-serialized essential parameters as an identity key.
Uses JSON-serialized essential parameters to ensure consistent, deterministic identity across instances. This approach guarantees that objects with identical essential parameters produce the same hash and compare as equal, enabling reliable use in hash-based collections.
- Return type:
- Returns:
JSON string representation of essential parameters used for hashing and equality comparisons.
- property essential_jsparams: JsonSerializedObject#
Cached JSON-serialized essential parameters for identity operations.
Provides a cached JSON representation of the object’s core parameters, used as the basis for hashing and equality comparisons. Caching ensures that serialization happens only once, improving performance for repeated operations.
- Returns:
JSON string representation of the object’s essential parameters.
- class mixinforge.NotPicklableMixin[source]#
Bases:
objectA mixin class that prevents objects from being pickled or unpickled.
This class provides a mechanism to explicitly prevent instances from being serialized using Python’s pickle module. Classes that inherit from this mixin will raise TypeError exceptions when pickle attempts to serialize or deserialize them.
This is useful for objects that contain non-serializable resources or should not be persisted for security or architectural reasons.
- class mixinforge.OutputCapturer[source]#
Bases:
objectContext manager that captures stdout, stderr, and logging output.
Uses a dual-stream “tee” approach: output is sent to both the original streams (preserving normal display) and to an internal buffer (enabling capture). This ensures users see output in real-time while also storing it for later retrieval via get_output().
Example
>>> with OutputCapturer() as capturer: ... print("Hello") # Prints normally AND is captured ... logging.info("Test") # Logged normally AND is captured >>> output = capturer.get_output() >>> assert "Hello" in output >>> assert "Test" in output
- class mixinforge.OutputSuppressor[source]#
Bases:
objectContext manager to suppress stdout and stderr.
Example
- with OutputSuppressor():
noisy_function() # Output is discarded
Notes
Internally uses contextlib.ExitStack to manage all redirections and to ensure restoration even when exceptions are raised.
- class mixinforge.ParameterizableMixin[source]#
Bases:
objectBase class for parameterizable classes.
Classes deriving from this base expose a stable set of configuration parameters that define their behavior and identity. Subclasses implement get_params to return these parameters, which can then be serialized to and from a portable JSON representation.
Note
This class is intended to be subclassed. The default implementation of get_params returns an empty mapping.
- get_params()[source]#
Return this instance’s configuration parameters.
Parameters define the object’s configuration but not its internal contents or data. They are typically passed to __init__ at creation time.
Note
Subclasses should override this method to return their specific parameters. The default implementation returns an empty dictionary.
- clone(**kwargs)[source]#
Create a new instance with the same parameters, optionally overriding some.
- Parameters:
**kwargs (
Any) – Parameter overrides to apply to the clone.- Return type:
Self- Returns:
A new instance with parameters from this instance, updated with kwargs.
- classmethod get_default_params()[source]#
Get the default parameters of the class as a dictionary.
Default values are taken from keyword parameters of __init__ and returned as a key-sorted dictionary. Subclasses may override if default computation requires custom logic.
- property essential_param_names: set[str]#
Names of parameters that define the object’s core identity and behavior.
Essential parameters are those that fundamentally define an object’s behavior or identity - for example, the maximum number of trees in a random forest or the maximum depth of a decision tree.
These parameters are oftentimes immutable throughout the object’s lifetime. They are guaranteed to be preserved during the copying/deepcopying, serialization/deserialization processes, and similar operations.
Note
Subclasses should override this property to specify which parameters are essential. The default implementation considers all parameters essential.
- Returns:
Names of essential parameters.
- property auxiliary_param_names: set[str]#
Names of the object’s auxiliary parameters.
Auxiliary parameters are parameters that do not fundamentally impact the object’s behavior or identity. These parameters might include settings like logging verbosity, debug flags, or probability thresholds for consistency checks.
They are considered “disregardable” in the sense that they are not guaranteed to be preserved during serialization/deserialization processes, or even during simple copying/deepcopying operations.
- Returns:
Set of auxiliary parameter names.
- class mixinforge.SingleThreadEnforcerMixin(*args, **kwargs)[source]#
Bases:
objectMixin to enforce single-threaded execution with multi-process support.
Add this mixin to any class to ensure its methods are called only from the thread that first instantiated it. Automatically resets ownership after process forks to support multi-process parallelism while preventing concurrent threading issues.
The enforcement happens at instantiation and can be manually triggered via the _restrict_to_single_thread method.
- Raises:
RuntimeError – If instantiated or if _restrict_to_single_thread is called from a different thread than the owner thread.
Example
>>> class MyClass(SingleThreadEnforcerMixin): ... def process(self): ... self._restrict_to_single_thread() ... # Process safely on owner thread
- class mixinforge.SingletonMixin(*args, **kwargs)[source]#
Bases:
ParameterizableMixinMixin for creating singleton classes.
Ensures each subclass maintains exactly one instance that is returned on every instantiation. The singleton instance is stored per class type, so each subclass has its own singleton instance.
- _instances#
Dictionary storing the singleton instance for each class.
- _counters#
Dictionary tracking the number of instantiation requests per class.
Note
This implementation is not thread-safe. For multi-threaded applications, additional synchronization mechanisms should be added.
- mixinforge.access_jsparams(jsparams, *args)[source]#
Access selected constructor parameters from a serialized JSON blob.
- Args:
jsparams: The JSON string produced by dumpjs. *args: Parameter names to extract from the internal PARAMS -> DICT
mapping.
- mixinforge.dumpjs(obj, **kwargs)[source]#
Dump an object to a JSON string using custom serialization.
- mixinforge.flatten_nested_collection(obj)[source]#
Yield leaf elements from nested collections with weak deduplication.
Atomic elements are indivisible values such as numbers, strings, matrices, or paths. The function traverses nested iterables, yielding leaf values, which includes both atomics and non-iterable objects. Their exact order and complete deduplication are not guaranteed.
Handles cycles gracefully by visiting each object only once.
Mapping keys and values are both traversed.
- mixinforge.find_instances_inside_composite_object(obj, classinfo, *, deep_search=True)[source]#
Find all instances of a target type within any object.
Performs traversal of iterables, mappings, and custom objects (via __dict__ and __slots__). Yields all instances matching classinfo, continuing to search inside matched objects for nested instances. Exact return order and complete deduplication are not guaranteed.
Handles cycles gracefully by visiting each object only once.
Mapping keys and values are both traversed.
- Parameters:
obj (
Any) – The object to search within.classinfo (
type|Union|tuple[type|Union|tuple[ClassInfo,...],...]) – Type or tuple of types to search for. Accepts the same values as the second argument to isinstance(): a single type, a tuple of types (recursively), or a union type (e.g., int | str).deep_search (
bool) – If True (default), after finding an instance, continue recursively searching inside it for more matching instances. If False, stop traversal at matched instances.
- Yields:
Instances matching classinfo in depth-first order, deduplicated by identity.
- Raises:
TypeError – If classinfo is invalid.
- Return type:
- mixinforge.install_package(package_name, *, upgrade=False, version=None, use_uv=True, import_name=None, verify_import=True)[source]#
Install a Python package from PyPI into the current environment.
Installs packages using uv (default) or pip, automatically bootstrapping missing package managers. Handles packages where the PyPI name differs from the import name, and verifies successful installation by default.
- Parameters:
- Raises:
ValueError – If args are invalid.
RuntimeError – If installation fails.
ModuleNotFoundError – If verification fails.
- Return type:
Example
>>> install_package("requests") >>> install_package("Pillow", import_name="PIL")
- mixinforge.is_package_installed(package_name)[source]#
Check if a Python package is installed and importable.
- mixinforge.is_valid_env_name(name)[source]#
Validate a portable environment variable name.
Enforces a strict, shell-safe subset (POSIX identifiers) so names are portable across macOS, Windows, and Ubuntu. Names must start with an ASCII letter or underscore and contain only ASCII letters, digits, and underscores.
- mixinforge.transform_instances_inside_composite_object(obj, classinfo, transform_fn, *, deep_transformation=True)[source]#
Transform all instances of a target type within any object.
Traverses collections and custom objects. Transforms matching instances and reconstructs the composite object. Handles cycles.
- Parameters:
obj (
Any) – The object to transform.classinfo (
type|Union|tuple[type|Union|tuple[ClassInfo,...],...]) – Type(s) to search for and transform.transform_fn (
Callable[[Any],Any]) – Function to apply to matching instances.deep_transformation (
bool) – If True, recursively transform inside result.
- Return type:
- Returns:
The transformed object (or original if unchanged).
- Raises:
TypeError – If classinfo is invalid.
- mixinforge.is_executed_in_notebook()[source]#
Return whether code is running inside a Jupyter/IPython notebook.
Uses a lightweight heuristic checking for IPython presence and specific attributes. Cached to avoid repeated imports.
- Return type:
- Returns:
True if running inside a notebook.
- mixinforge.loadjs(s, **kwargs)[source]#
Load an object from a JSON string produced by dumpjs.
- Parameters:
- Return type:
- Returns:
The reconstructed Python object.
- Raises:
TypeError – If s is not a string.
ValueError – If object_hook is provided.
- mixinforge.reset_notebook_detection()[source]#
Clear the cached result of is_executed_in_notebook().
Forces re-detection on next call (useful for testing).
- Return type:
- mixinforge.uninstall_package(package_name, *, use_uv=True, import_name=None, verify_uninstall=True)[source]#
Remove a Python package from the current environment.
Protects critical packages (pip, uv). Verifies removal.
- Parameters:
- Raises:
ValueError – If uninstalling protected packages.
RuntimeError – If uninstall fails or package remains.
- Return type:
- mixinforge.update_jsparams(jsparams, **kwargs)[source]#
Update constructor parameters inside a serialized JSON blob.
This helper takes a JSON string produced by dumpjs for an object that was serialized via its get_params method and returns a new JSON string with the provided parameters updated or added under the internal PARAMS -> DICT mapping.
- Parameters:
- Return type:
- Returns:
A new JSON string with updated parameters.
- Raises: