github beartype/beartype v0.7.0
beartype refs/tags/v0.7.0

latest releases: v0.18.5, v0.18.4, v0.18.3...
3 years ago

Beartype 0.7.0 released.

This release brings titillating support for beartype validators, Python 3.10, PEP 563 – "Postponed Evaluation of Annotations", and PEP 586 – "Literal Types".

This release resolves 4 outstanding issues and merges 1 pending pull request. Significant changes include:

Features Added

  • Beartype validators, the world's first PEP-compliant validation API. Validate anything with two-line type hints designed by you, built by the @beartype decorator for you. The new public beartype.vale subpackage enables beartype users to design their own PEP-compliant type hints enforcing arbitrary runtime constraints on the internal structure and contents of parameters and returns via user-defined lambda functions and nestable declarative expressions leveraging familiar typing syntax – all seamlessly composable with standard type hints through an expressive domain-specific language (DSL). Specifically, @beartype-decorated callables may now be annotated by type hints of the form typing.Annotated[{cls}, beartype.vale.Is[lambda obj: {test_expr1}], ..., beartype.vale.Is[lambda obj: {test_exprN}]], where:
    • {cls} is any arbitrary class (e.g., str, numpy.ndarray).
    • {test_expr1} and {test_exprN} are any arbitrary expressions evaluating to booleans (e.g., len(obj) <= 80, obj.dtype == np.dtype(np.float64)).
      beartype.vale.Is may also be subscripted (indexed) by non-lambda callables with similar signatures. For convenience, beartype.vale.Is objects support a rich domain-specific language (DSL) enabling new validators to be synthesized from existing validators with Pythonic set operators:
    • Negation with ~beartype.vale.Is[lambda obj: {test_expr}], equivalent to
      beartype.vale.Is[lambda obj: not {test_expr}].
    • And-ing with beartype.vale.Is[lambda obj: {test_expr1}] & beartype.vale.Is[lambda obj: {test_expr2}], equivalent to beartype.vale.Is[lambda obj: {test_expr1} and {test_expr2}].
    • Or-ing with beartype.vale.Is[lambda obj: {test_expr1}] | beartype.vale.Is[lambda obj: {test_expr2}], equivalent to beartype.vale.Is[lambda obj: {test_expr1} or {test_expr2}].
      This syntax fully complies with PEP 593 and thus requires Python ≥ 3.9. See Beartype validators for full usage instructions, complete with real-world examples including tensors. Rejoice machine learning data scientists! This resolves issue #32, kindly submitted by fashionable London steampunk cat pimp @Saphyel (Carlos Jimenez).

Features Optimized

  • Package importation. The first importation of both the beartype package and @beartype decorator has been significantly optimized, now consuming on the order of microseconds rather than milliseconds (or even seconds in the worst case). This critical optimization should significantly improve runtime performance for short-lived CLI applications. Isn't that great, guys? ...guys? awkward cough
  • Wrapper function attributes. The @beartype decorator now generates unconditionally faster type-checking wrapper functions. Previously, attributes accessed in the bodies of those functions were indirectly passed to those functions via a common dictionary singleton referred to as the "beartypistry" directly passed to those functions; while trivial, this approach had the measurable harm of one dictionary lookup for each attribute access in those functions. Now, the same attributes are instead directly passed as optional private beartype-specific parameters to these functions; while non-trivial, this approach has the measurable benefit of avoiding any dictionary lookups by instead localizing all requisite attributes to the signatures of those functions. Of course, this isn't just an optimization; this is also a hard prerequisite for supporting both "PEP 586 -- Literal Types" and beartype validators. The beartypistry singleton remains used only to dynamically resolve forward references to undeclared user types.

Compatibility Improved

  • Python ≥ 3.10.0. @beartype now officially supports Python 3.10, currently in beta but maybe-soon-to-be-released thanks to Python's accelerated release schedule. Python 3.10 significantly broke backwards compatibility with runtime introspection of type hints and thus runtime type checkers, complicating support for Python 3.10 for most runtime type checkers (including us). Specifically, Python 3.10 unconditionally enables "PEP 563 -- Postponed Evaluation of Annotations" – an abysmal standard preferentially improving the efficiency of statically type-checked applications by reducing the efficiency of applications also checked by runtime type checkers. We can only protest with skinny fists lifted like antennas to GitHub. Praise be to Guido.
  • PEP 563 – "Postponed Evaluation of Annotations". While beartype 0.1.1 only partially supported PEP 563, @beartype now fully supports all edge cases associated with PEP 563 – including postponed methods, nested functions, closures, and forward references. Forward references merit particular mention. Why? Because of course, forward references are fundamentally indistinguishable from PEP 563-postponed type hints, because PEP 563 was never intended to be usable at runtime. Unsurprisingly, it isn't. While numerous Python packages superficially support PEP 563 by deferring to the broken typing.get_type_hints() function, @beartype is the first and thus far only annotation-based Python package to fully support PEP 563 and thus Python 3.10.
  • PEP 586 – "Literal Types". The @beartype decorator now fully supports the new typing.Literal type hint introduced by Python ≥ 3.9. Note, however, that beartype validators offer similar but significantly more practical support for type hint-based equality comparison in our new beartype.vale.IsEqual class.

Issues Resolved

  • typing.OrderedDict under Python 3.7.0 and 3.7.1. @beartype now conditionally imports the typing.OrderedDict singleton only if the active Python interpreter targets Python ≥ 3.7.2, the patch release that bizarrely changed the public typing API by introducing this new public attribute. Doing so improves compatibility with both Python 3.7.0 and 3.7.1 and resolves issue #33 – kindly reported by @aiporre, the dancing unicorn that radiates sparkles named Ariel.

Tests Improved

  • Test coverage. The test suite for @beartype now automatically generates test coverage metrics – resolving #20. This includes:
    • Locally via the third-party coverage package (if importable under the active Python interpreter). @beartype intentionally leverages the coverage package directly rather than its higher-level pytest-cov wrapper, as the latter offers no tangible benefits over the former while suffering various tangible harms. These include:
      • Insufficient configurability, preventing us from sanely generating XML-formatted reports via our existing tox.ini configuration.
      • Ambiguous output, preventing us from sanely differentiating expected from unexpected behaviours.
      • Argumentative and strongly opinionated developers, which is frankly never a good look for open-source volunteerism.
    • Remotely via the third-party Codecov.io coverage service, integrated with the codecov/codecov-action now performed on each commit and pull request by our GitHub Actions continuous integration (CI) workflow.
  • Python Development Mode (PDM). The PDM (e.g., -X dev, PYTHONDEVMODE) is now enabled by default under both pytest and tox and thus continuous integration (CI), mildly improving the robustness of our test suite in edge cases that absolutely should never apply (e.g., GIL and memory safety violations) but probably will, because bad things always happen to good coders. It's, like, a law.

Documentation Revised

  • See Also. The See Also section of our front-facing README.rst
    documentation has been significantly expanded with:
    • A comparative review of all known runtime type checkers.
    • A new Runtime Data Validators subsection enumerating all known runtime validation (e.g., contract, trait) packages.

(Winsome winners ransom random dendritic endoscopy!)

Don't miss a new beartype release

NewReleases is sending notifications on new releases.