Skip to content

trcks.oop.BaseWrapper

Bases: Generic[_T_co]

Base class for all wrappers in the trcks.oop package.

Attributes:

  • core (Final[_T_co]) –

    The wrapped value.

Note

This class is not particularly useful by itself. If you want to wrap and process a value, please consider using one of its subclasses, such as trcks.oop.Wrapper.

Example

Wrapping and unwrapping an integer:

>>> from trcks.oop import BaseWrapper
>>> wrapped_integer = BaseWrapper[int](core=42)
>>> wrapped_integer
BaseWrapper(core=42)
>>> unwrapped_integer = wrapped_integer.core
>>> unwrapped_integer
42

Equality depends on the class and on the wrapped value:

>>> from trcks.oop import BaseWrapper
>>> BaseWrapper(core=42) == BaseWrapper(core=42)
True
>>> BaseWrapper(core=42) == BaseWrapper(core=0)
False
>>> class SubWrapper(BaseWrapper[int]):
...     def __init__(self, core: int, metadata: str) -> None:
...         super().__init__(core)
...         self.metadata = metadata
>>> SubWrapper(core=42, metadata="x") == BaseWrapper(core=42)
False
>>> BaseWrapper(core=42) == SubWrapper(core=42, metadata="x")
False
>>> SubWrapper(core=42, metadata="x") == SubWrapper(core=42, metadata="y")
True

Same class and same wrapped value implies same hash:

>>> from trcks.oop import BaseWrapper
>>> hash(BaseWrapper(core=42)) == hash(BaseWrapper(core=42))
True
>>> class SubWrapper(BaseWrapper[int]):
...     def __init__(self, core: int, metadata: str) -> None:
...         super().__init__(core)
...         self.metadata = metadata
>>> hash(
...     SubWrapper(core=42, metadata="x")
... ) == hash(SubWrapper(core=42, metadata="y"))
True

Unhashable values lead to unhashable wrappers:

>>> from trcks.oop import BaseWrapper
>>> hash(BaseWrapper(core=[1, 2, 3]))
Traceback (most recent call last):
    ...
TypeError: unhashable type: 'list'

Wrappers are immutable:

>>> from trcks.oop import BaseWrapper
>>> wrapper = BaseWrapper(core=42)
>>> wrapper.core = 100
Traceback (most recent call last):
    ...
AttributeError: cannot assign to attribute 'core'
>>> del wrapper.core
Traceback (most recent call last):
    ...
AttributeError: cannot delete attribute 'core'
Source code in src/trcks/oop/_base_wrapper.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
class BaseWrapper(Generic[_T_co]):
    """Base class for all wrappers in the [trcks.oop][] package.

    Attributes:
        core: The wrapped value.

    Note:
        This class is not particularly useful by itself.
        If you want to wrap and process a value,
        please consider using one of its subclasses,
        such as [trcks.oop.Wrapper][].

    Example:
        Wrapping and unwrapping an integer:

            >>> from trcks.oop import BaseWrapper
            >>> wrapped_integer = BaseWrapper[int](core=42)
            >>> wrapped_integer
            BaseWrapper(core=42)
            >>> unwrapped_integer = wrapped_integer.core
            >>> unwrapped_integer
            42

        Equality depends on the class and on the wrapped value:

            >>> from trcks.oop import BaseWrapper
            >>> BaseWrapper(core=42) == BaseWrapper(core=42)
            True
            >>> BaseWrapper(core=42) == BaseWrapper(core=0)
            False
            >>> class SubWrapper(BaseWrapper[int]):
            ...     def __init__(self, core: int, metadata: str) -> None:
            ...         super().__init__(core)
            ...         self.metadata = metadata
            >>> SubWrapper(core=42, metadata="x") == BaseWrapper(core=42)
            False
            >>> BaseWrapper(core=42) == SubWrapper(core=42, metadata="x")
            False
            >>> SubWrapper(core=42, metadata="x") == SubWrapper(core=42, metadata="y")
            True

        Same class and same wrapped value implies same hash:

            >>> from trcks.oop import BaseWrapper
            >>> hash(BaseWrapper(core=42)) == hash(BaseWrapper(core=42))
            True
            >>> class SubWrapper(BaseWrapper[int]):
            ...     def __init__(self, core: int, metadata: str) -> None:
            ...         super().__init__(core)
            ...         self.metadata = metadata
            >>> hash(
            ...     SubWrapper(core=42, metadata="x")
            ... ) == hash(SubWrapper(core=42, metadata="y"))
            True

        Unhashable values lead to unhashable wrappers:

            >>> from trcks.oop import BaseWrapper
            >>> hash(BaseWrapper(core=[1, 2, 3]))
            Traceback (most recent call last):
                ...
            TypeError: unhashable type: 'list'

        Wrappers are immutable:

            >>> from trcks.oop import BaseWrapper
            >>> wrapper = BaseWrapper(core=42)
            >>> wrapper.core = 100
            Traceback (most recent call last):
                ...
            AttributeError: cannot assign to attribute 'core'
            >>> del wrapper.core
            Traceback (most recent call last):
                ...
            AttributeError: cannot delete attribute 'core'
    """

    # Data classes do not play nicely with covariant type variables in Python 3.13+
    # (see https://github.com/microsoft/pyright/discussions/11012 and https://github.com/python/mypy/issues/17623).
    # Therefore, we need to implement the following dunder methods and attributes
    # manually:

    __slots__: tuple[str, ...] = ("core",)

    @final
    @override
    def __delattr__(self, name: str) -> Never:
        """Prevent attribute deletion.

        Raises:
            AttributeError: Always.
        """
        msg = f"cannot delete attribute {name!r}"
        raise AttributeError(msg, name=name, obj=self)

    @final
    @override
    def __eq__(self, other: object) -> bool:
        """Check if this wrapper is equal to another object.

        Args:
            other: The object to compare with.

        Returns:
            NotImplemented if the classes differ.
                False if the wrapped values differ.
                True otherwise.
        """
        if type(other) is type(self):
            return other.core == self.core
        return NotImplemented

    @final
    @override
    def __hash__(self) -> int:
        """Hash the wrapper.

        Returns:
            The hash of the wrapper.
        """
        return hash((type(self), self.core))

    def __init__(self, core: _T_co) -> None:
        """Initialize the wrapper.

        Args:
            core: The value to be wrapped.
        """
        super().__init__()
        self.core: Final[_T_co] = core

    @override
    def __repr__(self) -> str:
        """Represent the wrapper textually.

        Returns:
            The textual representation of the wrapper.
        """
        return f"{self.__class__.__name__}(core={self.core!r})"

    @final
    @override
    def __setattr__(self, name: str, value: object) -> None:
        """Set attribute during initialization.

        Args:
            name: The name of the attribute.
            value: The value to set.

        Raises:
            AttributeError: If the attribute already exists.
        """
        try:
            self.__getattribute__(name)
        except AttributeError:
            pass  # Attribute does not exist yet.
        else:
            msg = f"cannot assign to attribute {name!r}"
            raise AttributeError(msg, name=name, obj=self)

        # Raises AttributeError if name is not in __slots__:
        super().__setattr__(name, value)

