Skip to content

Beartype 0.16.3

Compare
Choose a tag to compare
@github-actions github-actions released this 14 Oct 05:09
· 194 commits to main since this release

This bug-defying patch release adds official support for hot module reloading, root superclass validators, forward reference issubclass() proxying, readable forward reference exceptions, and class redecoration eliding as well as documenting a medley of topics and APIs first introduced with the beartype.claw subpackage under @beartype 0.15.0. Where did the time go? Probably playing vidya games, if I'm being openly honest with myself.

@beartype 0.16.3 almost qualified as a full-blown minor release called @beartype 0.17.0. In the end, however... you failed, @beartype 0.16.3! You weren't quite big enough, dizzyingly stupefying enough, or blatantly broken enough to get upgraded to a minor release. It's for the best.

Look. It was Canadian Thanksgiving. It was all I could do to take the roasted turkey leg out of my mouth. Still, there is awesome sauce. This includes:

  • Hot reloading. @beartype is now robust against hot reloading (i.e., re-importation of previously imported modules containing one or more @beartype-decorated classes), resolving issue #288 kindly submitted by awfully ingenious Cambridge researcher @awf (Andrew Fitzgibbon). The @beartype decorator now explicitly (in order):

    1. Detects class redefinition (i.e., redefinition of a previously @beartype-decorated class with the same name in the same module, usually but not necessarily due to hot reloading).
    2. On the first redefinition of any class, clears all caches (i.e., @beartype-specific internal caches that could possibly contain the prior definition of that redefined class).
  • Root superclass validators. The @beartype decorator now supports beartype validators of the form typing(|_extensions).Annotated[object, beartype.vale.Is*, ...] (i.e., PEP 593-compliant type hints annotating the otherwise ignorable root object superclass by one or more unignorable beartype validators), resolving both issues #290 kindly submitted by Plum maestro @wesselb (Wessel) and beartype/plum#120 kindly submitted by professional hodge-podger @hodgespodge. With the fearsome power of root superclass validators, validate that arbitrary objects satisfy various constraints regardless of the actual types of those objects. This is now a thing:

    >>> from beartype.door import is_bearable
    >>> from beartype.typing import Annotated
    >>> from beartype.vale import Is
    
    >>> ICanHazAttr = Annotated[object, Is[
    ...     lambda value: hasattr(value, 'i_can_haz_attr')]]
    >>> is_bearable('hello', ICanHazAttr)
    False  # <-- y u no got that attr, "str" class!?
    
    >>> class IHazAttr(object):
    ...     i_can_haz_attr = 'Totally got this one, bro.'
    >>> is_bearable(IHazAttr, ICanHazAttr)
    True   # <-- kk, you gots that attr
  • Forward reference issubclass() proxying. The @beartype decorator now supports subscripted forward references (e.g., "type[MuhClass]") to proxy both isinstance() and issubclass() type-checks, resolving issue #289 kindly submitted by Google X extraordinaire @patrick-kidger (Patrick Kidger). Previously, subscripted forward references erroneously proxied only isinstance() type-checks; this omission prevented these references from correctly resolving stringified type hints of the form type[{UndefinedClass}] (i.e., subscriptions of the PEP 585-compliant type[...] builtin by a forward reference to a class that has yet to be defined). Now, all is full of QA. Praise be to the Kidger: e.g.,

    from beartype import beartype         # .-- this really hot ASCII art
                                          # |   arrow means this works now
    @beartype                             # v
    def dance_beartype_dance(i_dont_wanna: 'type[YoullDanceAndLikeIt]'):
        pass
    
    class YoullDanceAndLikeIt(...): ...
  • Readable forward reference exceptions. The @beartype decorator now raises human-readable exceptions involving forward references. Previously, forward reference proxies insanely presented themselves as unreadable private @beartype classes like beartype._check.forward._fwdref._BeartypeForwardRefIndexable. Now, forward reference proxies quietly pretend they're just the classes they proxy. They're not, but you're no longer supposed to know. Sure... okay. Look. This is a bald-faced lie, but @beartype is okay with lying to your face git blame when doing so is in your best interests. Specifically, forward reference proxies now additionally proxy both:

    • The fully-qualified names of the modules declaring the classes to which they refer.
    • The unqualified basenames of those classes.
  • Class redecoration eliding. The @beartype decorator now efficiently protects itself against redecoration. Previously, @beartype uselessly allowed classes already decorated by @beartype to be redecorated by @beartype. Now, @beartype usefully ignores attempts to redecorate classes: e.g.,

    @beartype  # <-- this now reduces to a noop
    @beartype  # <-- this still does nice stuff
    class MuhRedecoratedClass(...): ...
  • Documented stuff. Read such risible, readily defensible, and easily digestible documentation as:

    • A revised high-level introduction to @beartype, which now promotes our principal beartype.claw.beartype_this_package() import hook. Ideally, this is what almost everyone should now be using.
    • A new beartype.claw API page. Every beartype import hook has now been exhaustively documented. Okay, okay. We omitted the beartype.claw.beartyping() context manager, because we ran out of time and Cyberpunk 2077 isn't going to hack its own neural link, is it? It might, actually. We were warned!
    • A new "What does 'pure-Python' mean?" FAQ entry. Reading is fun, even if you learn nothing and squander precious time that could have been better spent breathlessly watching Keanu Reeves do Keanu Reeves things.
    • A new "What does 'hybrid runtime-static' mean?" FAQ entry. You will be bored to tears even as you gnash your teeth in mute frustration, which really cannot be good for your teeth.
    • A new "What does 'third-generation type-checker' mean?" FAQ entry. Fun with Tedious Historical Facts That Will Bore You and Were Probably Just Made Up By @leycec Anyway: The Reckoning.
    • Injects superfluous images illegally culled from Akira into this documentation, just because. If @beartype can do something, @beartype will do something.

This is @beartype 0.16.3, the patch release best described as...

When you strive for Mount Olympus, yet you're still in Hades.
— @leycec, excerpts from "My Life with Beartype: A Sad Story"

This is how the QA was won. Not with a whimper, but an exploding head emoji. 😑 → 🤯