File fix-python313.patch of Package python-beartype
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.