Skip to content

Commit

Permalink
"typing_extensions.Annotated" x 19.
Browse files Browse the repository at this point in the history
This commit is the next in a commit chain adding transparent support
for the third-party `typing_extensions.Annotated` type hint back-ported
to Python < 3.9, en route to resolving #34. Once finalized, this will
enable usage of beartype validators under Python < 3.9 via this hint.
Specifically, this commit continues disastrously breaking literally
everything by continuing to disembowel the feckless
`beartype._util.hint.data.pep.datapep` submodule and its untrustworthy
`beartype._util.hint.data.pep.proposal` crony subpackage in favour of
`beartype._util.hint.data.pep.sign`, which is the only subpackage left
standing. Save us from our reckless selves, GitHub! (*Stubby tubers!*)
  • Loading branch information
leycec committed Jul 14, 2021
1 parent 42d813d commit b143af5
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 281 deletions.
39 changes: 23 additions & 16 deletions beartype/_decor/_cache/cachehint.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
#Checkmate, "typing". Checkmate.

# ....................{ IMPORTS }....................
from beartype._cave._cavefast import NotImplementedType
from beartype._cave._cavefast import NotImplementedType, NoneType
from beartype._util.hint.utilhinttest import die_unless_hint
from beartype._util.data.func.datafunc import METHOD_NAMES_BINARY_DUNDER
from collections.abc import Callable
Expand All @@ -67,13 +67,13 @@
This dictionary caches:
* `PEP 585`_-compliant type hints, which do *not* cache themselves.
* `PEP 563`_-compliant **deferred type hints** (i.e., type hints persisted as
* :pep:`585`-compliant type hints, which do *not* cache themselves.
* :pep:`563`-compliant **deferred type hints** (i.e., type hints persisted as
evaluatable strings rather than actual type hints), enabled if the active
Python interpreter targets either:
* Python 3.7.0 *and* the module declaring this callable explicitly enables
`PEP 563`_ support with a leading dunder importation of the form ``from
:pep:`563` support with a leading dunder importation of the form ``from
__future__ import annotations``.
* Python 4.0.0, where `PEP 563`_ is expected to be mandatory.
Expand All @@ -99,11 +99,6 @@
instead persisted for the lifetime of the active Python process. Ergo,
temporarily caching hints in an LRU cache is pointless, as there are *no*
space savings in dropping stale references to unused hints.
.. _PEP 563:
https://www.python.org/dev/peps/pep-0563
.. _PEP 585:
https://www.python.org/dev/peps/pep-0585
'''

# ....................{ CACHERS }....................
Expand Down Expand Up @@ -178,15 +173,25 @@ def coerce_hint_pep(
# Original instance of this hint *PRIOR* to being subsequently coerced.
hint_old = hint

# ..................{ PEP 484 }..................
# If this hint is the PEP 484-compliant "None" singleton, coerce this hint
# into the type of that singleton. This is explicitly required by PEP 484
# *and* implicitly required by Python convention, where the bodies of
# callables annotated as returning "None" are understood to contain *no*
# explicit "return" statements and thus implicitly return "None".
if hint is None:
hint = NoneType
# Else, this hint is *NOT* the PEP 484-compliant "None" singleton.
#
# ..................{ MYPY }..................
# If...
if (
elif (
# This hint annotates the return for the decorated callable *AND*...
pith_name == 'return' and
# The decorated callable is a binary dunder method (e.g., __eq__())...
func.__name__ in METHOD_NAMES_BINARY_DUNDER
):
# Expand this hint to accept both booleans *AND* the "NotImplemented"
# Expand this hint to accept both this hint *AND* the "NotImplemented"
# singleton as valid returns from this method. Why? Because this
# expansion has been codified by mypy and is thus a de-facto typing
# standard, albeit one currently lacking formal PEP standardization.
Expand Down Expand Up @@ -231,16 +236,18 @@ def coerce_hint_pep(
# this edge case by effectively performing the same type expansion as
# performed here. *applause*
hint = Union[hint, NotImplementedType]
# Else, this hint is *NOT* the mypy-compliant "NotImplemented" singleton.
#
# ..................{ NON-PEP }..................
# If this hint is a PEP-noncompliant tuple union...
# If this hint is a PEP-noncompliant tuple union, coerce this union into
# the equivalent PEP-compliant union subscripted by the same child hints.
# By definition, PEP-compliant unions are a superset of PEP-noncompliant
# tuple unions and thus accept all child hints accepted by the latter.
elif isinstance(hint, tuple):
# Coerce this union into the equivalent PEP-compliant union subscripted
# by the same child hints. By definition, PEP-compliant unions are a
# strict superset of PEP-noncompliant tuple unions and thus accept all
# child hints accepted by the latter.
hint = Union.__getitem__(hint)
# Else, this hint is *NOT* a PEP-noncompliant tuple union.

# ..................{ COERCION }..................
# If this hint was coerced above into a different instance, replace the
# original instance of this hint in the annotations dunder dictionary
# attached to the decorated callable with the new instance of this hint.
Expand Down
21 changes: 6 additions & 15 deletions beartype/_decor/_code/_pep/_pephint.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,6 @@
release_object_typed,
)
from beartype._util.data.hint.datahint import HINTS_IGNORABLE_SHALLOW
from beartype._util.data.hint.pep.datapep import (
HINT_SIGNS_SUPPORTED_DEEP as HINT_SIGNS_SUPPORTED_DEEP_BAD,
HINT_SIGNS_TYPE_STDLIB,
)
from beartype._util.data.hint.pep.proposal.datapep484 import (
HINT_PEP484_SIGNS_UNION)
from beartype._util.data.hint.pep.datapepattr import (
HINT_PEP586_ATTR_LITERAL,
HINT_PEP593_ATTR_ANNOTATED,
Expand All @@ -106,6 +100,7 @@
HINT_SIGNS_SEQUENCE_ARGS_1,
HINT_SIGNS_SUPPORTED_DEEP,
HINT_SIGNS_TYPE_STDLIB,
HINT_SIGNS_UNION,
)
from beartype._util.func.utilfuncscope import (
CallableScope,
Expand Down Expand Up @@ -1050,9 +1045,9 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
# for that attribute *MUST* also be added to the parallel:
# * "beartype._util.hint.pep.errormain" submodule, which
# raises exceptions on the current pith failing this check.
# * "beartype._util.data.hint.pep.datapep.HINT_SIGNS_SUPPORTED_DEEP"
# frozen set of all supported unsubscripted "typing" attributes
# for which this function generates deeply type-checking code.
# * "beartype._util.data.hint.pep.sign.datapepsignset.HINT_SIGNS_SUPPORTED_DEEP"
# frozen set of all signs for which this function generates
# deeply type-checking code.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#FIXME: Python 3.10 provides proper syntactic support for "case"
Expand Down Expand Up @@ -1115,7 +1110,7 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
# benefit from Python >= 3.8-specific assignment expressions. This
# differs from "typing" pseudo-containers, which narrow the current
# pith expression and thus do benefit from these expressions.
if hint_curr_sign in HINT_PEP484_SIGNS_UNION:
if hint_curr_sign in HINT_SIGNS_UNION:
# Assert this union is subscripted by one or more child hints.
# Note this should *ALWAYS* be the case, as:
#
Expand Down Expand Up @@ -1333,11 +1328,7 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
#FIXME: Remove this branch *AFTER* deeply supporting all
#hints.
# Currently unsupported with deep type-checking...
(
hint_curr_sign not in HINT_SIGNS_SUPPORTED_DEEP and
#FIXME: Remove this shuddering horror after refactoring!
hint_curr_sign not in HINT_SIGNS_SUPPORTED_DEEP_BAD
)
hint_curr_sign not in HINT_SIGNS_SUPPORTED_DEEP
)
):
# Then generate trivial code shallowly type-checking the current
Expand Down
4 changes: 1 addition & 3 deletions beartype/_decor/_error/errormain.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@
get_cause_or_none_literal)
from beartype._decor._error._proposal._errorpep593 import (
get_cause_or_none_annotated)
from beartype._util.data.hint.pep.datapep import (
HINT_SIGNS_TYPE_STDLIB,
)
from beartype._util.data.hint.pep.proposal.datapep484 import (
HINT_PEP484_SIGNS_UNION)
from beartype._util.data.hint.pep.sign.datapepsigns import (
Expand All @@ -103,6 +100,7 @@
)
from beartype._util.data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1,
HINT_SIGNS_TYPE_STDLIB,
)
from beartype._util.hint.utilhinttest import die_unless_hint
from beartype._util.py.utilpyversion import IS_PYTHON_AT_LEAST_3_9
Expand Down
26 changes: 0 additions & 26 deletions beartype/_util/data/hint/datahint.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
'''

# ....................{ IMPORTS }....................
from beartype._util.data.hint.pep.datapep import HINT_PEP_ATTRS_IGNORABLE
from beartype._util.data.hint.pep.proposal.datapep484 import (
HINT_PEP484_TYPE_FORWARDREF)

Expand Down Expand Up @@ -40,28 +39,3 @@
such that all type hints forward referencing user-defined types are instances
of these superclasses).
'''


HINTS_IGNORABLE_SHALLOW = HINT_PEP_ATTRS_IGNORABLE | {
# The PEP-noncompliant builtin "object" type is the transitive superclass
# of all classes, parameters and return values annotated as "object"
# unconditionally match *ALL* objects under isinstance()-based type
# covariance and thus semantically reduce to unannotated parameters and
# return values. This is literally the "beartype.cave.AnyType" type.
object,
}
'''
Frozen set of all **shallowly ignorable type hints** (i.e., annotations
unconditionally ignored by the :func:`beartype.beartype` decorator).
Caveats
----------
**The high-level**
:func:`beartype._util.hint.pep.utilhinttest.is_hint_ignorable` **tester
function should always be called in lieu of testing type hints against this
low-level set.** This set is merely shallow and thus excludes **deeply
ignorable type hints** (e.g., :data:`Union[Any, bool, str]`). Since there exist
a countably infinite number of deeply ignorable type hints, this set is
necessarily constrained to the substantially smaller finite subset of only
shallowly ignorable type hints.
'''
14 changes: 0 additions & 14 deletions beartype/_util/data/hint/pep/datapepmap.py

This file was deleted.

0 comments on commit b143af5

Please sign in to comment.