forked from pool/python-beartype
- Update to 0.19.0: * see upstream release announcement: https://github.com/beartype/beartype/releases/tag/v0.19.0 - Add fix-python313.patch to fix tests under Python 3.13 OBS-URL: https://build.opensuse.org/request/show/1234596 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-beartype?expand=0&rev=25
336 lines
14 KiB
Diff
336 lines
14 KiB
Diff
From a565eb2d0589d187dc367b794e1f2afd9e765a2e Mon Sep 17 00:00:00 2001
|
|
From: leycec <leycec@gmail.com>
|
|
Date: Wed, 20 Nov 2024 18:09:46 -0400
|
|
Subject: [PATCH] Python 3.13.0 release party.
|
|
|
|
This commit celebrates the official stable release of **Python 3.13.0.**
|
|
Specifically, this commit:
|
|
|
|
* Resolves testing-specific issues with Python 3.13.0.
|
|
* Enables GitHub Actions-based continuous integration (CI) testing
|
|
workflows for Python 3.13.0.
|
|
|
|
(*Marked down on downy malarkey, turnkey turkey!*)
|
|
---
|
|
beartype/_check/code/codecls.py | 104 ++++++++++--------
|
|
beartype/_util/cls/utilclstest.py | 8 +-
|
|
.../door/_fixture/_doorfix_is_subhint.py | 60 ++++++----
|
|
5 files changed, 150 insertions(+), 116 deletions(-)
|
|
|
|
Index: beartype-0.19.0/beartype/_check/code/codecls.py
|
|
===================================================================
|
|
--- beartype-0.19.0.orig/beartype/_check/code/codecls.py
|
|
+++ beartype-0.19.0/beartype/_check/code/codecls.py
|
|
@@ -34,6 +34,7 @@ from beartype._check.code.snip.codesnips
|
|
CODE_HINT_CHILD_PLACEHOLDER_PREFIX,
|
|
CODE_HINT_CHILD_PLACEHOLDER_SUFFIX,
|
|
)
|
|
+from beartype._data.hint.datahintpep import Hint
|
|
from beartype._util.cache.pool.utilcachepoollistfixed import (
|
|
FIXED_LIST_SIZE_MEDIUM,
|
|
FixedList,
|
|
@@ -52,7 +53,7 @@ class HintMeta(object):
|
|
|
|
Attributes
|
|
----------
|
|
- hint : object
|
|
+ hint : Hint
|
|
Type hint currently visited by this BFS.
|
|
hint_placeholder : str
|
|
**Type-checking placeholder substring** to be globally replaced in the
|
|
@@ -162,24 +163,24 @@ class HintMeta(object):
|
|
__slots__ = (
|
|
'hint',
|
|
'hint_placeholder',
|
|
+ 'indent_level',
|
|
'pith_expr',
|
|
'pith_var_name_index',
|
|
- 'indent_level',
|
|
)
|
|
|
|
# Squelch false negatives from mypy. This is absurd. This is mypy. See:
|
|
# https://github.com/python/mypy/issues/5941
|
|
if TYPE_CHECKING:
|
|
- hint: object
|
|
+ hint: Hint
|
|
hint_placeholder: str
|
|
+ indent_level: int
|
|
pith_expr: str
|
|
pith_var_name_index: int
|
|
- indent_level: int
|
|
|
|
# ..................{ INITIALIZERS }..................
|
|
def __init__(self, pith_var_name_index: int) -> None:
|
|
'''
|
|
- Initialize this type-checking metadata dataclass.
|
|
+ Initialize this type-checking metadata.
|
|
|
|
Parameters
|
|
----------
|
|
@@ -203,9 +204,43 @@ class HintMeta(object):
|
|
)
|
|
|
|
# Nullify all remaining parameters for safety.
|
|
- self.hint = SENTINEL
|
|
- self.pith_expr = SENTINEL # type: ignore[assignment]
|
|
+ self.hint = SENTINEL # type: ignore[assignment]
|
|
self.indent_level = SENTINEL # type: ignore[assignment]
|
|
+ self.pith_expr = SENTINEL # type: ignore[assignment]
|
|
+
|
|
+
|
|
+ def reinit(
|
|
+ self,
|
|
+ hint: Hint,
|
|
+ indent_level: int,
|
|
+ pith_expr: str,
|
|
+ ) -> None:
|
|
+ '''
|
|
+ Reinitialize this type-checking metadata with the passed metadata.
|
|
+
|
|
+ Parameters
|
|
+ ----------
|
|
+ hint : Hint
|
|
+ Currently iterated child type hint subscripting the currently
|
|
+ visited type hint.
|
|
+ indent_level : int
|
|
+ 1-based indentation level describing the current level of
|
|
+ indentation appropriate for the currently iterated child hint.
|
|
+ pith_expr : str
|
|
+ Python code snippet evaluating to the child pith to be type-checked
|
|
+ against the currently iterated child type hint.
|
|
+ '''
|
|
+ assert isinstance(indent_level, int), (
|
|
+ f'{repr(indent_level)} not integer.')
|
|
+ assert isinstance(pith_expr, str), (
|
|
+ f'{repr(pith_expr)} not string.')
|
|
+ assert indent_level > 1, f'{repr(indent_level)} <= 1.'
|
|
+ assert pith_expr, f'{repr(pith_expr)} empty.'
|
|
+
|
|
+ # Classify all passed parameters.
|
|
+ self.hint = hint
|
|
+ self.indent_level = indent_level
|
|
+ self.pith_expr = pith_expr
|
|
|
|
# ....................{ SUBCLASSES }....................
|
|
#FIXME: Unit test us up, please.
|
|
@@ -311,7 +346,7 @@ class HintsMeta(FixedList):
|
|
assert 0 <= index <= len(self), f'{index} not in [0, {len(self)}].'
|
|
|
|
# Type hint type-checking metadata at this index.
|
|
- hint_meta = FixedList.__getitem__(index) # type: ignore[call-overload]
|
|
+ hint_meta = super().__getitem__(index) # type: ignore[call-overload]
|
|
|
|
# If this metadata has yet to be instantiated...
|
|
if hint_meta is None:
|
|
@@ -324,29 +359,18 @@ class HintsMeta(FixedList):
|
|
return hint_meta
|
|
|
|
# ..................{ METHODS }..................
|
|
- def enqueue_hint_child(
|
|
- self,
|
|
- hint: object,
|
|
- pith_expr: str,
|
|
- indent_level: int,
|
|
- ) -> str:
|
|
+ def enqueue_hint_child(self, *args, **kwargs) -> str:
|
|
'''
|
|
- **Enqueue** (i.e., append) a new tuple of metadata describing the
|
|
- currently iterated child type hint to the end of the this queue,
|
|
- enabling this hint to be visited by the ongoing breadth-first search
|
|
- (BFS) traversing over this queue.
|
|
+ **Enqueue** (i.e., append) to the end of the this queue new
|
|
+ **type-checking metadata** (i.e., a :class:`.HintMeta` object)
|
|
+ describing the currently iterated child type hint with the passed
|
|
+ metadata, enabling this hint to be visited by the ongoing breadth-first
|
|
+ search (BFS) traversing over this queue.
|
|
|
|
Parameters
|
|
----------
|
|
- hint : object
|
|
- Currently iterated child type hint subscripting the currently
|
|
- visited type hint.
|
|
- pith_expr : str
|
|
- Python code snippet evaluating to the child pith to be type-checked
|
|
- against the currently iterated child type hint.
|
|
- indent_level : int
|
|
- 1-based indentation level describing the current level of
|
|
- indentation appropriate for the currently iterated child hint.
|
|
+ All parameters are passed as is to the lower-level
|
|
+ :meth:`HintMeta.reinit` method.
|
|
|
|
Returns
|
|
-------
|
|
@@ -354,12 +378,6 @@ class HintsMeta(FixedList):
|
|
Placeholder string to be subsequently replaced by code type-checking
|
|
this child pith against this child type hint.
|
|
'''
|
|
- assert isinstance(pith_expr, str), (
|
|
- f'{repr(pith_expr)} not string.')
|
|
- assert isinstance(indent_level, int), (
|
|
- f'{repr(indent_level)} not integer.')
|
|
- assert pith_expr, f'{repr(pith_expr)} empty.'
|
|
- assert indent_level > 1, f'{repr(indent_level)} <= 1.'
|
|
|
|
# Increment the 0-based index of metadata describing the last visitable
|
|
# hint in this list (which also serves as the unique identifier of the
|
|
@@ -375,9 +393,7 @@ class HintsMeta(FixedList):
|
|
hint_meta = self.__getitem__(self.index_last)
|
|
|
|
# Replace prior fields of this metadata with the passed fields.
|
|
- hint_meta.hint = hint
|
|
- hint_meta.pith_expr = pith_expr
|
|
- hint_meta.indent_level = indent_level
|
|
+ hint_meta.reinit(*args, **kwargs)
|
|
|
|
# Return the placeholder substring associated with this type hint.
|
|
return hint_meta.hint_placeholder
|
|
Index: beartype-0.19.0/beartype/_util/cls/utilclstest.py
|
|
===================================================================
|
|
--- beartype-0.19.0.orig/beartype/_util/cls/utilclstest.py
|
|
+++ beartype-0.19.0/beartype/_util/cls/utilclstest.py
|
|
@@ -285,7 +285,7 @@ def is_type_subclass(
|
|
lower-level** :func:`issubclass` **builtin,** which raises an undescriptive
|
|
exception when the first passed parameter is *not* a class: e.g.,
|
|
|
|
- .. code-block:: python
|
|
+ .. code-block:: pycon
|
|
|
|
>>> issubclass(object(), type)
|
|
TypeError: issubclass() arg 1 must be a class
|
|
@@ -327,10 +327,10 @@ def is_type_subclass(
|
|
def is_type_subclass_proper(
|
|
cls: object, base_classes: TypeOrTupleTypes) -> bool:
|
|
'''
|
|
- ``True`` only if the passed object is a proper subclass of the passed
|
|
+ :data:`True` only if the passed object is a proper subclass of the passed
|
|
superclass(es).
|
|
|
|
- Specifically, this tester returns ``True`` only if either:
|
|
+ Specifically, this tester returns :data:`True` only if either:
|
|
|
|
* If ``base_classes`` is a single superclass, the passed class is a subclass
|
|
of that superclass (but *not* that superclass itself).
|
|
@@ -352,7 +352,7 @@ def is_type_subclass_proper(
|
|
Returns
|
|
-------
|
|
bool
|
|
- ``True`` only if this object is a proper subclass of these
|
|
+ :data:`True` only if this object is a proper subclass of these
|
|
superclass(es).
|
|
'''
|
|
assert isinstance(base_classes, TestableTypesTuple), (
|
|
Index: beartype-0.19.0/beartype_test/a00_unit/a40_api/door/_fixture/_doorfix_is_subhint.py
|
|
===================================================================
|
|
--- beartype-0.19.0.orig/beartype_test/a00_unit/a40_api/door/_fixture/_doorfix_is_subhint.py
|
|
+++ beartype-0.19.0/beartype_test/a00_unit/a40_api/door/_fixture/_doorfix_is_subhint.py
|
|
@@ -50,8 +50,10 @@ def door_cases_is_subhint() -> 'Iterable
|
|
import collections.abc
|
|
import typing
|
|
from beartype._data.hint.datahinttyping import S, T
|
|
+ from beartype._util.cls.utilclstest import is_type_subclass_proper
|
|
from beartype._util.hint.pep.utilpepget import get_hint_pep_typevars
|
|
from beartype._util.py.utilpyversion import IS_PYTHON_AT_LEAST_3_9
|
|
+ from abc import ABCMeta
|
|
from collections.abc import (
|
|
Collection as CollectionABC,
|
|
Sequence as SequenceABC,
|
|
@@ -361,18 +363,26 @@ def door_cases_is_subhint() -> 'Iterable
|
|
|
|
# ..................{ LISTS ~ typing }..................
|
|
# List of the unqualified basenames of all standard ABCs published by
|
|
- # the standard "collections.abc" module, defined as...
|
|
- COLLECTIONS_ABC_BASENAMES = [
|
|
- # For the unqualified basename of each attribute defined by the standard
|
|
- # "collections.abc" module...
|
|
- COLLECTIONS_ABC_BASENAME
|
|
- for COLLECTIONS_ABC_BASENAME in dir(collections.abc)
|
|
- # If this basename is *NOT* prefixed by an underscore, this attribute is
|
|
- # public and thus an actual ABC. In this case, include this ABC.
|
|
- if not COLLECTIONS_ABC_BASENAME.startswith('_')
|
|
- # Else, this is an unrelated private attribute. In this case, silently
|
|
- # ignore this attribute and continue to the next.
|
|
- ]
|
|
+ # the standard "collections.abc" module, initialized to the empty list.
|
|
+ COLLECTIONS_ABC_BASENAMES = []
|
|
+
|
|
+ # For the unqualified basename of each attribute and that attribute defined
|
|
+ # by the standard "collections.abc" submodule...
|
|
+ for collections_abc_basename, collections_abc in (
|
|
+ collections.abc.__dict__.items()):
|
|
+ # If this attribute is a public ABC, include this ABC, where public ABCs
|
|
+ # are detected as...
|
|
+ if (
|
|
+ # The unqualified basename of this attribute is not prefixed by an
|
|
+ # underscore (and is thus public) *AND*...
|
|
+ not collections_abc_basename.startswith('_') and
|
|
+ # This attribute is an ABC but *NOT* the semantically meaningless
|
|
+ # "abc.ABCMeta" superclass itself.
|
|
+ is_type_subclass_proper(collections_abc, ABCMeta)
|
|
+ ):
|
|
+ COLLECTIONS_ABC_BASENAMES.append(collections_abc_basename)
|
|
+ # Else, this is an unrelated attribute. In this case, silently ignore
|
|
+ # this attribute and continue to the next.
|
|
|
|
# List of the unqualified basenames of all standard abstract base classes
|
|
# (ABCs) supported by the standard "typing" module, defined as the
|
|
@@ -386,6 +396,7 @@ def door_cases_is_subhint() -> 'Iterable
|
|
# supported by the standard "typing" module.
|
|
['Deque']
|
|
)
|
|
+ print(f'TYPING_ABC_BASENAMES: {TYPING_ABC_BASENAMES}')
|
|
|
|
# ..................{ HINTS ~ abcs }..................
|
|
# For the unqualified basename of each standard ABCs supported by the
|
|
@@ -399,40 +410,41 @@ def door_cases_is_subhint() -> 'Iterable
|
|
# Type hint factory published by the "typing" module corresponding to
|
|
# this ABC if any *OR* "None" otherwise (i.e., if "typing" publishes
|
|
# *NO* such type hint factory).
|
|
- TypingABC = getattr(typing, TYPING_ABC_BASENAME, None)
|
|
+ typing_abc = getattr(typing, TYPING_ABC_BASENAME, None)
|
|
|
|
# If "typing" publishes *NO* such type hint factory, silently ignore
|
|
# this ABC and continue to the next.
|
|
- if TypingABC is None:
|
|
+ if typing_abc is None:
|
|
continue
|
|
# Else, "typing" publishes this type hint factory.
|
|
|
|
# Number of type variables parametrizing this ABC, defined as either...
|
|
- TYPING_ABC_TYPEVARS_LEN = (
|
|
+ typing_abc_typevars_len = (
|
|
# If the active Python interpreter targets Python >= 3.9, a private
|
|
# instance variable of this type hint factory yielding this
|
|
# metadata. Under Python >= 3.9, unsubscripted type hint factories
|
|
# are *NOT* parametrized by type variables.
|
|
- TypingABC._nparams
|
|
+ typing_abc._nparams
|
|
+ # getattr(typing_abc, '_nparams', 0)
|
|
if IS_PYTHON_AT_LEAST_3_9 else
|
|
# Else, the active Python interpreter targets Python < 3.9. In this
|
|
# case, the number of type variables directly parametrizing this
|
|
# ABC.
|
|
- len(get_hint_pep_typevars(TypingABC))
|
|
+ len(get_hint_pep_typevars(typing_abc))
|
|
)
|
|
|
|
# If this ABC is parametrized by one or more type variables, exercise
|
|
# that this ABC subscripted by one or more arbitrary concrete types is a
|
|
# non-trivial subhint of this same ABC subscripted by one or more
|
|
# arbitrary different ABCs of those concrete types.
|
|
- if TYPING_ABC_TYPEVARS_LEN:
|
|
- subhint = TypingABC[(list,) * TYPING_ABC_TYPEVARS_LEN]
|
|
- superhint = TypingABC[(Sequence,) * TYPING_ABC_TYPEVARS_LEN]
|
|
+ if typing_abc_typevars_len:
|
|
+ subhint = typing_abc[(list,) * typing_abc_typevars_len]
|
|
+ superhint = typing_abc[(Sequence,) * typing_abc_typevars_len]
|
|
# Else, this ABC is parametrized by *NO* type variables. In this case,
|
|
# fallback to exercising that this ABC is a trivial subhint of itself.
|
|
else:
|
|
- subhint = TypingABC
|
|
- superhint = TypingABC
|
|
+ subhint = typing_abc
|
|
+ superhint = typing_abc
|
|
|
|
# Append a new hint subhint case exercising that this subhint is
|
|
# actually a subhint of this superhint.
|