Base types collections.

Module Contents

Exceptions

IDError

Exception for Multiton identity errors.

Classes

Multiton

Multiton.

MultitonType

Metaclass for the Multiton pattern.

FrozenType

A metaclass that make class immutable.

StaticType

A metaclass that make class derivation static.

FrozenProtocol

Protocol defining the interface for frozen…

Frozen

A frozen data class with immutable attributes.

Attributes

UnsetType

The type of the Unset singleton.

AnyStr

A constrained type variable.

FilePath

Type alias for a filepath.

AnyFilePath

Type alias for a file path of any string type.

Unset

Sentinel value indicating an attribute has not…

exception IDError[source]

Extends: TypeError

Exception for Multiton identity errors.

Raised during Multiton instance creation when __id__ arguments do not match __match_args__.

See Multiton for details.

Initialize self. See help(type(self)) for accurate signature.

class Multiton[source]

Multiton.

Implements the Multiton pattern, which extends the Singleton pattern to allow a limited number of instances based on identifying values.

Each unique combination of constructor arguments maps to a single instance. Subsequent calls with the same arguments return the same instance, while different argument combinations create new instances (up to the limit of unique argument combinations).

By default, instances are stored using weak references to prevent memory leaks. When no strong references to an instance remain, it is automatically removed from the internal cache. To disable weak reference behavior and maintain strong references to all instances, set weakref=False when defining the class:

class MyClass(Multiton, weakref=False):

The __init__ method of each instance is guaranteed to be called exactly once per unique instance, unless explicitly invoked by user code.

To use this class, subclasses must either:

  1. Define a __match_args__ class attribute listing the attribute names used for instance identification, or

  2. Override the __id__ class method to return a tuple of hashable values that uniquely identify instances based on constructor arguments.

Note

The default weak reference behavior means instances will be garbage collected when no longer referenced elsewhere in the program. To keep instances alive, maintain a strong reference to them.

Warning

Overriding __id__ or __match_args__ incorrectly can lead to unexpected behavior where different constructor arguments might return the same instance or identical arguments might create different instances.

Examples:

>>> class Point(Multiton):
...     __match_args__ = ('x', 'y')
...
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
>>> p1 = Point(1, 2)
>>> p2 = Point(1, 2)
>>> p1 is p2
True
>>> p3 = Point(3, 4)
>>> p1 is p3
False

Subclassing Interface

Multiton provides two overridable methods to customize instance identification and retrieval:

__id__(cls, *args, **kwds) -> tuple[object, ...]

Generates a unique instance identifier from constructor arguments.

The default implementation uses __match_args__ to construct a namedtuple from the constructor’s positional and keyword arguments. Override this method to provide custom identification logic when __match_args__ alone is insufficient.

This method accepts any positional (*args) and keyword (**kwds) arguments passed to the class constructor and returns a tuple of hashable values that uniquely identify the instance. Raises IDError if the provided arguments do not match the attributes defined in __match_args__ and __id__ has not been overridden.

Examples:

>>> class Point(Multiton):
...     __match_args__ = ('x', 'y')
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
>>> Point.__id__(1, 2)
tmp(x=1, y=2)
>>> Point.__id__(x=3, y=4)
tmp(x=3, y=4)
__get_instance__(cls, value: int, default: T | None = None) -> T | None

Retrieve an existing instance by its identifier hash.

This method looks up a previously created Multiton instance using the hash value computed from the identifier tuple returned by __id__. It is intended to be called by a public get() class method that provides a more user-friendly interface.

The value parameter should be the integer hash of the instance identifier tuple. The default parameter specifies the value to return if no instance with the given identifier hash exists (defaults to None).

Examples:

>>> class Point(Multiton):
...     __match_args__ = ('x', 'y')
...     def __init__(self, x, y):
...         self.x = x
...         self.y = y
...
>>> p1 = Point(1, 2)
>>> Point.__get_instance__(hash(Point.__id__(1, 2))) is p1
True
>>> Point.__get_instance__(9999) is None
True
class MultitonType(*_args: Any, **_kwds: Any)[source]

Extends: type

Metaclass for the Multiton pattern.

Implements the Multiton pattern where each unique combination of constructor arguments maps to a single instance. Full documentation and usage details are provided in the Multiton base class.

Example:

class Point(metaclass=MultitonType):
    __match_args__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

Type creation.

ID_METH_NAME = "'__id__'"
INSTANCES_MAP_NAME = "'__instances__'"
WEAKREF_FLAG_NAME = "'__multiton_weakref__'"
class FrozenType[source]

Extends: type

A metaclass that make class immutable.

FrozenType creates types that cannot have their attributes modified after class creation. This provides compile-time safety and prevents accidental or intentional changes to class-level state.

