pypi beartype 0.11.0
Beartype 0.11.0

latest releases: 0.21.0, 0.21.0rc0, 0.20.2...
3 years ago

Beartype 0.11.0 released.

This minor release unleashes a major firestorm of support for class decoration, colourful exceptions, pyright + PyLance + VSCode, the Decidedly Object-Orientedly Recursive (DOOR) API, the Python Enhancement Proposals (PEPs) API, PEP 484, PEP 544, PEP 561, PEP 563, PEP 585, PEP 604, PEP 612, and PEP 647.

This minor release resolves a mammoth 29 issues and merges 12 pull requests. Noteworthy changes include:

Compatibility Improved

  • Class decoration. The @beartype decorator now decorates both higher-level classes and lower-level callables (i.e., functions, methods), resolving feature request #152 kindly submitted by @posita the positively sublime. All possible edge cases are supported, including:
    • Classes defining methods decorated by builtin decorators: i.e.,
      • Class methods via @classmethod.
      • Static methods via @staticmethod.
      • Property getters, setters, and deleters via @property.
    • Arbitrarily deeply nested (i.e., inner) classes.
    • Arbitrarily deeply nested (i.e., inner) classes whose type hints are
      postponed under PEP 563.
      Since this was surprisingly trivial, @leycec probably should have done this a few years ago. He didn't. This is why he laments into his oatmeal in late 2022.
  • PEP 484- and PEP 585-compliant nested generics. @beartype now supports arbitrarily complex PEP 484- and PEP 585-compliant inheritance trees subclassing non-trivial combinations of the typing.Generic superclass and other typing pseudo-superclasses, resolving issue #140 kindly submitted by @langfield (William Blake – yes, that William Blake). Notably, this release extricated our transitive visitation of the tree of all pseudo-superclasses of any PEP 484- and 585-compliant generic type hint (...don't ask) from its prior hidden sacred cave deep within the private beartype._decor._code._pep._pephint submodule into a new reusable iter_hint_pep484585_generic_bases_unerased_tree() generator, which is now believed to be the most fully-compliant algorithm for traversing generic inheritance trees at runtime. This cleanly resolved all lingering issues surrounding generics, dramatically reduced the likelihood of more issues surrounding generics, and streamlined the resolution of any more issues surrounding generics should they arise... which they won't. Generics: we have resoundingly beaten you. Stay down, please.
  • PEP 544 compatibility. @beartype now supports arbitrarily complex PEP 544-compliant inheritance trees subclassing non-trivial combinations of the typing.Protocol + abc.ABC superclasses, resolving #117 kindly submitted by too-entertaining pun master @twoertwein (Torsten Wörtwein). Notably, @beartype now:
    • Correctly detects non-protocols as non-protocols. Previously, @beartype erroneously detected a subset of non-protocols as PEP 544-compliant protocols. It's best not to ask why.
    • Ignores both the unsubscripted beartype.typing.Protocol superclass and parametrizations of that superclass by one or more type variables (e.g., beartype.typing.Protocol[typing.TypeVar('T')]) as semantically meaningless in accordance with similar treatment of the typing.Protocol superclass.
    • Permits caller-defined abstract protocols subclassing our caching beartype.typing.Protocol superclass to themselves be subclassed by one or more concrete subclasses. Previously, attempting to do so would raise non-human-readable exceptions from the typing module; now, doing so behaves as expected.
    • Relaxed our prior bad assumption that the second-to-last superclass of all generics – and thus protocols – is the typing.Generic superclass. That assumption only holds for standard generics and protocols; non-standard protocols subclassing non-typing superclasses (e.g., the abc.ABC superclass) after the list typing superclass in their method resolution order (MRO) flagrantly violate this assumption. Well, that's fine. We're fine with that. What's not fine about that? Fine. This is fine.
    • Avoids a circular import dependency. Previously, our caching beartype.typing.Protocol superclass leveraged the general-purpose @beartype._util.cache.utilcachecall.callable_cached decorator to memoize its subscription; however, since that decorator transitively imports from the beartype.typing subpackage, doing so induced a circular import dependency. To circumvent this, a new @beartype.typing._typingcache.callable_cached_minimal decorator implementing only the minimal subset of the full @beartype._util.cache.utilcachecall.callable_cached decorator has been defined; the beartype.typing subpackage now safely defers to this minimal variant for all its caching needs.
  • PEP 563 compatibility. @beartype now resolves PEP 563-postponed self-referential type hints (i.e., type hints circularly referring to the class currently being decorated). Caveat: this support requires that external callers decorate the class being referred to (rather than the method doing the referring) by the @beartype decorator. For this and similar reasons, users are advised to begin refactoring their object-oriented codebases to decorate their classes rather than methods with @beartype.
  • PEP 612 partial shallow compatibility. @beartype now shallowly detects PEP 612-compliant typing.ParamSpec objects by internally associating such objects with our beartype._data.hint.pep.sign.datapepsigns.HintSignParamSpec singleton, enabling @beartype to portably introspect Callable[typing.ParamSpec(...), ...] type hints.
  • Static type-checking. @beartype is now substantially more compliant with static type-checkers, including:
    • Microsoft pyright + PyLance + VSCode. @beartype now officially supports pyright, Microsoft's in-house static type-checker oddly implemented in pure-TypeScript, gulp resolving issues #126 and #127 kindly submitted by fellow Zelda aficionado @rbroderi. Specifically, this release resolves several hundred false warnings and errors issued by pyright against the @beartype codebase. It is, indeed, dangerous to go alone – but we did it anyway.
    • mypy beartype.typing.Protocol compatibility. The @beartype-specific beartype.typing.Protocol superclass implementing PEP 544-compliant fast caching protocols is now fully compatible with mypy, Python's official static type-checker. Specifically, beartype.typing.Protocol now circumvents:
      • python/mypy#11013 by explicitly annotating the type of its __slots__ as Any.
      • python/mypy#9282 by explicitly setting the typing.TypeVar() bounds parameter to this superclass.
  • PEP 647 compatibility. @beartype now supports arbitrarily complex type narrowing in PEP 647-compliant static type-checkers (e.g., mypy, pyright), resolving issues #164 and #165 kindly submitted in parallel by foxy machine learning gurus @justinchuby (Justin Chuby) and @rsokl (Ryan Soklaski). Thanks to their earnest dedication, @beartype is now believed to be the most fully complete type narrower. Specifically, the return of both the beartype.door.is_bearable() function and corresponding beartype.door.TypeHint.is_bearable() method are now annotated by the PEP 647-compliant typing.TypeGuard[...] type hint under both Python ≥ 3.10 and Python < 3.10 when the optional third-party typing_extensions dependency is installed. Doing so substantially reduces false positives from static type checkers on downstream codebases deferring to these callables. Thanks so much for improving @beartype so much, @justinchuby and @rsokl!
  • @{classmethod,staticmethod,property} chaining. The @beartype decorator now implicitly supports callables decorated by both @beartype and one of the builtin method decorators @classmethod, @staticmethod, or @property regardless of decoration order, resolving issue #80 kindly requested by @qiujiangkun (AKA, Type Genius-kun). Previously, @beartype explicitly raised an exception when ordered after one of those builtin method decorators. This releseae relaxes this constraint, enabling callers to list @beartype either before or after one of those builtin method decorators.
  • beartype.vale.Is[...] integration. Functional validators (i.e., beartype.vale.Is[...]) now integrate more cleanly with the remainder of the Python ecosystem, including:
    • IPython. Functional validators localized to a sufficiently intelligent REPL (e.g., IPython) that caches locally defined callables to the standard linecache module now raise human-readable errors on type-checking, resolving issue #123 kindly submitted by typing brain-child @braniii. Relatedly, @beartype now permissively accepts both physical on-disk files and dynamic in-memory fake files cached with linecache as the files defining an arbitrary callable.
    • NumPy, which publishes various bool-like tester functions (i.e., functions returning a non-bool object whose class defines at least one of the __bool__() or __len__() dunder methods and is thus implicitly convertible into a bool). Functional validators now support subscription by these functions, resolving issue #153 kindly submitted by molecular luminary @braniii (Daniel Nagel). Specifically, @beartype now unconditionally wraps all tester callables subscripting (indexing) beartype.vale.Is with a new private _is_valid_bool() closure that (in order):
      1. Detects when those tester callables return bool-like objects.
      2. Coerces those objects into corresponding bool values.
      3. Returns those bool values instead.
  • Moar fake builtin types.@beartype now detects all known fake builtin types (i.e., C-based types falsely advertising themselves as being builtin and thus not require explicit importation), succinctly resolving issue #158 kindly submitted by the decorous typing gentleman @langfield. Specifically, @beartype now recognizes instances of all of the following as fake builtin types:
    • beartype.cave.AsyncCoroutineCType.
    • beartype.cave.AsyncGeneratorCType.
    • beartype.cave.CallableCodeObjectType.
    • beartype.cave.CallableFrameType.
    • beartype.cave.ClassDictType.
    • beartype.cave.ClassType.
    • beartype.cave.ClosureVarCellType.
    • beartype.cave.EllipsisType.
    • beartype.cave.ExceptionTracebackType.
    • beartype.cave.FunctionType.
    • beartype.cave.FunctionOrMethodCType.
    • beartype.cave.GeneratorCType.
    • beartype.cave.MethodBoundInstanceDunderCType.
    • beartype.cave.MethodBoundInstanceOrClassType.
    • beartype.cave.MethodDecoratorBuiltinTypes.
    • beartype.cave.MethodUnboundClassCType.
    • beartype.cave.MethodUnboundInstanceDunderCType.
    • beartype.cave.MethodUnboundInstanceNondunderCType.
    • beartype.cave.MethodUnboundPropertyNontrivialCExtensionType.
    • beartype.cave.MethodUnboundPropertyTrivialCExtensionType.

