Skip to content

Commit

Permalink
beartype.typing removals scheduled.
Browse files Browse the repository at this point in the history
This commit schedules various public `typing` attributes currently
exported by the `beartype.typing` subpackage for removal under future
Python releases, resolving future issue #386 kindly submitted by core
Python `typing` mega-boss @JelleZijlstra (Jelle Zijlstra). Specifically,
this commit schedules:

* `beartype.typing.ByteString` for removal under Python ≥ 3.14.
* `beartype.typing.AnyStr` for removal under Python ≥ 3.16.

Thanks a heap overflow for the heads up, mega-boss @JelleZijlstra!
(*Stationary inundation on undated stats!*)
  • Loading branch information
leycec committed May 30, 2024
1 parent e3f322b commit 4b27fbb
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 83 deletions.
6 changes: 6 additions & 0 deletions beartype/_check/code/codemake.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@ class variable or method annotated by this hint *or* :data:`None`).
hints_meta_index_last = -1

# ..................{ LOCALS ~ func : code }..................
#FIXME: [SPEED] Consider refactoring this into a "collections.deque[str]"
#data structure instead -- assuming that calling the deque.append() method
#is actually faster than performing string concatenations as we currently
#do, anyway. In theory, a deque *SHOULD* be substantially faster -- but
#everything depends on Python's internal implementation, really.

# Python code snippet type-checking the current pith against the currently
# visited hint (to be appended to the "func_wrapper_code" string).
func_curr_code: str = None # type: ignore[assignment]
Expand Down
6 changes: 3 additions & 3 deletions beartype/_data/code/datacodeindent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
This private submodule is *not* intended for importation by downstream callers.
'''

# ....................{ SUBCLASSES }....................
class IndentLevelToCode(dict):
# ....................{ PRIVATE ~ subclasses }....................
class _IndentLevelToCode(dict):
'''
**Indentation cache** (i.e., dictionary mapping from 1-based indentation
levels to the corresponding indentation string constant).
Expand Down Expand Up @@ -69,7 +69,7 @@ def __missing__(self, indent_level: int) -> str:
return indent_code

# ....................{ MAPPINGS }....................
INDENT_LEVEL_TO_CODE = IndentLevelToCode()
INDENT_LEVEL_TO_CODE = _IndentLevelToCode()
'''
**Indentation cache singleton** (i.e., global dictionary efficiently mapping
from 1-based indentation levels to the corresponding indentation string
Expand Down
93 changes: 83 additions & 10 deletions beartype/_util/py/utilpyversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,99 @@
# ....................{ IMPORTS }....................
from sys import version_info

# ....................{ CONSTANTS ~ at least }....................
# ....................{ CONSTANTS }....................
# While cumbersome, the current approach is substantially faster than automated
# alternatives (e.g., dictionary subclasses overriding the __missing__() dunder
# method to implement crude caches). Faster >>>> every other concern here, as
# Python interpreter version checks appear so frequently in critical code paths.

IS_PYTHON_AT_LEAST_4_0 = version_info >= (4, 0)
'''
:data:`True` only if the active Python interpreter targets at least Python
4.0.0.
'''


#FIXME: After dropping Python 3.15 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove this global.
#* Remove all decorators resembling:
# @skip_if_python_version_less_than('3.16.0')
IS_PYTHON_AT_LEAST_3_16 = IS_PYTHON_AT_LEAST_4_0 or version_info >= (3, 16)
'''
:data:`True` only if the active Python interpreter targets at least Python
3.16.0.
'''


#FIXME: After dropping Python 3.15 support:
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_15 = not IS_PYTHON_AT_LEAST_3_16
'''
:data:`True` only if the active Python interpreter targets at most Python
3.15.x.
'''


#FIXME: After dropping Python 3.14 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove this global.
#* Remove all decorators resembling:
# @skip_if_python_version_less_than('3.15.0')
IS_PYTHON_AT_LEAST_3_15 = IS_PYTHON_AT_LEAST_3_16 or version_info >= (3, 15)
'''
:data:`True` only if the active Python interpreter targets at least Python
3.15.0.
'''


#FIXME: Preserved if we ever require this. *shrug*
# #FIXME: After dropping Python 3.14 support:
# #* Remove all code conditionally testing this global.
# #* Remove this global.
# IS_PYTHON_AT_MOST_3_14 = not IS_PYTHON_AT_LEAST_3_15
# '''
# :data:`True` only if the active Python interpreter targets at most Python
# 3.14.x.
# '''


