Skip to content

Commit

Permalink
"typing_extensions.Annotated" x 15.
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 disastrously breaks literally everything by
finally committing to this refactoring by disemboweling 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. Since everything is now broken, we can only devoutly pray for
a miraculously swift and just refactoring. (*Untimely turntables!*)
  • Loading branch information
leycec committed Jul 14, 2021
1 parent 62ea63d commit 05a09dc
Show file tree
Hide file tree
Showing 21 changed files with 635 additions and 888 deletions.
4 changes: 2 additions & 2 deletions beartype/_decor/_code/_pep/_pephint.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
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_SEQUENCE_ARGS_ONE,
HINT_SIGNS_TYPE_ORIGIN_STDLIB,
)
from beartype._util.data.hint.pep.proposal.datapep484 import (
Expand All @@ -104,6 +103,7 @@
HintSignTuple,
)
from beartype._util.data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1,
HINT_SIGNS_SUPPORTED_DEEP,
HINT_SIGNS_TYPE_STDLIB,
)
Expand Down Expand Up @@ -1364,7 +1364,7 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
# If this hint is either...
elif (
# A standard sequence (e.g., "typing.List[int]") *OR*...
hint_curr_sign in HINT_SIGNS_SEQUENCE_ARGS_ONE or (
hint_curr_sign in HINT_SIGNS_SEQUENCE_ARGS_1 or (
# A tuple *AND*...
hint_curr_sign is HintSignTuple and
# This tuple is subscripted by exactly two child hints
Expand Down
13 changes: 6 additions & 7 deletions beartype/_decor/_error/_errorsequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
# ....................{ IMPORTS }....................
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._decor._error._errortype import get_cause_or_none_type_stdlib
from beartype._util.data.hint.pep.datapep import (
HINT_SIGNS_SEQUENCE_ARGS_ONE,
)
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignTuple
from beartype._util.data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1)
from beartype._util.hint.pep.utilhintpeptest import is_hint_pep_tuple_empty
from beartype._util.hint.utilhinttest import is_hint_ignorable
from beartype._util.text.utiltextrepr import represent_object
Expand All @@ -27,7 +26,7 @@
__all__ = ['STAR_IMPORTS_CONSIDERED_HARMFUL']

# ....................{ GETTERS ~ sequence }....................
def get_cause_or_none_sequence_standard(sleuth: CauseSleuth) -> Optional[str]:
def get_cause_or_none_sequence_args_1(sleuth: CauseSleuth) -> Optional[str]:
'''
Human-readable string describing the failure of the passed arbitrary object
to satisfy the passed **PEP-compliant standard sequence type hint** (i.e.,
Expand All @@ -44,7 +43,7 @@ def get_cause_or_none_sequence_standard(sleuth: CauseSleuth) -> Optional[str]:
Type-checking error cause sleuth.
'''
assert isinstance(sleuth, CauseSleuth), f'{repr(sleuth)} not cause sleuth.'
assert sleuth.hint_sign in HINT_SIGNS_SEQUENCE_ARGS_ONE, (
assert sleuth.hint_sign in HINT_SIGNS_SEQUENCE_ARGS_1, (
f'{repr(sleuth.hint)} not standard sequence hint.')

# Assert this sequence was subscripted by exactly one argument. Note that
Expand Down Expand Up @@ -191,14 +190,14 @@ def _get_cause_or_none_sequence(sleuth: CauseSleuth) -> Optional[str]:
Type-checking error cause sleuth.
'''
# Assert this type hint to describe a variadic sequence. See the parent
# get_cause_or_none_sequence_standard() and get_cause_or_none_tuple()
# get_cause_or_none_sequence_args_1() and get_cause_or_none_tuple()
# functions for derivative logic.
#
# Note that this pith need *NOT* be validated to be an instance of the
# expected variadic sequence, as the caller guarantees this to be the case.
assert isinstance(sleuth, CauseSleuth), f'{repr(sleuth)} not cause sleuth.'
assert (
sleuth.hint_sign in HINT_SIGNS_SEQUENCE_ARGS_ONE or (
sleuth.hint_sign in HINT_SIGNS_SEQUENCE_ARGS_1 or (
sleuth.hint_sign is HintSignTuple and
len(sleuth.hint_childs) == 2 and
sleuth.hint_childs[1] is Ellipsis
Expand Down
4 changes: 2 additions & 2 deletions beartype/_decor/_error/_errorsleuth.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ def get_cause_or_none(self) -> Optional[str]:
and the list ``list(range(256)) + [False,]`` consisting of the integers
0 through 255 followed by boolean ``False``. Since this list is a
standard sequence, the
:func:`._peperrorsequence.get_cause_or_none_sequence_standard`
:func:`._peperrorsequence.get_cause_or_none_sequence_args_1`
function must decide the cause of this list's failure to comply with
this hint by finding the list item that is neither an integer nor a
string, implemented by by iteratively passing each list item to the
:func:`._peperrorunion.get_cause_or_none_union` function. Since
the first 256 items of this list are integers satisfying this hint,
:func:`._peperrorunion.get_cause_or_none_union` returns
``None`` to
:func:`._peperrorsequence.get_cause_or_none_sequence_standard`
:func:`._peperrorsequence.get_cause_or_none_sequence_args_1`
before finally finding the non-compliant boolean item and returning the
human-readable cause.
Expand Down
12 changes: 7 additions & 5 deletions beartype/_decor/_error/errormain.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
from beartype._decor._error._errorgeneric import (
get_cause_or_none_generic)
from beartype._decor._error._errorsequence import (
get_cause_or_none_sequence_standard,
get_cause_or_none_sequence_args_1,
get_cause_or_none_tuple,
)
from beartype._decor._error._errorsleuth import CauseSleuth
Expand All @@ -92,7 +92,6 @@
from beartype._decor._error._proposal._errorpep593 import (
get_cause_or_none_annotated)
from beartype._util.data.hint.pep.datapep import (
HINT_SIGNS_SEQUENCE_ARGS_ONE,
HINT_SIGNS_TYPE_ORIGIN_STDLIB,
)
from beartype._util.data.hint.pep.proposal.datapep484 import (
Expand All @@ -102,6 +101,9 @@
HintSignGeneric,
HintSignTuple,
)
from beartype._util.data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1,
)
from beartype._util.hint.utilhinttest import die_unless_hint
from beartype._util.py.utilpyversion import IS_PYTHON_AT_LEAST_3_9
from beartype._util.text.utiltextlabel import (
Expand Down Expand Up @@ -346,9 +348,9 @@ def _init() -> None:
get_cause_or_none_type_stdlib)

# Map each standard sequence "typing" attribute to the appropriate getter.
for pep_sign_sequence_standard in HINT_SIGNS_SEQUENCE_ARGS_ONE:
PEP_HINT_SIGN_TO_GET_CAUSE_FUNC[pep_sign_sequence_standard] = (
get_cause_or_none_sequence_standard)
for pep_sign_sequence_args_1 in HINT_SIGNS_SEQUENCE_ARGS_1:
PEP_HINT_SIGN_TO_GET_CAUSE_FUNC[pep_sign_sequence_args_1] = (
get_cause_or_none_sequence_args_1)

# Map each unifying "typing" attribute to the appropriate getter.
for pep_sign_type_union in HINT_PEP484_SIGNS_UNION:
Expand Down
192 changes: 12 additions & 180 deletions beartype/_util/data/hint/pep/datapep.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,24 @@
# ....................{ IMPORTS }....................
from beartype._util.data.hint.pep.proposal.datapep484 import (
HINT_PEP484_ATTRS_DEPRECATED,
HINT_PEP484_ATTRS_IGNORABLE,
HINT_PEP484_SIGNS_SEQUENCE_STANDARD,
HINT_PEP484_SIGNS_SUPPORTED_DEEP,
HINT_PEP484_SIGNS_SUPPORTED_SHALLOW,
HINT_PEP484_ATTRS_ISINSTANCEABLE,
HINT_PEP484_SIGNS_TYPE_ORIGIN,
# HINT_PEP484_ATTRS_ISINSTANCEABLE,
)
from beartype._util.data.hint.pep.proposal.datapep544 import (
HINT_PEP544_ATTRS_IGNORABLE,
HINT_PEP544_SIGNS_SUPPORTED_DEEP,
)
from beartype._util.data.hint.pep.proposal.datapep585 import (
HINT_PEP585_SIGNS_SEQUENCE_STANDARD,
HINT_PEP585_SIGNS_SUPPORTED_DEEP,
HINT_PEP585_ATTRS_ISINSTANCEABLE,
)
from beartype._util.data.hint.pep.proposal.datapep586 import (
HINT_PEP586_SIGNS_SUPPORTED_DEEP)
from beartype._util.data.hint.pep.proposal.datapep593 import (
HINT_PEP593_SIGNS_SUPPORTED_DEEP)
from beartype._util.lib.utilliboptional import IS_LIB_TYPING_EXTENSIONS
# from beartype._util.data.hint.pep.proposal.datapep585 import (
# HINT_PEP585_ATTRS_ISINSTANCEABLE,
# )

# See the "beartype.cave" submodule for further commentary.
__all__ = ['STAR_IMPORTS_CONSIDERED_HARMFUL']

# ....................{ MODULES }....................
HINT_PEP_MODULE_NAMES = frozenset(
(
# Name of the official typing module bundled with the Python stdlib.
'typing',
) + (
# If the third-party "typing_extensions" module backporting "typing"
# hints introduced in newer Python versions to older Python versions is
# importable under the active Python interpreter, a 1-tuple of the name
# of that module;
('typing_extensions',)
if IS_LIB_TYPING_EXTENSIONS else
# Else, the empty tuple.
()
)
)
HINT_PEP_MODULE_NAMES = frozenset((
# Name of the official typing module bundled with the Python stdlib.
'typing',

# Name of the third-party "typing_extensions" module backporting "typing"
# hints introduced in newer Python versions to older Python versions.
'typing_extensions',
))
'''
Frozen set of the unqualified names of all top-level **hinting modules** (i.e.,
modules declaring attributes usable for creating PEP-compliant type hints
Expand All @@ -71,148 +48,3 @@
Frozen set of all **deprecated typing attributes** (i.e., :mod:`typing` type
hints obsoleted by more recent PEPs).
'''

# ....................{ SIGNS ~ category }....................
#FIXME: Remove this and all upstream sets entirely.
HINT_PEP_ATTRS_ISINSTANCEABLE = (
HINT_PEP484_ATTRS_ISINSTANCEABLE |
HINT_PEP585_ATTRS_ISINSTANCEABLE
)
'''
Frozen set of all **isinstanceable typing attributes** (i.e., unsubscripted
:mod:`typing` type hints that are also isinstanceable classes passable as the
second argument to the :func:`isinstance` builtin).
'''


#FIXME: Remove this and all upstream sets entirely.
HINT_PEP_ATTRS_IGNORABLE = (
HINT_PEP484_ATTRS_IGNORABLE |
HINT_PEP544_ATTRS_IGNORABLE
)
'''
Frozen set of all **ignorable typing attributes** (i.e., unsubscripted
:mod:`typing` type hints unconditionally ignored by the
:func:`beartype.beartype` decorator).
See Also
----------
:attr:`beartype._util.data.hint.datahint.HINTS_IGNORABLE_SHALLOW`
Further commentary.
'''


#FIXME: Remove "HINT_PEP484_SIGNS_SEQUENCE_STANDARD" and
#"HINT_PEP585_SIGNS_SEQUENCE_STANDARD" entirely.
HINT_SIGNS_SEQUENCE_ARGS_ONE = (
HINT_PEP484_SIGNS_SEQUENCE_STANDARD |
HINT_PEP585_SIGNS_SEQUENCE_STANDARD
)
'''
Frozen set of all **standard sequence signs** (i.e., arbitrary objects uniquely
identifying PEP-compliant type hints accepting exactly one subscripted type
hint argument constraining *all* items of compliant sequences, which
necessarily satisfy the :class:`collections.abc.Sequence` protocol with
guaranteed ``O(1)`` indexation across all sequence items).
This set intentionally excludes the:
* :attr:`typing.AnyStr` sign, which accepts only the :class:`str` and
:class:`bytes` types as its sole subscripted argument, which does *not*
unconditionally constrain *all* items (i.e., unencoded and encoded characters
respectively) of compliant sequences but instead parametrizes this attribute.
* :attr:`typing.ByteString` sign, which accepts *no* subscripted arguments.
:attr:`typing.ByteString` is simply an alias for the
:class:`collections.abc.ByteString` abstract base class (ABC) and thus
already handled by our fallback logic for supported PEP-compliant type hints.
* :attr:`typing.Deque` sign, whose compliant objects (i.e.,
:class:`collections.deque` instances) only `guarantee O(n) indexation across
all sequence items <collections.deque_>`__:
Indexed access is ``O(1)`` at both ends but slows to ``O(n)`` in the
middle. For fast random access, use lists instead.
* :attr:`typing.NamedTuple` sign, which embeds a variadic number of
PEP-compliant field type hints and thus requires special-cased handling.
* :attr:`typing.Text` sign, which accepts *no* subscripted arguments.
:attr:`typing.Text` is simply an alias for the builtin :class:`str` type and
thus handled elsewhere as a PEP-noncompliant type hint.
* :attr:`typing.Tuple` sign, which accepts a variadic number of subscripted
arguments and thus requires special-cased handling.
.. _collections.deque:
https://docs.python.org/3/library/collections.html#collections.deque
'''

# ....................{ SIGNS ~ supported }....................
#FIXME: Remove this and "HINT_PEP484_SIGNS_SUPPORTED_SHALLOW" entirely.
_HINT_PEP_SIGNS_SUPPORTED_SHALLOW = (
HINT_PEP484_SIGNS_SUPPORTED_SHALLOW
)
'''
Frozen set of all **shallowly supported non-originative signs** (i.e.,
arbitrary objects uniquely identifying PEP-compliant type hints *not*
originating from a non-:mod:`typing` origin type for which the
:func:`beartype.beartype` decorator generates shallow type-checking code).
'''


#FIXME: Remove this and all upstream sets entirely.
HINT_SIGNS_SUPPORTED_DEEP = (
HINT_PEP484_SIGNS_SUPPORTED_DEEP |
HINT_PEP544_SIGNS_SUPPORTED_DEEP |
HINT_PEP585_SIGNS_SUPPORTED_DEEP |
HINT_PEP586_SIGNS_SUPPORTED_DEEP |
HINT_PEP593_SIGNS_SUPPORTED_DEEP
)
'''
Frozen set of all **deeply supported signs** (i.e., arbitrary objects uniquely
identifying PEP-compliant type hints for which the :func:`beartype.beartype`
decorator generates deeply type-checking code).
This set contains *every* sign explicitly supported by one or more conditional
branches in the body of the
:func:`beartype._decor._code._pep._pephint.pep_code_check_hint` function
generating code deeply type-checking the current pith against the PEP-compliant
type hint annotated by a subscription of that attribute.
'''

# ....................{ SIGNS ~ type }....................
#FIXME: Remove this and all upstream sets entirely.
HINT_SIGNS_TYPE_ORIGIN_STDLIB = (
HINT_PEP484_SIGNS_TYPE_ORIGIN |
# Since all PEP 585-compliant type hints originate from an origin type, the
# set of all PEP 585-compliant standard class signs also doubles as the
# set of all PEP 585-compliant original class signs.
HINT_PEP585_ATTRS_ISINSTANCEABLE
)
'''
Frozen set of all **signs** (i.e., arbitrary objects) uniquely identifying
PEP-compliant type hints originating from an **origin type** (i.e.,
non-:mod:`typing` class such that *all* objects satisfying this hint are
instances of this class).
Since any arbitrary object is trivially type-checkable against an
:func:`isinstance`-able class by passing that object and class to the
:func:`isinstance` builtin, *all* parameters and return values annotated by
PEP-compliant type hints subscripting unsubscripted typing attributes listed in
this dictionary are shallowly type-checkable from wrapper functions generated
by the :func:`beartype.beartype` decorator.
'''

# ....................{ SIGNS ~ supported : all }....................
#FIXME: Remove this and all upstream sets entirely.
HINT_SIGNS_SUPPORTED = (
# Set of all deeply supported signs.
HINT_SIGNS_SUPPORTED_DEEP |
# Set of all shallowly supported signs *NOT* originating from a
# non-"typing" origin type.
_HINT_PEP_SIGNS_SUPPORTED_SHALLOW |
# Set of all shallowly supported signs originating from a non-"typing"
# origin type.
HINT_SIGNS_TYPE_ORIGIN_STDLIB
)
'''
Frozen set of all **supported signs** (i.e., arbitrary objects uniquely
identifying PEP-compliant type hints).
'''

0 comments on commit 05a09dc

Please sign in to comment.