Compatibility Broken

  • Python 3.6.x support dropped. This release unilaterally drops support for the Python 3.6.x series, which somnambulantly collided with its End-of-Life (EOL) a year ago and now constitutes a compelling security risk. Doing so substantially streamlines the codebase, whose support for Python 3.6.x required an unmaintainable writhing nest of wicked corner cases. We all now breathe a sigh of contentment in the temporary stillness of morning.
  • beartype.cave deprecation removals. This release removes all deprecated third-party attributes from the beartype.cave submodule. The continued existence of these attributes substantially increased the cost of importing anything from our mostly undocumented beartype.cave submodule, rendering that submodule even less useful than it already is. Specifically, this release removes these previously deprecated attributes:
    • beartype.cave.NumpyArrayType.
    • beartype.cave.NumpyScalarType.
    • beartype.cave.SequenceOrNumpyArrayTypes.
    • beartype.cave.SequenceMutableOrNumpyArrayTypes.
    • beartype.cave.SetuptoolsVersionTypes.
    • beartype.cave.VersionComparableTypes.
    • beartype.cave.VersionTypes.

Exceptions Improved

  • Colour – the sensation formerly known as "color." @beartype now emits colourized type-checking violations (i.e., beartype.roar.BeartypeCallHintViolation exceptions) raised by both @beartype-decorated callables and statement-level type-checkers (e.g., beartype.door.die_if_unbearable(), beartype.door.TypeHint.die_if_unbearable()), resolving issue #161 kindly submitted by foxy machine learning expert @justinchuby (Justin Chu). When standard output is attached to an interactive terminal (TTY), ANSII-flavoured colours now syntactically highlight various substrings of those violations for improved visibility, readability, and debuggability. Since all actively maintained versions of Windows (i.e., Windows ≥ 10) now widely support ANSII escape sequences across both Microsoft-managed terminals (e.g., Windows Terminal) and Microsoft-managed Integrated Development Environments (IDEs) (e.g., VSCode), this supports extends to Windows as well. The bad old days of non-standard behaviour are behind us all. Thanks so much to @justinchuby for his immense contribution to the righteous cause of eye-pleasing user experience (UX)!
  • Types disambiguated. @beartype now explicitly disambiguates the types of parameters and returns that violate type-checking in exception messages raised by the @beartype decorator, resolving issue #124 kindly submitted by typing brain-child @braniii. Thus was justice restored to the QAverse.
  • Stack frame squelched. @beartype now intentionally squelches (i.e., hides) the ignorable stack frame encapsulating the call to our private beartype._decor._error.errormain.get_beartype_violation() getter from the parent type-checking wrapper function generated by the :mod:beartype.beartype decorator, resolving issue #140 kindly submitted by @langfield (William Blake – yes, that William Blake). That stack frame only needlessly complicated visual inspection of type-checking violations in tracebacks – especially from testing frameworks like :mod:pytest that recapitulate the full definition of the get_beartype_violation() getter (including verbose docstring) in those tracebacks. Specifically, this release:
    • Renamed the poorly named raise_pep_call_exception() function to get_beartype_violation() for clarity.
    • Refactored get_beartype_violation() to return rather than raise BeartypeCallHintViolation exceptions (while still raising all other types of unexpected exceptions for robustness).
    • Refactored type-checking wrapper functions to directly raise the exception returned by calling get_beartype_violation().
  • None type. The type of the None singleton is no longer erroneously labelled as a PEP 544-compliant protocol in type-checking violations. Let's pretend that never happened.
  • beartype.abby.die_if_unbearable() violations. The beartype.abby.die_if_unbearable() validator function no longer raises non-human-readable exception messages prefixed by the unexpected substring "@beartyped beartype.abby._abbytest._get_type_checker._die_if_unbearable() return". "Surely that never happened, @beartype!"