#FIXME: After dropping Python 3.13 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove this global.
#* Remove all decorators resembling:
# @skip_if_python_version_less_than('3.14.0')
IS_PYTHON_AT_LEAST_3_14 = IS_PYTHON_AT_LEAST_3_15 or version_info >= (3, 14)
'''
:data:`True` only if the active Python interpreter targets at least Python
3.14.0.
'''


#FIXME: After dropping Python 3.13 support:
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_13 = not IS_PYTHON_AT_LEAST_3_14
'''
:data:`True` only if the active Python interpreter targets at most Python
3.13.x.
'''


#FIXME: After dropping Python 3.12 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove this global.
#* Remove all decorators resembling:
# @skip_if_python_version_less_than('3.13.0')
IS_PYTHON_AT_LEAST_3_13 = IS_PYTHON_AT_LEAST_4_0 or version_info >= (3, 13)
IS_PYTHON_AT_LEAST_3_13 = IS_PYTHON_AT_LEAST_3_14 or version_info >= (3, 13)
'''
:data:`True` only if the active Python interpreter targets at least Python
3.12.0.
3.13.0.
'''

#FIXME: After dropping Python 3.13 support:

#FIXME: After dropping Python 3.11 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove this global.
#* Remove all decorators resembling:
Expand All @@ -43,8 +116,8 @@
'''


#FIXME: After dropping Python 3.10 support:
#* Refactor all code conditionally testing this global to be unconditional.
#FIXME: After dropping Python 3.11 support:
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_11 = not IS_PYTHON_AT_LEAST_3_12
'''
Expand All @@ -65,8 +138,8 @@
'''


#FIXME: After dropping Python 3.9 support:
#* Refactor all code conditionally testing this global to be unconditional.
#FIXME: After dropping Python 3.10 support:
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_10 = not IS_PYTHON_AT_LEAST_3_11
'''
Expand All @@ -88,7 +161,7 @@


#FIXME: After dropping Python 3.9 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_9 = not IS_PYTHON_AT_LEAST_3_10
'''
Expand All @@ -109,7 +182,7 @@


#FIXME: After dropping Python 3.8 support:
#* Refactor all code conditionally testing this global to be unconditional.
#* Remove all code conditionally testing this global.
#* Remove this global.
IS_PYTHON_AT_MOST_3_8 = not IS_PYTHON_AT_LEAST_3_9
'''
Expand Down
28 changes: 16 additions & 12 deletions beartype/door/_doorcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,15 @@ def is_subhint(subhint: object, superhint: object) -> bool:
Examples
--------
>>> from beartype.door import is_subhint
>>> is_subhint(int, int)
True
>>> is_subhint(Callable[[], list], Callable[..., Sequence[Any]])
True
>>> is_subhint(Callable[[], list], Callable[..., Sequence[int]])
False
.. code-block:: pycon
>>> from beartype.door import is_subhint
>>> is_subhint(int, int)
True
>>> is_subhint(Callable[[], list], Callable[..., Sequence[Any]])
True
>>> is_subhint(Callable[[], list], Callable[..., Sequence[int]])
False
'''

# Avoid circular import dependencies.
Expand Down Expand Up @@ -278,11 +280,13 @@ def munch_list_of_integers(lst: list[int]): ....
Examples
--------
>>> from beartype.door import is_bearable
>>> is_bearable(['Things', 'fall', 'apart;'], list[str])
True
>>> is_bearable(['the', 'centre', 'cannot', 'hold;'], list[int])
False
.. code-block:: pycon
>>> from beartype.door import is_bearable
>>> is_bearable(['Things', 'fall', 'apart;'], list[str])
True
>>> is_bearable(['the', 'centre', 'cannot', 'hold;'], list[int])
False
'''

# Memoized low-level type-checking tester function returning true only if
Expand Down
Loading

0 comments on commit 4b27fbb

Please sign in to comment.