Skip to content

Commit cccf3a0

Browse files
committed
Remove base _CachingProtocolMeta and use beartype's instead
Now that beartype/beartype#86 has landed (and made it into a release), we can remove our own base implementation and use that one instead. We still provide our own implementation that allows overriding runtime checking, but it neatly derives from ``beartype``'s.
1 parent 514e875 commit cccf3a0

27 files changed

Lines changed: 147 additions & 334 deletions

README.md

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ AssertionError
121121
For example, let’s say one wanted to ensure type compatibility with primitives that support both ``__abs__`` and ``__divmod__``.
122122

123123
``` python
124-
>>> from typing import TypeVar
124+
>>> from beartype.typing import TypeVar
125125
>>> T_co = TypeVar("T_co", covariant=True)
126126
>>> from numerary.types import (
127127
... CachingProtocolMeta, Protocol, runtime_checkable,
@@ -186,7 +186,7 @@ False
186186

187187
``` python
188188
>>> from abc import abstractmethod
189-
>>> from typing import Iterable, Union
189+
>>> from beartype.typing import Iterable, Union
190190
>>> from numerary.types import CachingProtocolMeta, Protocol, runtime_checkable
191191

192192
>>> @runtime_checkable
@@ -292,7 +292,7 @@ Not very well, unfortunately, at least not on its own.
292292
``Union``s allow a work-around.
293293