Features Added

  • beartype.door. @beartype now provides a new public framework for introspecting, sorting, and type-checking type hints at runtime in constant time. N-n-now... hear me out here. @leycec came up with a ludicrous acronym and we're going to have to learn to live with it: the Decidedly Object-Orientedly Recursive (DOOR) API. Or, beartype.door for short. Open the door to a whole new type-hinting world, everyone. beartype.door enables type hint arithmetic via an object-oriented type hint class hierarchy encapsulating the crude non-object-oriented type hint declarative API standardized by the typing module, resolving issues #133 and 138 kindly submitted by Harvard microscopist and general genius @tlambert03. The new beartype.door subpackage defines a public:
    • TypeHint({type_hint}) superclass, enabling rich comparisons between pairs of arbitrary type hints. Altogether, this class implements a partial ordering over the countably infinite set of all type hints. Pedagogical excitement ensues. Instances of this class efficiently satisfy both the collections.abc.Sequence and collections.abc.FrozenSet abstract base classes (ABC) and thus behave just like tuples and frozen sets over child type hints. Public attributes defined by this class include:
      • A pair of die_if_unbearable() and is_bearable() runtime type-checking methods, analogous in behaviour to the existing beartype.abby.die_if_unbearable() and beartype.abby.is_bearable() runtime type-checking functions.
      • TypeHint.is_bearable(), currently implemented in terms of the procedural beartype.abby.is_bearable() tester.
      • An is_ignorable property evaluating to True only if the current type hint is semantically ignorable (e.g., object, typing.Any). There exist a countably infinite number of semantically ignorable type hints. The more you know, the less you want to read this changeset.
      • The equality comparison operator (e.g., ==), enabling type hints to be compared according to semantic equivalence.
      • Rich comparison operators (e.g., <=, >), enabling type hints to be compared and sorted according to semantic narrowing.
      • A sane __bool__() dunder method, enabling type hint wrappers to be trivially evaluated as booleans according to the child type hints subscripting the wrapped type hints.
      • A sane __len__() dunder method, enabling type hint wrappers to be trivially sized according to the child type hints subscripting the wrapped type hints.
      • A sane __contains__() dunder method, enabling type hint wrappers to be tested for child type hint membership – just like builtin sets, frozen sets, and dictionaries.
      • A sane __getindex__() dunder method, enabling type hint wrappers to be subscripted by both positive and negative indices as well as slices of such indices – just like builtin tuples.
    • beartype.door.AnnotatedTypeHint subclass.
    • beartype.door.CallableTypeHint subclass.
    • beartype.door.LiteralTypeHint subclass.
    • beartype.door.NewTypeTypeHint subclass.
    • beartype.door.TupleTypeHint subclass.
    • beartype.door.TypeVarTypeHint subclass.
    • beartype.door.UnionTypeHint subclass.
    • is_subtype({type_hint_a}, {type_hint_b}) function, enabling @beartype users to decide whether any type hint is a subtype (i.e., narrower type hint) of any other type hint.
    • beartype.roar.BeartypeDoorNonpepException type, raised when the beartype.door.TypeHint constructor is passed an object that is not a PEP-compliant type hint currently supported by the DOOR API.
      Thanks so much to @tlambert03 for his phenomenal work here. He ran GitHub's PR gauntlet so that you did not have to. Praise be to him. Some people are the living embodiment of quality. @tlambert03 is one such people.
  • beartype.peps. @beartype now publicizes runtime support for typing-centric Python Enhancement Proposals (PEPs) that currently lack official runtime support via a new public subpackage: beartype.peps. Notably, @beartype now provides:
    • A new public beartype.peps.resolve_pep563() function resolving PEP 563-postponed type hints on behalf of third-party Python packages. This function is intended to be "the final word" on runtime resolution of PEP 563. May no other third-party package suffer as we have suffered. This commit is for you, everyone. And "by everyone," we of course mostly mean @wesselb of Plum fame. See also beartype/plum#53.
  • beartype.vale.Is*[...] {&,|} short-circuiting. &- and |-chained beartype validators now explicitly short-circuit when raising human-readable exceptions from type-checking violations against those validators, resolving issue #125 kindly submitted by typing brain-child @braniii.

