Skip to content

numerary.protocol package reference

Experimental

This package is an attempt to ease compatibility between Python’s numbers and types. If that sounds like it shouldn’t be a thing, you won’t get any argument out of me. Anyhoo, this package should be considered experimental. I am working toward stability as quickly as possible, but be warned that future release may introduce incompatibilities or remove this package altogether. Feedback, suggestions, and contributions are desperately appreciated.

numerary has donated its core caching protocol implementation to (and now depends on) beartype. beartype is awesome, and its author is even awesomer.1 numerary’s version (in this package) augments that implementation to allow for runtime check overrides.

CachingProtocolMeta

Bases: _BeartypeCachingProtocolMeta

An extension of beartype.typing.Protocol that allows overriding runtime checks.

Source code in numerary/protocol.py
 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 CachingProtocolMeta(_BeartypeCachingProtocolMeta):
    # TODO(posita): Add more precise link to beartype.typing.Protocol documentation once
    # it becomes available.
    r"""
    An extension of [``#!python
    beartype.typing.Protocol``](https://github.com/beartype/beartype) that allows
    overriding runtime checks.
    """

    _abc_inst_check_cache_overridden: Dict[Type, bool]
    _abc_inst_check_cache_listeners: Set[CachingProtocolMeta]

    # Defined in beartype.typing.Protocol from which we inherit
    _abc_inst_check_cache: Dict[type, bool]

    def __new__(
        mcls: Type[_TT],
        name: str,
        bases: Tuple[Type, ...],
        namespace: Dict[str, Any],
        **kw: Any,
    ) -> _TT:
        cls = super().__new__(mcls, name, bases, namespace, **kw)

        # Prefixing this class member with "_abc_" is necessary to prevent it from being
        # considered part of the Protocol. (See
        # <https://github.com/python/cpython/blob/main/Lib/typing.py>.)
        cls._abc_inst_check_cache_overridden = defaultdict(bool)  # defaults to False
        cls._abc_inst_check_cache_listeners = set()

        for base in bases:
            if hasattr(base, "_abc_inst_check_cache_listeners"):
                base._abc_inst_check_cache_listeners.add(cls)

        return cls

    def includes(cls, inst_t: Type) -> None:
        r"""
        Registers *inst_t* as supporting the interface in the runtime type-checking cache.
        This overrides any prior cached value.

        ``` python
        >>> from abc import abstractmethod
        >>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

        >>> @runtime_checkable
        ... class SupportsSpam(
        ...   Protocol,
        ...   metaclass=CachingProtocolMeta
        ... ):
        ...   @abstractmethod
        ...   def spam(self) -> str:
        ...     pass

        >>> class NoSpam:
        ...   pass

        >>> isinstance(NoSpam(), SupportsSpam)
        False
        >>> SupportsSpam.includes(NoSpam)
        >>> isinstance(NoSpam(), SupportsSpam)
        True

        ```

        !!! note

            This does not affect static type-checking.

            ``` python
            >>> my_spam: SupportsSpam = NoSpam()  # type: ignore [assignment]  # still generates a Mypy warning

            ```
        """
        cls._abc_inst_check_cache[inst_t] = True
        cls._abc_inst_check_cache_overridden[inst_t] = True
        cls._dirty_for(inst_t)

    def excludes(cls, inst_t: Type) -> None:
        r"""
        Registers *inst_t* as supporting the interface in the runtime type-checking cache.
        This overrides any prior cached value.

        ``` python
        >>> from abc import abstractmethod
        >>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

        >>> @runtime_checkable
        ... class SupportsHam(
        ...   Protocol,
        ...   metaclass=CachingProtocolMeta
        ... ):
        ...   @abstractmethod
        ...   def ham(self) -> str:
        ...     pass

        >>> class NoHam:
        ...   def ham(self) -> str:
        ...     raise NotImplementedError

        >>> isinstance(NoHam(), SupportsHam)
        True
        >>> SupportsHam.excludes(NoHam)
        >>> isinstance(NoHam(), SupportsHam)
        False

        ```

        !!! note

            This does not affect static type-checking.

            ``` python
            >>> my_ham: SupportsHam = NoHam()  # does *not* generate a Mypy warning

            ```
        """
        cls._abc_inst_check_cache[inst_t] = False
        cls._abc_inst_check_cache_overridden[inst_t] = True
        cls._dirty_for(inst_t)

    def reset_for(cls, inst_t: Type) -> None:
        r"""
        Clears any cached instance check for *inst_t*.
        """
        if inst_t in cls._abc_inst_check_cache:
            del cls._abc_inst_check_cache[inst_t]
            del cls._abc_inst_check_cache_overridden[inst_t]
            cls._dirty_for(inst_t)

    def _dirty_for(cls, inst_t: Type) -> None:
        for inheriting_cls in cls._abc_inst_check_cache_listeners:
            if (
                inst_t in inheriting_cls._abc_inst_check_cache
                and not inheriting_cls._abc_inst_check_cache_overridden[inst_t]
            ):
                del inheriting_cls._abc_inst_check_cache[inst_t]
                del inheriting_cls._abc_inst_check_cache_overridden[inst_t]