Immutability Rules:
  • Deletion: Attributes cannot be deleted from the class

  • Assignment: Most attributes cannot be modified after creation

Exceptions:

The following attributes are exempt from immutability and can be modified:

  • __abstractmethods__: Required for ABC/Protocol functionality

  • __protocol_attrs__: Required for Protocol functionality

  • Any attribute that is currently Unset

Use Cases:
  • Create classes that should never be modified

  • Prevent accidental class attribute changes in large codebases

  • Provide a stable class interface that cannot be altered by consumers

  • Serve as a base for other metaclasses that need immutability (e.g., StaticType)

Examples

Create a frozen class:

class Constants(metaclass=FrozenType):
    VERSION = "1.0"
    MAX_SIZE = 100

# These raise TypeError
Constants.VERSION = "2.0"  # TypeError: cannot set 'VERSION' attribute...
del Constants.VERSION     # TypeError: cannot delete 'VERSION' attribute...

Check if a class is frozen:

class Mutable:
    pass

class Immutable(metaclass=FrozenType):
    pass

type(Mutable)   # Returns <class 'type'>
type(Immutable) # Returns <class 'FrozenType'>

Note

FrozenType only prevents changes at the class level. Instance attributes (stored in __dict__) are not affected — only class attributes defined on the type itself.

class StaticType(*_args: Any, **_kwds: Any)[source]

Extends: FrozenType, _ProtocolMeta

A metaclass that make class derivation static.

StaticType creates types that “borrow” their attributes (methods, classmethods, staticmethods, etc.) from a base class without using normal class inheritance. When a class inherits from a StaticType-based type, it automatically becomes a new StaticType and borrows all attributes from its parent.

This approach avoids the drawbacks of inheritance (method resolution order issues, diamond problems, tight coupling) while allowing derived classes to use the borrowed behaviors as if they were their own.

The borrowing mechanism:
  • Attributes are copied (not referenced) from the parent to the child

  • The child becomes a new StaticType, allowing further derivation

  • __slots__ from parent and child are merged if both are defined

Single Inheritance Restriction:

Because a class can only borrow from one source, multiple concrete base classes are not supported. However, this metaclass supports special combination with typing.Protocol or abc.ABC to allow borrowing from a Protocol while remaining a Protocol.

Immutability:

Like FrozenType, StaticType makes the created class immutable — attributes cannot be set or deleted after class creation.

Relation to Traits:

StaticType shares the core philosophy of the Traits design pattern: composing behavior without traditional inheritance. However, there are key differences:

  • Implementation vs Interface: Traits define a contract (interface) that must be implemented by consuming classes. StaticType copies behavior from an already-implemented class—the source already has full implementations, not just signatures.

  • Multiple Composition: Traits allow composing multiple traits into a single class. StaticType supports only a single borrowing source per class (linear derivation chain).

  • Commutativity: Traits are commutative—A + B is equivalent to B + A. StaticType is not commutative: deriving from A produces a different result than deriving from B, and importantly, you can only derive from one source at a time.

  • Associativity: Traits are associative—(A + B) + C is equivalent to A + (B + C). StaticType is not associative. Since you can only borrow from one parent, the derivation is a linear chain: Child Parent GrandParent, not a tree or composition.

Examples

First, create a class using StaticType as its metaclass. This class serves as the source of borrowed implementations:

class Vehicle(metaclass=StaticType):
    def start(self) -> str:
        return "Engine started"

    def stop(self) -> str:
        return "Engine stopped"

Now derive from it—attributes are copied (borrowed) to the new class:

class Car(Vehicle):
    pass

# Car borrows start() and stop() from Vehicle
c = Car()
c.start()  # Returns "Engine started"

Deriving again creates a linear chain—each level borrows from its parent:

class SportsCar(Car):
    pass

# Linear chain: SportsCar → Car → Vehicle
# SportsCar borrows from Car, which borrowed from Vehicle
sc = SportsCar()
sc.start()  # Returns "Engine started"

Combine with typing.Protocol to create a non-instantiable interface that can be implemented by derivation:

class Drawable(Protocol, metaclass=StaticType):
    def draw(self) -> None: ...

# Drawable cannot be instantiated (it's a Protocol)
Drawable()  # Raises TypeError

class Shape(Drawable):
    def draw(self) -> None:
        print("Drawing shape")

# Shape implements Drawable by derivation
Shape().draw()  # Prints "Drawing shape"
Raises:

TypeError – If multiple concrete base classes are provided, or if attempting to create a Protocol from a non-Protocol concrete type.

UnsetType

The type of the Unset singleton.

