Skip to content

Commit

Permalink
Python 3.10 "NewType" x 3.
Browse files Browse the repository at this point in the history
This commit is the last in a commit chain improving compatibility with
the variant of the `typing.NewType` attribute implemented under Python ≥
3.10, which fundamentally refactored that attribute from a function
factory to a class -- significantly complicating cross-version detection
of that attribute. Specifically, this commit finalizes both the
implementation and testing of this attribute under Python ≥ 3.10.
(*Ignominious gnomish minions!*)
  • Loading branch information
leycec committed Aug 14, 2021
1 parent 95ae28e commit b7ab8b0
Show file tree
Hide file tree
Showing 74 changed files with 607 additions and 590 deletions.
3 changes: 2 additions & 1 deletion README.rst
Expand Up @@ -2144,6 +2144,7 @@ Compliance
* `PEP 589 -- TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys
<PEP 589_>`__.
* `PEP 591 -- Adding a final qualifier to typing <PEP 591_>`__.
* `PEP 612 -- Parameter Specification Variables <PEP 612_>`__.
See also the **PEP** and **typing** categories of our `features matrix
<Features_>`__ for further details.
Expand Down Expand Up @@ -3518,7 +3519,7 @@ External ``beartype`` resources include:
* `This list of all open-source PyPI-hosted dependents of this package
<beartype dependents_>`__ (i.e., third-party packages requiring ``beartype``
as a runtime dependency), kindly provided by the `Libraries.io package
as a runtime dependency), kindly furnished by the `Libraries.io package
registry <Libraries.io_>`__.
Related type-checking resources include:
Expand Down
6 changes: 3 additions & 3 deletions beartype/_cave/_cavefast.py
Expand Up @@ -891,11 +891,11 @@ class or instance attributes).
by this type, higher-level PEP-specific functions *must* be called instead.
These include:
* :func:`beartype._util.hint.pep.proposal.utilhintpep484.is_hint_pep484_generic`.
* :func:`beartype._util.hint.pep.proposal.utilpep484.is_hint_pep484_generic`.
detecting `PEP 484`_-compliant generic type hints.
* :func:`beartype._util.hint.pep.proposal.utilhintpep585.is_hint_pep585_builtin`.
* :func:`beartype._util.hint.pep.proposal.utilpep585.is_hint_pep585_builtin`.
detecting `PEP 585`_-compliant builtin type hints.
* :func:`beartype._util.hint.pep.proposal.utilhintpep585.is_hint_pep585_generic`.
* :func:`beartype._util.hint.pep.proposal.utilpep585.is_hint_pep585_generic`.
detecting `PEP 585`_-compliant generic type hints.
.. _PEP 484:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -11,7 +11,7 @@
'''

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

# See the "beartype.cave" submodule for further commentary.
Expand Down
File renamed without changes.
Expand Up @@ -12,9 +12,9 @@
'''

# ....................{ IMPORTS }....................
from beartype._util.data.hint.pep.sign import datapepsigns
from beartype._util.data.hint.pep.sign.datapepsigncls import HintSign
from beartype._util.data.hint.pep.sign.datapepsigns import (
from beartype._data.hint.pep.sign import datapepsigns
from beartype._data.hint.pep.sign.datapepsigncls import HintSign
from beartype._data.hint.pep.sign.datapepsigns import (
HintSignAbstractSet,
# HintSignAnnotated,
# HintSignAny,
Expand Down Expand Up @@ -55,7 +55,7 @@
HintSignMutableSequence,
HintSignMutableSet,
# HintSignNamedTuple,
# HintSignNewType,
HintSignNewType,
HintSignNone,
HintSignNumpyArray,
# HintSignOptional,
Expand Down Expand Up @@ -220,6 +220,14 @@
# string as PEP-compliant substantially simplifies logic throughout the
# codebase, we (currently) opt to do so.
'builtins.str': HintSignForwardRef,

# Python >= 3.10 implements PEP 484-compliant "typing.NewType" type hints
# as instances of that class. Regardless of the current Python version,
# "typing_extensions.NewType" type hints remain implemented in manner of
# Python < 3.10 -- which is to say, as closures of that function. Ergo, we
# intentionally omit "typing_extensions.NewType" here. See also:
# https://github.com/python/typing/blob/master/typing_extensions/src_py3/typing_extensions.py
'typing.NewType': HintSignNewType,
}
'''
Dictionary mapping from the fully-qualified classnames of all PEP-compliant
Expand Down Expand Up @@ -319,7 +327,7 @@ def _init() -> None:

# ..................{ EXTERNALS }..................
# Defer initialization-specific imports.
from beartype._util.data.mod.datamod import TYPING_MODULE_NAMES
from beartype._data.mod.datamod import TYPING_MODULE_NAMES

# Permit redefinition of these globals below.
global \
Expand Down
File renamed without changes.
Expand Up @@ -5,7 +5,7 @@

'''
Project-wide **Python version-agnostic signs** (i.e., instances of the
:class:`beartype._util.data.hint.pep.sign.datapepsigncls.HintSign` class
:class:`beartype._data.hint.pep.sign.datapepsigncls.HintSign` class
uniquely identifying PEP-compliant type hints in a safe, non-deprecated manner
regardless of the Python version targeted by the active Python interpreter).
Expand All @@ -17,7 +17,7 @@
# CAUTION: Attributes imported here at module scope *MUST* be explicitly
# deleted from this module's namespace below.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
from beartype._util.data.hint.pep.sign.datapepsigncls import (
from beartype._data.hint.pep.sign.datapepsigncls import (
HintSign as _HintSign)

# ....................{ SIGNS ~ explicit }....................
Expand Down
Expand Up @@ -6,15 +6,15 @@
'''
Project-wide **PEP-compliant type hint sign sets** (i.e., frozen set globals
aggregating instances of the
:class:`beartype._util.data.hint.pep.sign.datapepsigncls.HintSign` class,
:class:`beartype._data.hint.pep.sign.datapepsigncls.HintSign` class,
enabling efficient categorization of signs as belonging to various categories
of PEP-compliant type hints).
This private submodule is *not* intended for importation by downstream callers.
'''

# ....................{ IMPORTS }....................
from beartype._util.data.hint.pep.sign.datapepsigns import (
from beartype._data.hint.pep.sign.datapepsigns import (
HintSignAbstractSet,
HintSignAnnotated,
HintSignAny,
Expand Down Expand Up @@ -149,7 +149,7 @@
:func:`beartype.beartype` decorator).
'''

# ....................{ SIGNS ~ origin }....................
# ....................{ SIGNS ~ type }....................
HINT_SIGNS_TYPE_STDLIB = frozenset((
# ..................{ PEP (484|585) }..................
HintSignAbstractSet,
Expand Down Expand Up @@ -226,6 +226,45 @@
:func:`beartype.beartype` decorator.
'''


HINT_SIGNS_TYPE_MIMIC = frozenset((
# ..................{ PEP 484 }..................
HintSignNewType,

# ..................{ PEP 593 }..................
HintSignAnnotated,
))
'''
Frozen set of all signs uniquely identifying **PEP-compliant type hint mimics**
(i.e., hints maliciously masquerading as another type by explicitly overriding
their ``__module__`` dunder instance variable to that of that type).
Notably, this set contains the signs of:
* :pep:`484`-compliant :attr:`typing.NewType` type hints under Python >= 3.10,
which badly masquerade as their first passed argument to such an extreme
degree that they even intentionally prefix their machine-readable
representation by the fully-qualified name of the caller's module: e.g.,
.. code-block:: python
# Under Python >= 3.10:
>>> import typing
>>> new_type = typing.NewType('List', bool)
>>> repr(new_type)
__main__.List # <---- this is genuine bollocks
* :pep:`593`-compliant :attr:`typing.Annotated` type hints, which badly
masquerade as their first subscripted argument (e.g., the :class:`int` in
``typing.Annotated[int, 63]``) such that the value of the ``__module__``
attributes of these hints is that of that argument rather than their own.
Oddly, their machine-readable representation remains prefixed by
``"typing."``, enabling an efficient test that also generalizes to all other
outlier edge cases that are probably lurking about.
I have no code and I must scream.
'''

# ....................{ SETS ~ supported }....................
_HINT_SIGNS_SUPPORTED_SHALLOW = frozenset((
# ..................{ PEP 484 }..................
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions beartype/_decor/_cache/cachehint.py
Expand Up @@ -40,7 +40,7 @@
# strongly benefit from some form of memoization or caching. Since this edge
# case should be fairly rare, even a dictionary would probably be overkill.
# Just implementing something resembling the following memoized getter
# in the "utilhintpep544" submodule would probably suffice:
# in the "utilpep544" submodule would probably suffice:
# @callable_cached
# def get_pep544_protocol_checkable_from_protocol_uncheckable(
# protocol_uncheckable: object) -> Protocol:
Expand All @@ -51,7 +51,7 @@
# ....................{ IMPORTS }....................
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 beartype._data.func.datafunc import METHOD_NAMES_BINARY_DUNDER
from collections.abc import Callable
from typing import Any, Dict, Union

Expand Down
33 changes: 16 additions & 17 deletions beartype/_decor/_code/_pep/_pephint.py
Expand Up @@ -85,14 +85,14 @@
acquire_object_typed,
release_object_typed,
)
from beartype._util.data.hint.pep.sign.datapepsigns import (
from beartype._data.hint.pep.sign.datapepsigns import (
HintSignAnnotated,
HintSignForwardRef,
HintSignGeneric,
HintSignLiteral,
HintSignTuple,
)
from beartype._util.data.hint.pep.sign.datapepsignset import (
from beartype._data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1,
HINT_SIGNS_SUPPORTED_DEEP,
HINT_SIGNS_TYPE_STDLIB,
Expand All @@ -105,13 +105,13 @@
add_func_scope_types,
)
from beartype._util.hint.utilhintget import get_hint_reduced
from beartype._util.hint.pep.proposal.utilhintpep484 import (
from beartype._util.hint.pep.proposal.utilpep484 import (
get_hint_pep484_generic_base_erased_from_unerased)
from beartype._util.hint.pep.proposal.utilhintpep585 import (
from beartype._util.hint.pep.proposal.utilpep585 import (
is_hint_pep585_builtin)
from beartype._util.hint.pep.proposal.utilhintpep586 import (
from beartype._util.hint.pep.proposal.utilpep586 import (
die_unless_hint_pep586)
from beartype._util.hint.pep.proposal.utilhintpep593 import (
from beartype._util.hint.pep.proposal.utilpep593 import (
get_hint_pep593_metadata,
get_hint_pep593_metahint,
)
Expand Down Expand Up @@ -973,7 +973,7 @@ 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.sign.datapepsignset.HINT_SIGNS_SUPPORTED_DEEP"
# * "beartype._data.hint.pep.sign.datapepsignset.HINT_SIGNS_SUPPORTED_DEEP"
# frozen set of all signs for which this function generates
# deeply type-checking code.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Expand Down Expand Up @@ -1662,12 +1662,11 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
#
# If this pseudo-superclass is neither a PEP 585-compliant
# type hint *NOR* a PEP-compliant type hint defined by the
# "typing" module, this pseudo-superclass *MUST* be a PEP
# 585-noncompliant user-defined pseudo-superclass. In this
# case, reduce this pseudo-superclass to the corresponding
# actual superclass originating this pseudo-superclass.
#
# Note that:
# "typing" module, this pseudo-superclass *MUST* be a
# user-defined pseudo-superclass *NOT* compliant with PEP
# 585. In this case, reduce this pseudo-superclass to the
# corresponding actual superclass originating this
# pseudo-superclass. Note that:
# * This horrible, irrational, and unintuitive edge case
# arises *ONLY* for user-defined PEP 484-compliant
# generics and PEP 544-compliant protocols subclassing
Expand All @@ -1684,7 +1683,7 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
# >>> isinstance(UserProtocolUnerased, type)
# False
# * PEP 585-compliant generics suffer no such issues:
# >>> from beartype._util.hint.pep.proposal.utilhintpep585 import is_hint_pep585_builtin
# >>> from beartype._util.hint.pep.proposal.utilpep585 import is_hint_pep585_builtin
# >>> class UserGeneric(list[int]): pass
# >>> class UserSubgeneric(UserGeneric[int]): pass
# >>> UserSubgeneric.__orig_bases__
Expand Down Expand Up @@ -1717,15 +1716,15 @@ def _enqueue_hint_child(pith_child_expr: str) -> str:
# other means of recursing into the possibly relevant
# superclasses of this erased superclass.
#
# Note that, in theory, we could deeply refactor this
# Note that, in theory, we could deeply refactor this whole
# algorithm to support the notion of child hints that
# should be ignored for purposes of type-checking but
# nonetheless recursed into. In practice, the current
# approach only introduces mild runtime inefficiencies
# while preserving sanity throughout this algorithm.
#
# Specifically, perform this awful reduction *ONLY* if
# this child hint is a PEP 484- or 544-compliant
# Specifically, perform this awful reduction *ONLY* if this
# pseudo-superclass is a PEP 484- or 544-compliant
# user-defined pseudo-superclass that is neither...
elif not (
# A PEP 585-compliant pseudo-superclass *NOR*...
Expand Down
6 changes: 3 additions & 3 deletions beartype/_decor/_error/_errorgeneric.py
Expand Up @@ -16,10 +16,10 @@
from beartype._decor._error._errortype import (
get_cause_or_none_type)
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignGeneric
from beartype._util.hint.pep.proposal.utilhintpep484 import (
from beartype._data.hint.pep.sign.datapepsigns import HintSignGeneric
from beartype._util.hint.pep.proposal.utilpep484 import (
get_hint_pep484_generic_base_erased_from_unerased)
from beartype._util.hint.pep.proposal.utilhintpep585 import (
from beartype._util.hint.pep.proposal.utilpep585 import (
is_hint_pep585_builtin)
from beartype._util.hint.pep.utilpepget import (
get_hint_pep_generic_type_or_none)
Expand Down
4 changes: 2 additions & 2 deletions beartype/_decor/_error/_errorsequence.py
Expand Up @@ -14,8 +14,8 @@
# ....................{ 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.sign.datapepsigns import HintSignTuple
from beartype._util.data.hint.pep.sign.datapepsignset import (
from beartype._data.hint.pep.sign.datapepsigns import HintSignTuple
from beartype._data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1)
from beartype._util.hint.pep.utilpeptest import is_hint_pep_tuple_empty
from beartype._util.hint.utilhinttest import is_hint_ignorable
Expand Down
2 changes: 1 addition & 1 deletion beartype/_decor/_error/_errorsleuth.py
Expand Up @@ -15,7 +15,7 @@
# ....................{ IMPORTS }....................
from beartype.roar._roarexc import _BeartypeCallHintPepRaiseException
from beartype._cave._cavemap import NoneTypeOr
from beartype._util.data.hint.pep.sign.datapepsignset import (
from beartype._data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SUPPORTED_DEEP,
HINT_SIGNS_TYPE_STDLIB,
)
Expand Down
2 changes: 1 addition & 1 deletion beartype/_decor/_error/_errortype.py
Expand Up @@ -14,7 +14,7 @@
# ....................{ IMPORTS }....................
from beartype.roar._roarexc import _BeartypeCallHintPepRaiseException
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignForwardRef
from beartype._data.hint.pep.sign.datapepsigns import HintSignForwardRef
from beartype._util.hint.nonpep.utilnonpeptest import (
die_unless_hint_nonpep_tuple)
from beartype._util.hint.pep.utilpepget import (
Expand Down
2 changes: 1 addition & 1 deletion beartype/_decor/_error/_proposal/_errorpep484noreturn.py
Expand Up @@ -15,7 +15,7 @@

# ....................{ IMPORTS }....................
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignNoReturn
from beartype._data.hint.pep.sign.datapepsigns import HintSignNoReturn
from beartype._util.text.utiltextlabel import label_callable

# See the "beartype.cave" submodule for further commentary.
Expand Down
2 changes: 1 addition & 1 deletion beartype/_decor/_error/_proposal/_errorpep484union.py
Expand Up @@ -16,7 +16,7 @@
# ....................{ IMPORTS }....................
from beartype.roar._roarexc import _BeartypeCallHintPepRaiseException
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsignset import HINT_SIGNS_UNION
from beartype._data.hint.pep.sign.datapepsignset import HINT_SIGNS_UNION
from beartype._util.hint.pep.utilpepget import (
get_hint_pep_type_stdlib_or_none)
from beartype._util.hint.pep.utilpeptest import is_hint_pep
Expand Down
2 changes: 1 addition & 1 deletion beartype/_decor/_error/_proposal/_errorpep586.py
Expand Up @@ -15,7 +15,7 @@

# ....................{ IMPORTS }....................
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignLiteral
from beartype._data.hint.pep.sign.datapepsigns import HintSignLiteral
from beartype._util.text.utiltextjoin import join_delimited_disjunction
from beartype._util.text.utiltextrepr import represent_object
from typing import Optional
Expand Down
4 changes: 2 additions & 2 deletions beartype/_decor/_error/_proposal/_errorpep593.py
Expand Up @@ -16,8 +16,8 @@
# ....................{ IMPORTS }....................
from beartype.roar._roarexc import _BeartypeCallHintPepRaiseException
from beartype._decor._error._errorsleuth import CauseSleuth
from beartype._util.data.hint.pep.sign.datapepsigns import HintSignAnnotated
from beartype._util.hint.pep.proposal.utilhintpep593 import (
from beartype._data.hint.pep.sign.datapepsigns import HintSignAnnotated
from beartype._util.hint.pep.proposal.utilpep593 import (
get_hint_pep593_metadata,
get_hint_pep593_metahint,
)
Expand Down
6 changes: 3 additions & 3 deletions beartype/_decor/_error/errormain.py
Expand Up @@ -93,16 +93,16 @@
get_cause_or_none_literal)
from beartype._decor._error._proposal._errorpep593 import (
get_cause_or_none_annotated)
from beartype._util.data.hint.pep.sign.datapepsigncls import HintSign
from beartype._util.data.hint.pep.sign.datapepsigns import (
from beartype._data.hint.pep.sign.datapepsigncls import HintSign
from beartype._data.hint.pep.sign.datapepsigns import (
HintSignAnnotated,
HintSignForwardRef,
HintSignGeneric,
HintSignLiteral,
HintSignNoReturn,
HintSignTuple,
)
from beartype._util.data.hint.pep.sign.datapepsignset import (
from beartype._data.hint.pep.sign.datapepsignset import (
HINT_SIGNS_SEQUENCE_ARGS_1,
HINT_SIGNS_TYPE_STDLIB,
HINT_SIGNS_UNION,
Expand Down
4 changes: 2 additions & 2 deletions beartype/_util/cls/utilclstest.py
Expand Up @@ -15,8 +15,8 @@
BeartypeDecorHintPep3119Exception,
_BeartypeUtilTypeException,
)
from beartype._util.data.cls.datacls import TYPES_BUILTIN_FAKE
from beartype._util.data.mod.datamod import BUILTINS_MODULE_NAME
from beartype._data.cls.datacls import TYPES_BUILTIN_FAKE
from beartype._data.mod.datamod import BUILTINS_MODULE_NAME
from typing import Type

# ....................{ VALIDATORS }....................
Expand Down

0 comments on commit b7ab8b0

Please sign in to comment.