Features Optimized

  • beartype.abby.is_bearable() when returning False. Previously, the public beartype.abby.is_bearable() runtime type-checker behaved reasonably optimally when the passed object satisfied the passed type hint but extremely suboptimally when that object violated that hint; this was due to our current naive implementation of that tester using the standard Easier to Ask for Permission than Forgiveness (EAFP) approach. This release fundamentally refactored beartype.abby.is_bearable() in terms of our new private beartype._check.checkmake.make_func_tester() type-checking tester function factory function. Ad-hoc profiling shows a speedup on the order of eight orders of magnitude – the single most intense optimization @beartype has ever brought to bear (heh). Our core code generation API now transparently generates both:
    • Runtime type-checking testers (i.e., functions merely returning False on type-checking violations).
    • Runtime type-checking validators (i.e., functions raising exceptions on type-checking violations).
  • PEP 604-compliant new unions (e.g., int | str | None). Since these unions are non-self-caching type hints (i.e., hints that do not implicitly cache themselves to reduce space and time consumption), @beartype now efficiently coerces these unions into singletons in the same manner as PEP 585-compliant type hints – which are similarly non-self-caching.

Features Deprecated

  • beartype.abbybeartype.door. This release officially deprecates the poorly named beartype.abby subpackage in favour of the sorta less poorly named beartype.door subpackage, whose name actually means something – even if that something is a punny acronym no one will ever find funny. Specifically:
    • beartype.abby.die_if_unbearable() has been moved to beartype.door.die_if_unbearable().
    • beartype.abby.is_bearable() has been moved to beartype.door.is_bearable().
      To preserve backward compatibility, the beartype.abby subpackage continues to dynamically exist (and thus be importable from) – albeit as a deprecated alias of the beartype.door subpackage.

