Skip to content

Commit

Permalink
typing.Protocol + abc.ABC x 1.
Browse files Browse the repository at this point in the history
This commit is the first in a commit chain supporting PEP 544-compliant
inheritance trees subclassing non-trivial combinations of the
`typing.Protocol` + `abc.ABC` superclasses, en-route to resolving beartype#117
kindly submitted by too-entertaining pun master @twoertwein (Torsten
Wörtwein). Specifically, this commit generalizes our test suite to test
the `typing.Literal` and `typing.Annotated` type hint factories against
the official `typing` module, the third-party `typing_extensions`
module, and the `beartype.typing` compatibility layer. Although doing
so admittedly has no relation whatsoever to this issue, every bug
resolution begins with a mild detour into the annals of inanity.
(*Undocumented acumen, man!*)
  • Loading branch information
leycec committed Apr 1, 2022
1 parent 325ab9f commit da3874b
Show file tree
Hide file tree
Showing 11 changed files with 968 additions and 807 deletions.
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ GitHub Sponsors <beartype sponsorship_>`__:
.. # well as the icon links below. kthx
.. # |icon-for-glorious-sponsor|
* **Your iconic URL here.** Let us bestow you with eyeballs.
* **Your iconic URL here.** `Let us bestow you with eyeballs <beartype
sponsorship_>`__.

.. code-block:: bash
Expand Down
17 changes: 8 additions & 9 deletions beartype/_util/hint/pep/proposal/pep484/utilpep484generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,7 @@ def get_hint_pep484_generic_bases_unerased(hint: Any) -> tuple:
if hint_bases is not None:
return hint_bases
# Else, this generic erased *NONE* of its superclasses. These superclasses
# *MUST* by definition be unerased and thus safely returnable as is. In
# this case...
# *MUST* by definition be unerased and thus safely returnable as is.

# Unerased superclasses of this generic defined by the method resolution
# order (MRO) for this generic.
Expand All @@ -428,7 +427,7 @@ def get_hint_pep484_generic_bases_unerased(hint: Any) -> tuple:
# Substring prefixing all exceptions raised below.
EXCEPTION_STR_PREFIX = (
f'PEP 484 generic {repr(hint)} '
f'method resolution order {repr(hint_bases)}'
f'method resolution order {repr(hint_bases)} '
)

# If this MRO lists strictly less than four classes, raise an exception.
Expand All @@ -439,20 +438,20 @@ def get_hint_pep484_generic_bases_unerased(hint: Any) -> tuple:
# * The "object" root superclass.
if len(hint_bases) < 4:
raise BeartypeDecorHintPep484Exception(
f'{EXCEPTION_STR_PREFIX} lists less than four classes.')
f'{EXCEPTION_STR_PREFIX}lists less than four classes.')
# Else, this MRO lists at least four classes.
#
# If any class listed by this MRO fails to comply with the above
# expectations, raise an exception.
elif hint_bases[0] != hint:
raise BeartypeDecorHintPep484Exception(
f'{EXCEPTION_STR_PREFIX} first item not {hint}.')
elif hint_bases[-2] != Generic:
raise BeartypeDecorHintPep484Exception(
f'{EXCEPTION_STR_PREFIX} second-to-last item not {Generic}.')
f'{EXCEPTION_STR_PREFIX}first item not {hint}.')
elif hint_bases[-1] != object:
raise BeartypeDecorHintPep484Exception(
f'{EXCEPTION_STR_PREFIX} last item not {object}.')
f'{EXCEPTION_STR_PREFIX}last item not {object}.')
elif hint_bases[-2] != Generic:
raise BeartypeDecorHintPep484Exception(
f'{EXCEPTION_STR_PREFIX}second-to-last item not {Generic}.')
# Else, all classes listed by this MRO comply with the above expectations.

# Return a slice of this tuple preserving *ONLY* the non-ignorable
Expand Down
23 changes: 19 additions & 4 deletions beartype_test/a00_unit/data/hint/pep/proposal/_data_pep544.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
'''

# ....................{ TODO }....................
#FIXME: Generalize this submodule to transparently test all hints against both
#the "typing.Protocol" *AND* "beartype.typing.Protocol" superclasses. Doing so
#will, in turn, require defining a new "HintPepMetadata.hints" instance
#variable required to be a sequence of one or more hints.

#FIXME: Test user-defined multiple-inherited protocols (i.e., user-defined
#classes directly subclassing the "typing.Protocol" ABC and one or more other
#superclasses) once @beartype supports these protocols as well.
Expand Down Expand Up @@ -36,6 +41,12 @@ def add_data(data_module: 'ModuleType') -> None:

# If the active Python interpreter targets less than Python < 3.8, this
# interpreter fails to support PEP 544. In this case, reduce to a noop.
#
# Note that we intentionally avoid testing against the
# "typing_extensions.Protocol" superclass. Why? Because that superclass is
# horribly broken under Python 3.7 and thus *CANNOT* be supported by
# beartype. This is why we only support a proper subset of
# "typing_extensions" attributes, folks.
if not IS_PYTHON_AT_LEAST_3_8:
return
# Else, the active Python interpreter targets at least Python >= 3.8 and
Expand All @@ -45,6 +56,12 @@ def add_data(data_module: 'ModuleType') -> None:
# Defer Python >= 3.8-specific imports.
import pathlib
from abc import abstractmethod
from beartype.typing import (
Any,
AnyStr,
TypeVar,
runtime_checkable,
)
from beartype._data.hint.pep.sign.datapepsigns import HintSignGeneric
from beartype_test.a00_unit.data.hint.util.data_hintmetacls import (
HintPepMetadata,
Expand All @@ -53,9 +70,9 @@ def add_data(data_module: 'ModuleType') -> None:
)
from beartype_test.util.mod.pytmodtest import (
is_package_beartype_vale_usable)

#FIXME: Generalize to iteratively import from "beartype.typing" as well.
from typing import (
Any,
AnyStr,
BinaryIO,
IO,
Protocol,
Expand All @@ -66,8 +83,6 @@ def add_data(data_module: 'ModuleType') -> None:
SupportsInt,
SupportsRound,
TextIO,
TypeVar,
runtime_checkable,
)

# Type variables.
Expand Down
Loading

0 comments on commit da3874b

Please sign in to comment.