The Unset singleton is design to act as a sentinel value that can be assigned to any type and mimics None where possible, while being type-checker friendly.

Example

>>> foo: str = None  # static type checker may complain
>>> bar: str = Unset  # should be valid for static type checker
>>> isinstance(bar, str)
False
>>> not Unset
True
>>> UnsetType() is Unset
True

See also

Unset: The singleton instance of this type.

AnyStr

A constrained type variable.

AnyStr is meant to be used for functions that may accept str or bytes arguments but cannot allow the two to mix.

Note

despite its name, AnyStr has nothing to do with the Any type, nor does it mean “any string”. In particular, AnyStr and str | bytes are different from each other and have different use cases.

FilePath : TypeAlias = 'AnyStr | PathLike[AnyStr]'

Type alias for a filepath.

Represents a path that can be either a string/bytes or an os.PathLike object. The type is parameterized by AnyStr, so a filepath can be either a str or bytes backed path, but not a mix of the two.

Example

>>> def load_config(path: FilePath[str]) -> dict[str, Any]:
...     ...
AnyFilePath : TypeAlias = 'FilePath[str] | FilePath[bytes]'

Type alias for a file path of any string type.

Represents a path that can be either a str-backed or bytes-backed file path. Unlike FilePath, this type explicitly allows mixing string and bytes paths at the cost of losing the constraint that paths must be of a consistent type.

Example

>>> def find_resource(path: AnyFilePath) -> str:
...     ...
Unset : deluxe._types.UnsetType

Sentinel value indicating an attribute has not been set.

This singleton serves as a type-safe alternative to None for indicating the absence of a value. It can be assigned to any type annotation without causing static type checker warnings.

class FrozenProtocol[source]

Extends: Protocol

Protocol defining the interface for frozen data objects.

This protocol specifies the minimal interface that Frozen and similar frozen data classes must implement.

Example

>>> def process_frozen(obj: FrozenProtocol) -> None:
...    for value in obj:
...        print(value)
class Frozen[source]

Extends: FrozenProtocol, deluxe._types._Frozen

A frozen data class with immutable attributes.

Frozen provides a declarative way to create immutable objects with named attributes. Attributes are specified via the __frozen__ class variable and become read-only after initial assignment.

Performance

Object instantiation is moderately slower than Nameduple but significantly faster than @dataclass or hand-rolled pure python implementations.

Benchmarks (creation time for 3-field objects):

  • mutable dict or slotted classes are almost equivalent

  • Named tuple: 1.4x slower

  • Frozen: 1.6x slower

  • dataclasses: 2.5x slower

  • Hand-rolled frozen: 2,5x slower

Use Cases

  • Need Inheritance: Supports inheritances of frozen attributes

  • Need ABC Mixin: Can combine with ABC for interface design

  • Allow Gradual Initialization: Frozen attributes can be set after instantiation

  • Need Mutable Attribute: defining __slots__ allow additional mutable attributes (eg., need a private attribute for internal state)

Prefer NamedTuple for defining simpler immutable type:

  • faster instantiation

  • less verbose declaration

  • simpler type hinting

  • better support with static type checker

__frozen__

Tuple of attribute names that define the frozen structure. Must be set in subclasses.

Type:

ClassVar[tuple[str, …]]

Iteration Protocol:

The class supports iteration over its values. Unset attributes are yielded as Unset sentinel values.

Example:
>>> class Point(Frozen):
...     __frozen__ = ("x", "y")
>>> p = Point()
>>> p.x = 1
>>> p.y = 2
>>> list(p)
[1, 2]
Sequence Protocol:

Implements sequence-like access via __getitem__ using positional indices (0 to len-1) and supports in, len(), count(), and index() operations.

Comparison Protocol:

Implements __eq__ for value-based equality comparison with other iterables. Implements __hash__ only when all attributes are set.

Pickling Support:

Supports serialization via __reduce__ and reconstruction via __setstate__. Frozen instances can be pickled and unpickled while preserving their attribute values.

raises TypeError:

If an attribute is set twice (immutability violation).

raises TypeError:

If __hash__ is called when any attribute is still Unset.

raises AttributeError:

If attempting to delete an attribute.

raises IndexError:

If __getitem__ receives an out-of-range index.

Example

>>> class User(Frozen):
...     __frozen__ = ("name", "email", "age")
>>> user = User()
>>> user.name = "Alice"
>>> user.email = "alice@example.com"
>>> user.age = 30
>>> user.name
'Alice'
>>> hash(user)
-1234567890
>>> user == User(name="Alice", email="alice@example.com", age=30)
True

See also

FrozenProtocol: Protocol interface for frozen objects. Unset: Sentinel value for unset attributes.