Deprecations Resolved

  • Setuptools licensing. This release resolves a mostly negligible setuptools deprecation warning concerning the deprecated license_file setting in the top-level setup.cfg file. Next!

Tests Improved

  • PEP 544 compatibility. All PEP 544-specific test type hints have been generalized to apply to both the non-caching typing.Protocol superclass and our caching beartype.typing.Protocol superclass.
  • PEP 561 compatibility via pyright. Our test suite now enforces static type-checking with pyright. Notably:
    • A new test_pep561_pyright functional test statically type-checks the @beartype codebase against the external pyright command in the current ${PATH} (if available) specific to the version of the active Python interpreter currently being tested. For personal sanity, this test is currently ignored on remote continuous integration (CI) workflows. Let this shrieking demon finally die!
    • The private beartype_test.util.cmd.pytcmdrun submodule underlying our cross-platform portable forking of testing subprocesses now transparently supports vanilla Windows shells (e.g., CMD.exe, PowerShell).
  • Tarball compatibility. beartype may now be fully tested from non-git repositories, including source tarballs containing the beartype_test package. Previously, three functional tests making inappropriate assumptions about the existence of a top-level .git/ directory failed when exercised from a source tarball.
  • Sphinx documentation. Our test suite now exercises that our documentation successfully builds with Sphinx via a new test_sphinx_build() functional test. This was surprisingly non-trivial – thanks to the pytest-specific sphinx.testing subpackage being mostly undocumented, behaving non-orthogonally, and suffering a host of unresolved issues that required we monkey-patch the core pathlib.Path class. Insanity, thy name is Sphinx.
  • GitHub Actions dependencies bumped. This release bumps our GitHub Actions-based continuous integration (CI) workflows to both the recently released checkout@v3 and setup-python@v3 actions, inspired by a pair of sadly closed PRs by @RotekHandelsGmbH CTO @bitranox (Robert Nowotny). Thanks so much for the great idea, @bitranox!
  • beartype.door conformance. A new smoke test guarantees conformance between our DOOR API and abstract base classes (ABCs) published by the standard typing module.
  • python/mypy#13627 circumvention. This release pins our GitHub Actions-based CI workflow to Python 3.10.6 rather than 3.10.7, resolving a mypy-specific complaint inducing spurious test failures.

