typing
frequenz.core.typing ¤
Type hints and utility functions for type checking and types.
For now this module only provides a decorator to disable the __init__
constructor of
a class, to force the use of a factory method to create instances. See
disable_init for more information.
Attributes¤
frequenz.core.typing.TypeT
module-attribute
¤
A type variable that is bound to a type.
Functions¤
frequenz.core.typing.disable_init ¤
disable_init(
cls: TypeT | None = None,
*,
error: Exception | None = None
) -> TypeT | Callable[[TypeT], TypeT]
Disable the __init__
constructor of a class.
This decorator can be used to disable the __init__
constructor of a class. It is
intended to be used with classes that don't provide a default constructor and
require the use of a factory method to create instances.
When marking a class with this decorator, the class cannot be even declared with a
__init__
method, as it will raise a TypeError
when the class is created, as soon
as the class is parsed by the Python interpreter. It will also raise a TypeError
when the __init__
method is called.
To create an instance you must provide a factory method, using __new__
.
Warning
This decorator will use a custom metaclass to disable the __init__
constructor
of the class, so if your class already uses a custom metaclass, you should be
aware of potential conflicts.
Basic example defining a class with a factory method
To be able to type hint the class correctly, you can declare the instance attributes in the class body, and then use a factory method to create instances.
from typing import Self
@disable_init
class MyClass:
value: int
@classmethod
def new(cls, value: int = 1) -> Self:
self = cls.__new__(cls)
self.value = value
return self
instance = MyClass.new()
# Calling the default constructor (__init__) will raise a TypeError
try:
instance = MyClass()
except TypeError as e:
print(e)
Class wrongly providing an __init__
constructor
Using a custom error message when the default constructor is called
from typing import Self
class NoInitError(TypeError):
def __init__(self) -> None:
super().__init__("Please create instances of MyClass using MyClass.new()")
@disable_init(error=NoInitError())
class MyClass:
@classmethod
def new(cls) -> Self:
return cls.__new__(cls)
try:
instance = MyClass()
except NoInitError as e:
assert str(e) == "Please create instances of MyClass using MyClass.new()"
print(e)
PARAMETER | DESCRIPTION |
---|---|
cls
|
The class to be decorated.
TYPE:
|
error
|
The error to raise if init is called, if
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
TypeT | Callable[[TypeT], TypeT]
|
A decorator that disables the |
Source code in frequenz/core/typing.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
|