excludes(inst_t: Type) -> None

Registers inst_t as supporting the interface in the runtime type-checking cache. This overrides any prior cached value.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
>>> from abc import abstractmethod
>>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

>>> @runtime_checkable
... class SupportsHam(
...   Protocol,
...   metaclass=CachingProtocolMeta
... ):
...   @abstractmethod
...   def ham(self) -> str:
...     pass

>>> class NoHam:
...   def ham(self) -> str:
...     raise NotImplementedError

>>> isinstance(NoHam(), SupportsHam)
True
>>> SupportsHam.excludes(NoHam)
>>> isinstance(NoHam(), SupportsHam)
False

Note

This does not affect static type-checking.

1
>>> my_ham: SupportsHam = NoHam()  # does *not* generate a Mypy warning
Source code in numerary/protocol.py
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
def excludes(cls, inst_t: Type) -> None:
    r"""
    Registers *inst_t* as supporting the interface in the runtime type-checking cache.
    This overrides any prior cached value.

    ``` python
    >>> from abc import abstractmethod
    >>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

    >>> @runtime_checkable
    ... class SupportsHam(
    ...   Protocol,
    ...   metaclass=CachingProtocolMeta
    ... ):
    ...   @abstractmethod
    ...   def ham(self) -> str:
    ...     pass

    >>> class NoHam:
    ...   def ham(self) -> str:
    ...     raise NotImplementedError

    >>> isinstance(NoHam(), SupportsHam)
    True
    >>> SupportsHam.excludes(NoHam)
    >>> isinstance(NoHam(), SupportsHam)
    False

    ```

    !!! note

        This does not affect static type-checking.

        ``` python
        >>> my_ham: SupportsHam = NoHam()  # does *not* generate a Mypy warning

        ```
    """
    cls._abc_inst_check_cache[inst_t] = False
    cls._abc_inst_check_cache_overridden[inst_t] = True
    cls._dirty_for(inst_t)

includes(inst_t: Type) -> None

Registers inst_t as supporting the interface in the runtime type-checking cache. This overrides any prior cached value.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
>>> from abc import abstractmethod
>>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

>>> @runtime_checkable
... class SupportsSpam(
...   Protocol,
...   metaclass=CachingProtocolMeta
... ):
...   @abstractmethod
...   def spam(self) -> str:
...     pass

>>> class NoSpam:
...   pass

>>> isinstance(NoSpam(), SupportsSpam)
False
>>> SupportsSpam.includes(NoSpam)
>>> isinstance(NoSpam(), SupportsSpam)
True

Note

This does not affect static type-checking.

1
>>> my_spam: SupportsSpam = NoSpam()  # type: ignore [assignment]  # still generates a Mypy warning
Source code in numerary/protocol.py
 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
def includes(cls, inst_t: Type) -> None:
    r"""
    Registers *inst_t* as supporting the interface in the runtime type-checking cache.
    This overrides any prior cached value.

    ``` python
    >>> from abc import abstractmethod
    >>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable

    >>> @runtime_checkable
    ... class SupportsSpam(
    ...   Protocol,
    ...   metaclass=CachingProtocolMeta
    ... ):
    ...   @abstractmethod
    ...   def spam(self) -> str:
    ...     pass

    >>> class NoSpam:
    ...   pass

    >>> isinstance(NoSpam(), SupportsSpam)
    False
    >>> SupportsSpam.includes(NoSpam)
    >>> isinstance(NoSpam(), SupportsSpam)
    True

    ```

    !!! note

        This does not affect static type-checking.

        ``` python
        >>> my_spam: SupportsSpam = NoSpam()  # type: ignore [assignment]  # still generates a Mypy warning

        ```
    """
    cls._abc_inst_check_cache[inst_t] = True
    cls._abc_inst_check_cache_overridden[inst_t] = True
    cls._dirty_for(inst_t)

reset_for(inst_t: Type) -> None

Clears any cached instance check for inst_t.

Source code in numerary/protocol.py
155
156
157
158
159
160
161
162
def reset_for(cls, inst_t: Type) -> None:
    r"""
    Clears any cached instance check for *inst_t*.
    """
    if inst_t in cls._abc_inst_check_cache:
        del cls._abc_inst_check_cache[inst_t]
        del cls._abc_inst_check_cache_overridden[inst_t]
        cls._dirty_for(inst_t)

  1. I acknowledge that the subject of who is awesomer, beartype or the man who made it, is hotly contested