Documentation Improved

  • beartype.abby documented. The new "Beartype At Any Time API" subsection of our front-facing README.rst file now documents our public beartype.abby API, resolving issue #139 kindly submitted by @gelatinouscube42 (i.e., the user whose username is the answer to the question: "What is the meaning of collagen sustainably harvested from animal body parts?").
  • GitHub Sponsors activated. @beartype is now proudly financially supported by GitHub Sponsors. Specifically, this release:
    • Defines a new GitHub-specific funding configuration (i.e., .github/FUNDING.yml).
    • Injects a hopefully non-intrusive advertising template gulp at the head of our README.rst documentation.
  • Sphinx configuration sanitized. As the first tentative step towards chain refactoring our documentation from its current monolithic home in our top-level README.rst file to its eventual modular home at ReadTheDocs (RTD), en-route to resolving issue #8 (!) kindly submitted a literal lifetime ago by visionary computer vision export and long-standing phenomenal Finn @felix-hilden (Felix Hildén):
    • Our core Sphinx configuration has been resurrected from its early grave – which now actually builds nothing without raising errors. Is this an accomplishment? In 2022, mere survival is an accomplishment! So... yes. Significant improvements include:
      • Activation and configuration of the effectively mandatory autosectionlabels builtin Sphinx extension.
    • Our doc/source/404.rst file has been temporarily moved aside, resolving a non-fatal warning pertaining to that file. Look, we're not here to actually solve deep issues; we're here to just get documentation building, which it's not. Sphinx, you have much to answer for.
    • Our top-level sphinx entry point now:
      • Temporarily disables Sphinx's nit-picky mode (i.e., the -n option previously passed to sphinx-build) due to Sphinx's autodoc extension locally failing to generate working references.
      • Unconditionally disables Sphinx caching by forcing all target documentation files to be rebuilt regardless of whether their underlying source files have since been modified or not, obviating spurious build issues.

(Impossible journey on an implacable placard-studded gurney!)

Don't miss a new beartype release

NewReleases is sending notifications on new releases.