294294
``` python
295-
>>> from typing import Union
295+
>>> from beartype.typing import Union
296296
>>> from numerary.types import SupportsFloorCeil, __floor__
297297
>>> SupportsFloorCeilU = Union[float, SupportsFloorCeil]
298298

@@ -301,7 +301,7 @@ Not very well, unfortunately, at least not on its own.
301301
... assert isinstance(arg, SupportsFloorCeil)
302302
... return __floor__(arg)
303303

304-
>>> my_floor_func(float(1.2)) # works in 3.7+
304+
>>> my_floor_func(float(1.2)) # works in 3.8+
305305
1
306306

307307
```
@@ -546,23 +546,20 @@ Alternately, you can download [the source](https://github.com/posita/numerary) a
546546

547547
``numerary`` requires a relatively modern version of Python:
548548

549-
* [CPython](https://www.python.org/) (3.7+)
550-
* [PyPy](http://pypy.org/) (CPython 3.7+ compatible)
549+
* [CPython](https://www.python.org/) (3.8+)
550+
* [PyPy](http://pypy.org/) (CPython 3.8+ compatible)
551551

552552
It has the following runtime dependencies:
553553

554554
* [``typing-extensions``](https://pypi.org/project/typing-extensions/) (with Python <3.9)
555-
556-
``numerary`` will opportunistically use the following, if available at runtime:
557-
558-
* [``beartype``](https://pypi.org/project/beartype/) for yummy runtime type-checking goodness (0.8+)
555+
* [``beartype``](https://pypi.org/project/beartype/) for caching protocols (0.10.1+)
559556
[![Bear-ified™](https://raw.githubusercontent.com/beartype/beartype-assets/main/badge/bear-ified.svg)](https://beartype.rtfd.io/)
560557

561-
If you use ``beartype`` for type-checking your code, but don’t want ``numerary`` to use it internally, set the ``NUMERARY_BEARTYPE`` environment variable to a falsy[^6] value before ``numerary`` is loaded.
558+
``numerary`` will not use ``beartype`` internally unless the ``NUMERARY_BEARTYPE`` environment variable is set to a truthy[^6] value before ``numerary`` is loaded.
562559

563560
[^6]:
564561

565-
I.E., one of: ``0``, ``off``, ``f``, ``false``, and ``no``.
562+
I.E., one of: ``1``, ``on``, ``t``, ``true``, and ``yes``.
566563

567564
See the [hacking quick-start](https://posita.github.io/numerary/0.3/contrib/#hacking-quick-start) for additional development and testing dependencies.
568565

docs/notes.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515

1616
# ``numerary`` release notes
1717

18+
## [0.4.0](https://github.com/posita/numerary/releases/tag/v0.4.0)
19+
20+
* Now relies on ``#!python beartype.typing.Protocol`` as the underlying caching protocol implementation.
21+
This means that ``beartype`` is now ``numerary``’s only runtime dependency.
22+
(``numerary`` still layers on its own runtime override mechanism via [CachingProtocolMeta][numerary._protocol.CachingProtocolMeta], which derives from ``beartype``’s.)
23+
24+
This decision was not made lightly.
25+
``numerary`` is intended as a temporary work-around.
26+
It’s obsolescence will be something to celebrate.
27+
Caching protocols, however, have much broader performance applications.
28+
They deserve more.
29+
``beartype`` will provide what ``numerary`` was never meant to: a loving, stable, and permanent home.
30+
1831
## [0.3.0](https://github.com/posita/numerary/releases/tag/v0.3.0)
1932

2033
* ~~Removes misleading advice that SCUs offer a performance benefit over merely using caching protocols.

docs/numerary.types.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
I am working toward stability as quickly as possible, but be warned that future release may introduce incompatibilities or remove this package altogether.
2424
[Feedback, suggestions, and contributions](contrib.md) are desperately appreciated.
2525

26-
In addition to the following protocols and helper functions, ``numerary.types`` also resolves importing ``Annotated``, ``Protocol``, and ``runtime_checkable`` from the best available source.
26+
Because ``numerary`` uses ``beartype`` in its implementation, you can use both to resolve importing ``Annotated``, ``Protocol``, and ``runtime_checkable`` from the best available source.
2727
This can be helpful if you need to support Python versions prior to 3.9, but don’t want to make a conditional import of ``typing_extensions`` everywhere.
2828
Instead of doing this all over the place …
2929

@@ -37,18 +37,13 @@ except ImportError:
3737
… you can do this instead …
3838

3939
``` python
40-
from numerary.types import Annotated, Protocol, runtime_checkable
40+
from beartype.typing import Annotated, runtime_checkable
41+
from numerary.types import Protocol
4142
```
4243

4344
Bang.
4445
Done.
4546

46-
Further, if you want to opportunistically take advantage of [``beartype``](https://github.com/beartype/beartype/) without imposing a strict runtime dependency, you can do this:
47-
48-
``` python
49-
from numerary.bt import beartype # will resolve to the identity decorator if beartype is unavailable at runtime
50-
```
51-
5247
Which you should totally do, because ``beartype`` is *awesome*.
5348
Its author is even *awesomer*.[^1]
5449

@@ -90,6 +85,7 @@ Its author is even *awesomer*.[^1]
9085
- "SupportsRealOps"
9186
- "SupportsIntegralOps"
9287
- "SupportsIntegralPow"
88+
- "Protocol"
9389
- "real"
9490
- "imag"
9591
- "__pow__"

docs/perf_rational_baseline.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%timeit isinstance(builtins.int(1), Rational)
2-
356 ns ± 15.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2+
244 ns ± 8.05 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
33
%timeit isinstance(fractions.Fraction(2), Rational)
4-
350 ns ± 14.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
4+
237 ns ± 4.85 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
55
%timeit isinstance(builtins.float(3.0), Rational)
6-
359 ns ± 3.21 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
6+
273 ns ± 9.28 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%timeit isinstance(builtins.int(1), SupportsLotsOfNumberStuff)
2-
136 µs ± 3.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
2+
207 ns ± 9.04 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
33
%timeit isinstance(fractions.Fraction(2), SupportsLotsOfNumberStuff)
4-
154 µs ± 5.94 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
4+
203 ns ± 1.85 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
55
%timeit isinstance(builtins.float(3.0), SupportsLotsOfNumberStuff)
6-
149 µs ± 8.33 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
6+
220 ns ± 42 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

docs/perf_rational_protocol.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
%timeit isinstance(builtins.int(1), SupportsNumeratorDenominator)
2-
13 µs ± 270 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
2+
12.5 µs ± 1.45 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
33
%timeit isinstance(fractions.Fraction(2), SupportsNumeratorDenominator)
4-
14 µs ± 761 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
4+
11.1 µs ± 864 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
55
%timeit isinstance(builtins.float(3.0), SupportsNumeratorDenominator)
6-
15.4 µs ± 323 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
6+
12.2 µs ± 1.96 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

docs/perf_supports_complex.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
%timeit isinstance(builtins.int(1), _SupportsComplexOps)
2-
11.9 µs ± 279 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
2+
340 ns ± 121 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
33
%timeit isinstance(builtins.int(1), SupportsComplexOps)
4-
312 ns ± 1.56 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
4+
258 ns ± 25.9 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
55

66
%timeit isinstance(builtins.float(2.0), _SupportsComplexOps)
7-
13.1 µs ± 385 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
7+
224 ns ± 5.17 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
88
%timeit isinstance(builtins.float(2.0), SupportsComplexOps)
9-
380 ns ± 23 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
9+
221 ns ± 10.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
1010

1111
%timeit isinstance(decimal.Decimal(3), _SupportsComplexOps)
12-
13.3 µs ± 897 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
12+
242 ns ± 18.2 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
1313
%timeit isinstance(decimal.Decimal(3), SupportsComplexOps)
14-
322 ns ± 12.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
14+
245 ns ± 27.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
1515

1616
%timeit isinstance(fractions.Fraction(4), _SupportsComplexOps)
17-
11.9 µs ± 178 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
17+
245 ns ± 27.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
1818
%timeit isinstance(fractions.Fraction(4), SupportsComplexOps)
19-
314 ns ± 1.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
19+
234 ns ± 17.2 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
2020

2121
%timeit isinstance(sympy.core.numbers.Integer(5), _SupportsComplexOps)
22-
12 µs ± 110 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
22+
227 ns ± 10.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
2323
%timeit isinstance(sympy.core.numbers.Integer(5), SupportsComplexOps)
24-
315 ns ± 4.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
24+
225 ns ± 13.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
2525

numerary/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from __future__ import annotations
1010

11-
from typing import Tuple, Union
11+
from beartype.typing import Tuple, Union
1212

1313
from .types import * # noqa: F401,F403
1414

0 commit comments

Comments
 (0)