API¶
Package frigid
¶
Data structures which are completely immutable after creation. This behavior is useful for configuration objects, value objects, and other scenarios requiring collections with strong immutability guarantees.
Dictionary
: A dict-like structure that becomes completely immutable after creation. Includes aValidatorDictionary
variant, which validates entries during creation.Namespace
: Similar totypes.SimpleNamespace
but completely immutable after creation.Module
: A module type that enforces complete attribute immutability.Object
: Base class for objects with immutable attributes.Class
: Metaclass for creating classes with immutable class attributes.immutable
: Decorator for making classes produce immutable instances.
Module frigid.dictionaries
¶
Immutable dictionaries.
Dictionaries which cannot be modified after creation.
Note
While types.MappingProxyType
also provides a read-only view
of a dictionary, it has important differences from
Dictionary
:
A
MappingProxyType
is a view over a mutable dictionary, so its contents can still change if the underlying dictionary is modified.Dictionary
owns its data and guarantees that it will never change.Dictionary
provides set operations (union, intersection) that maintain immutability guarantees.
Use MappingProxyType
when you want to expose a read-only view of a
dictionary that might need to change. Use Dictionary
when you want
to ensure that the data can never change, such as for configuration
objects or other cases requiring strong immutability guarantees.
AbstractDictionary
: Base class defining the immutable dictionary interface. Implementations must provide__getitem__
,__iter__
, and__len__
.Dictionary
: Standard implementation of an immutable dictionary. Supports all usual dict read operations but prevents any modifications.ValidatorDictionary
: Validates entries before addition using a supplied predicate function.
>>> from frigid import Dictionary
>>> d = Dictionary( x = 1, y = 2 )
>>> d[ 'z' ] = 3 # Attempt to add entry
Traceback (most recent call last):
...
frigid.exceptions.EntryImmutabilityError: Cannot assign or delete entry for 'z'.
>>> d[ 'x' ] = 4 # Attempt modification
Traceback (most recent call last):
...
frigid.exceptions.EntryImmutabilityError: Cannot assign or delete entry for 'x'.
>>> del d[ 'y' ] # Attempt removal
Traceback (most recent call last):
...
frigid.exceptions.EntryImmutabilityError: Cannot assign or delete entry for 'y'.
- class frigid.dictionaries.AbstractDictionary¶
Bases:
Mapping
[H
,V
]Abstract base class for immutable dictionaries.
An immutable dictionary prevents modification or removal of entries after creation. This provides a clean interface for dictionaries that should never change.
Implementations must provide: - __getitem__, __iter__, __len__
- get(k[, d]) D[k] if k in D, else d. d defaults to None. ¶
- items() a set-like object providing a view on D's items ¶
- keys() a set-like object providing a view on D's keys ¶
- values() an object providing a view on D's values ¶
- class frigid.dictionaries.Dictionary(*iterables: Annotated[Mapping[H, V] | Iterable[tuple[H, V]], Doc('Zero or more iterables from which to initialize dictionary data. Each iterable must be dictionary or sequence of key-value pairs. Duplicate keys will result in an error.')], **entries: Annotated[V, Doc('Zero or more keyword arguments from which to initialize dictionary data.')])¶
Bases:
Object
,_DictionaryOperations
[H
,V
]Immutable dictionary.
Prevents addition, alteration, or removal of dictionary entries after creation.
- copy() Self ¶
Provides fresh copy of dictionary.
- get(key: H, default: V | AbsentSingleton = absence.absent) Annotated[V, Doc('Value of entry, if it exists. Else, supplied default value or ``None``.')] ¶
Retrieves entry associated with key, if it exists.
- values() ValuesView[V] ¶
Provides iterable view over dictionary values.
- with_data(*iterables: Annotated[Mapping[H, V] | Iterable[tuple[H, V]], Doc('Zero or more iterables from which to initialize dictionary data. Each iterable must be dictionary or sequence of key-value pairs. Duplicate keys will result in an error.')], **entries: Annotated[V, Doc('Zero or more keyword arguments from which to initialize dictionary data.')]) Self ¶
Creates new dictionary with same behavior but different data.
- class frigid.dictionaries.ValidatorDictionary(validator: Annotated[Callable[[H, V], bool], Doc('Callable which validates entries before addition to dictionary.')], /, *iterables: Annotated[Mapping[H, V] | Iterable[tuple[H, V]], Doc('Zero or more iterables from which to initialize dictionary data. Each iterable must be dictionary or sequence of key-value pairs. Duplicate keys will result in an error.')], **entries: Annotated[V, Doc('Zero or more keyword arguments from which to initialize dictionary data.')])¶
Bases:
Dictionary
[H
,V
]Immutable dictionary with validation of entries on initialization.
Prevents addition, alteration, or removal of dictionary entries after creation.
When an attempt to create a dictionary with entries, each entry is validated against supplied criteria. If validation fails for any entry, then the dictionary creation is rejected.
- copy() Self ¶
Provides fresh copy of dictionary.
- get(key: H, default: V | AbsentSingleton = absence.absent) Annotated[V, Doc('Value of entry, if it exists. Else, supplied default value or ``None``.')] ¶
Retrieves entry associated with key, if it exists.
- values() ValuesView[V] ¶
Provides iterable view over dictionary values.
- with_data(*iterables: Annotated[Mapping[H, V] | Iterable[tuple[H, V]], Doc('Zero or more iterables from which to initialize dictionary data. Each iterable must be dictionary or sequence of key-value pairs. Duplicate keys will result in an error.')], **entries: Annotated[V, Doc('Zero or more keyword arguments from which to initialize dictionary data.')]) Self ¶
Creates new dictionary with same behavior but different data.
Module frigid.namespaces
¶
Immutable namespaces.
Provides a namespace type with immutable attributes. Similar to
types.SimpleNamespace
, but attributes cannot be modified or
deleted after initialization.
The namespace implementation is modeled after
types.SimpleNamespace
but adds immutability. Like
types.SimpleNamespace
, it provides a simple __repr__
which
lists all attributes.
>>> from frigid import Namespace
>>> ns = Namespace( x = 1, y = 2 )
>>> ns.z = 3 # Attempt to add attribute
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'z'.
>>> ns.x = 4 # Attempt modification
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'x'.
>>> ns
frigid.namespaces.Namespace( x = 1, y = 2 )
- class frigid.namespaces.Namespace(*iterables: Annotated[Mapping[H, V] | Iterable[tuple[H, V]], Doc('Zero or more iterables from which to initialize dictionary data. Each iterable must be dictionary or sequence of key-value pairs. Duplicate keys will result in an error.')], **attributes: Annotated[V, Doc('Zero or more keyword arguments from which to initialize dictionary data.')])¶
Bases:
Object
Immutable namespaces.
A namespace is an object, whose attributes can be determined from iterables and keyword arguments, at initialization time. The string representation of the namespace object reflects its current instance attributes. Modeled after
types.SimpleNamespace
.Prevents assignment or deletion of instance attributes after instance creation.
Module frigid.modules
¶
Immutable modules.
Provides a module type that enforces complete attribute immutability. This helps ensure that module-level constants remain constant and that module interfaces remain stable during runtime.
The module implementation is derived from types.ModuleType
and
adds immutability. This makes it particularly useful for:
Ensuring constants remain constant
Preventing modification of module interfaces
Also provides a convenience function:
reclassify_modules
: Converts existing modules to immutable modules.
- class frigid.modules.Module(name, doc=None)¶
Bases:
ModuleType
Immutable modules.
Derived from
types.ModuleType
, this class is suitable for use as a Python module class.Prevents assignment or deletion of module attributes after module creation.
This behavior helps ensure that module-level constants remain constant and that module interfaces remain stable during runtime.
- frigid.modules.reclassify_modules(attributes: Annotated[Mapping[str, Any] | ModuleType | str, Doc('Module, module name, or dictionary of object attributes.')], recursive: Annotated[bool, Doc('Recursively reclassify package modules?')] = False) None ¶
Reclassifies modules to be immutable.
This function converts existing modules to immutable modules, enforcing attribute immutability after conversion. It can operate on individual modules or entire package hierarchies.
Notes¶
Only converts modules within the same package to prevent unintended modifications to external modules
When used with a dictionary, converts any module objects found as values if they belong to the same package
Module conversion is permanent for the runtime session
Has no effect on already-immutable modules
Module frigid.classes
¶
Immutable classes.
Provides metaclasses for creating classes with immutable attributes. Once a class is initialized, its attributes cannot be reassigned or deleted.
The implementation includes:
Class
: Standard metaclass for immutable classes; derived fromtype
.ABCFactory
: Metaclass for abstract base classes; derived fromabc.ABCMeta
.ProtocolClass
: Metaclass for protocol classes; derived fromtyping.Protocol
.
These metaclasses are particularly useful for:
Creating classes with constant class attributes
Defining stable abstract base classes
Building protocol classes with fixed interfaces
>>> from frigid import Class
>>> class Example( metaclass = Class ):
... x = 1
>>> Example.y = 2 # Attempt assignment
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'y'.
>>> Example.x = 3 # Attempt reassignment
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'x'.
- class frigid.classes.ABCFactory(name: str, bases: tuple[type, ...], namespace: dict[str, Any], *, decorators: Iterable[Callable[[type], type]] = (), docstring: str | None | AbsentSingleton = absence.absent, mutables: Collection[str] = (), **args: Any)¶
Bases:
ABCMeta
Immutable abstract base class factory.
Derived from
type
, this is a metaclass. A metaclass is a class factory class. I.e., it is a class that produces other classes as its instances.Prevents assignment or deletion of class attributes after class creation.
- mro()¶
Return a type’s method resolution order.
- register(subclass)¶
Register a virtual subclass of an ABC.
Returns the subclass, to allow usage as a class decorator.
- class frigid.classes.Class(name: str, bases: tuple[type, ...], namespace: dict[str, Any], *, decorators: Iterable[Callable[[type], type]] = (), docstring: str | None | AbsentSingleton = absence.absent, mutables: Collection[str] = (), **args: Any)¶
Bases:
type
Immutable class factory.
Derived from
type
, this is a metaclass. A metaclass is a class factory class. I.e., it is a class that produces other classes as its instances.Prevents assignment or deletion of class attributes after class creation.
- mro()¶
Return a type’s method resolution order.
- class frigid.classes.ProtocolClass(name: str, bases: tuple[type, ...], namespace: dict[str, Any], *, decorators: Iterable[Callable[[type], type]] = (), docstring: str | None | AbsentSingleton = absence.absent, mutables: Collection[str] = (), **args: Any)¶
Bases:
_ProtocolMeta
Immutable protocol class factory.
Derived from
type
, this is a metaclass. A metaclass is a class factory class. I.e., it is a class that produces other classes as its instances.Prevents assignment or deletion of class attributes after class creation.
- mro()¶
Return a type’s method resolution order.
- register(subclass)¶
Register a virtual subclass of an ABC.
Returns the subclass, to allow usage as a class decorator.
Module frigid.objects
¶
Immutable objects.
Provides a base class and decorator for creating objects with immutable attributes. Once an object is initialized, its attributes cannot be modified or deleted.
The implementation uses a special dictionary type for attribute storage that enforces immutability. This makes it suitable for:
Configuration objects
Value objects
Immutable data containers
Objects requiring attribute stability
>>> from frigid import Object
>>> class Point( Object ):
... def __init__( self, x, y ):
... self.x = x
... self.y = y
... super( ).__init__( )
...
>>> obj = Point( 1, 2 ) # Initialize with attributes
>>> obj.z = 3 # Attempt to add attribute
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'z'.
>>> obj.x = 4 # Attempt modification
Traceback (most recent call last):
...
frigid.exceptions.AttributeImmutabilityError: Cannot assign or delete attribute 'x'.
Module frigid.sequences
¶
Immutable sequences.
- frigid.sequences.one(value: _V) tuple[_V, ...] ¶
Produces single-item tuple from value.
Provides a more explicit and readable alternative to the comma-syntax for creating single-item tuples. While Python allows
( x, )
for creating single-item tuples, usingone( x )
can be clearer, especially in certain contexts:List comprehensions and generator expressions
Situations where formatter behavior with trailing commas is undesired
Module frigid.installers
¶
Convenience to expose certain package features as Python builtins.
Module frigid.exceptions
¶
Family of exceptions for package API.
Provides a hierarchy of exceptions that are raised when immutability is violated. The hierarchy is designed to allow both specific and general exception handling.
Omniexception
: Base for all package exceptionsOmnierror
: Base for all package errorsAttributeImmutabilityError
: Raised for attribute modificationEntryImmutabilityError
: Raised for dictionary entry modification
- exception frigid.exceptions.AttributeImmutabilityError(name: str)¶
Bases:
Omnierror
,AttributeError
,TypeError
Attempt to modify immutable attribute.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
- name¶
attribute name
- obj¶
object
- exception frigid.exceptions.DecoratorCompatibilityError(class_name: str, method_name: str)¶
-
Attempt to apply decorator to incompatible class.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
- exception frigid.exceptions.EntryImmutabilityError(key: Hashable)¶
-
Attempt to modify immutable dictionary entry.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
- exception frigid.exceptions.EntryValidityError(indicator: Hashable, value: Any)¶
Bases:
Omnierror
,ValueError
Attempt to add invalid entry to dictionary.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
- exception frigid.exceptions.Omnierror¶
Bases:
Omniexception
,Exception
Base for error exceptions raised by package API.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
- exception frigid.exceptions.Omniexception¶
Bases:
ImmutableObject
,BaseException
Base for all exceptions raised by package API.
- with_traceback()¶
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- args¶
Module frigid.qaliases
¶
Qualified aliases to immutable data structures.
Provides aliases prefixed with “Immutable” for all core classes. These are useful for avoiding namespace collisions when importing from the package, particularly with common names like “Dictionary” or “Namespace”.
For example, instead of:
>>> from frigid import Dictionary
>>> # Possible conflict with other Dictionary classes
you could use:
>>> from frigid.qaliases import ImmutableDictionary
>>> # Clearly indicates the source and behavior
- frigid.qaliases.AbstractImmutableDictionary
alias of
AbstractDictionary
- frigid.qaliases.ImmutableABCFactory
alias of
ABCFactory
- frigid.qaliases.ImmutableClass
alias of
Class
- frigid.qaliases.ImmutableDictionary
alias of
Dictionary
- frigid.qaliases.ImmutableModule
alias of
Module
- frigid.qaliases.ImmutableNamespace
alias of
Namespace
- frigid.qaliases.ImmutableObject
alias of
Object
- frigid.qaliases.ImmutableProtocolClass
alias of
ProtocolClass
- frigid.qaliases.ImmutableValidatorDictionary
alias of
ValidatorDictionary
- frigid.qaliases.immutable(class_: type[C]) type[C]
Decorator which makes class immutable after initialization.
Cannot be applied to classes which define their own __setattr__ or __delattr__ methods.
- frigid.qaliases.reclassify_modules_as_immutable(attributes: Annotated[Mapping[str, Any] | ModuleType | str, Doc('Module, module name, or dictionary of object attributes.')], recursive: Annotated[bool, Doc('Recursively reclassify package modules?')] = False) None
Reclassifies modules to be immutable.
This function converts existing modules to immutable modules, enforcing attribute immutability after conversion. It can operate on individual modules or entire package hierarchies.
Notes¶
Only converts modules within the same package to prevent unintended modifications to external modules
When used with a dictionary, converts any module objects found as values if they belong to the same package
Module conversion is permanent for the runtime session
Has no effect on already-immutable modules