__delattr__(name)

Prevent attribute deletion.

Raises:

Source code in src/trcks/oop/_base_wrapper.py
 94
 95
 96
 97
 98
 99
100
101
102
103
@final
@override
def __delattr__(self, name: str) -> Never:
    """Prevent attribute deletion.

    Raises:
        AttributeError: Always.
    """
    msg = f"cannot delete attribute {name!r}"
    raise AttributeError(msg, name=name, obj=self)

__eq__(other)

Check if this wrapper is equal to another object.

Parameters:

  • other (object) –

    The object to compare with.

Returns:

  • bool

    NotImplemented if the classes differ. False if the wrapped values differ. True otherwise.

Source code in src/trcks/oop/_base_wrapper.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
@final
@override
def __eq__(self, other: object) -> bool:
    """Check if this wrapper is equal to another object.

    Args:
        other: The object to compare with.

    Returns:
        NotImplemented if the classes differ.
            False if the wrapped values differ.
            True otherwise.
    """
    if type(other) is type(self):
        return other.core == self.core
    return NotImplemented

__hash__()

Hash the wrapper.

Returns:

  • int

    The hash of the wrapper.

Source code in src/trcks/oop/_base_wrapper.py
122
123
124
125
126
127
128
129
130
@final
@override
def __hash__(self) -> int:
    """Hash the wrapper.

    Returns:
        The hash of the wrapper.
    """
    return hash((type(self), self.core))

__init__(core)

Initialize the wrapper.

Parameters:

  • core (_T_co) –

    The value to be wrapped.

Source code in src/trcks/oop/_base_wrapper.py
132
133
134
135
136
137
138
139
def __init__(self, core: _T_co) -> None:
    """Initialize the wrapper.

    Args:
        core: The value to be wrapped.
    """
    super().__init__()
    self.core: Final[_T_co] = core

__repr__()

Represent the wrapper textually.

Returns:

  • str

    The textual representation of the wrapper.

Source code in src/trcks/oop/_base_wrapper.py
141
142
143
144
145
146
147
148
@override
def __repr__(self) -> str:
    """Represent the wrapper textually.

    Returns:
        The textual representation of the wrapper.
    """
    return f"{self.__class__.__name__}(core={self.core!r})"

__setattr__(name, value)

Set attribute during initialization.

Parameters:

  • name (str) –

    The name of the attribute.

  • value (object) –

    The value to set.

Raises:

Source code in src/trcks/oop/_base_wrapper.py
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@final
@override
def __setattr__(self, name: str, value: object) -> None:
    """Set attribute during initialization.

    Args:
        name: The name of the attribute.
        value: The value to set.

    Raises:
        AttributeError: If the attribute already exists.
    """
    try:
        self.__getattribute__(name)
    except AttributeError:
        pass  # Attribute does not exist yet.
    else:
        msg = f"cannot assign to attribute {name!r}"
        raise AttributeError(msg, name=name, obj=self)

    # Raises AttributeError if name is not in __slots__:
    super().__setattr__(name, value)