-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit is the next in a commit chain deeply type-checking **reiterables** (i.e., collections satisfying the `collections.abc.Collection` protocol with guaranteed `O(1)` read-only access to *only* the first collection item), en-route to *finally* resolving feature request #167 kindly submitted by the perennial brilliant @langfield (...*how I miss that awesome guy!*) several lifetimes ago back when I was probably a wandering vagabond Buddhist monk with a bad attitude, a begging bowl the size of my emaciated torso, and an honestly pretty cool straw hat that glinted dangerously in the firelight. Note that reiterables include *all* containers matched by one or more of the following PEP 484- or 585-compliant type hints: * `frozenset[...]`. * `set[...]`. * `collections.deque[...]`. * `collections.abc.Collection[...]`. * `collections.abc.KeysView[...]`. * `collections.abc.MutableSet[...]`. * `collections.abc.Set[...]`. * `collections.abc.ValuesView[...]`. * `typing.AbstractSet[...]`. * `typing.Collection[...]`. * `typing.Deque[...]`. * `typing.FrozenSet[...]`. * `typing.KeysView[...]`. * `typing.MutableSet[...]`. * `typing.Set[...]`. * `typing.ValuesView[...]`. Specifically, this commit continues reducing problematic DRY (Don't Repeat Yourself) violations in @beartype's internal type-checking code generator. (*Numerous Numenoreans in a Hyperborean hyperbole!*)
- Loading branch information
Showing
5 changed files
with
233 additions
and
246 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright (c) 2014-2024 Beartype authors. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
Beartype **hint sign logic class hierarchy** (i.e., dataclasses encapsulating | ||
all low-level Python code snippets and associated metadata required to | ||
dynamically generate high-level Python code snippets fully type-checking various | ||
kinds of type hints uniquely identified by common signs). | ||
This private submodule is *not* intended for importation by downstream callers. | ||
''' | ||
|
||
# ....................{ IMPORTS }.................... | ||
from beartype._data.hint.datahinttyping import CallableStrFormat | ||
from beartype.typing import ( | ||
TYPE_CHECKING, | ||
Optional, | ||
) | ||
|
||
# ....................{ CLASSES }.................... | ||
class HintSignLogic(object): | ||
''' | ||
**Hint sign logic** (i.e., dataclass encapsulating all low-level Python code | ||
snippets and associated metadata required to dynamically generate a | ||
high-level Python code snippet fully type-checking some kind of type hint | ||
uniquely identified by a common sign). | ||
Caveats | ||
------- | ||
**Each such snippet must not contain ternary conditionals.** For unknown | ||
reasons suggesting a critical defect in the current implementation of Python | ||
3.8's assignment expressions, the following snippet raises | ||
:exc:`UnboundLocalError` exceptions resembling the following when this | ||
snippet contains one or more ternary conditionals: | ||
UnboundLocalError: local variable '__beartype_pith_1' referenced before | ||
assignment | ||
In particular, the initial draft of these snippets guarded against empty | ||
sequences with a seemingly reasonable ternary conditional: | ||
.. code-block:: python | ||
CODE_PEP484585_SEQUENCE_ARGS_1 = \'\'\'( | ||
{indent_curr} isinstance({pith_curr_assign_expr}, {hint_curr_expr}) and | ||
{indent_curr} {hint_child_placeholder} if {pith_curr_var_name} else True | ||
{indent_curr})\'\'\' | ||
That should behave as expected, but doesn't, presumably due to obscure | ||
scoping rules and a non-intuitive implementation of ternary conditionals in | ||
CPython. Ergo, the current version of this snippet guards against empty | ||
sequences with disjunctions and conjunctions (i.e., ``or`` and ``and`` | ||
operators) instead. Happily, the current version is more efficient than the | ||
equivalent approach based on ternary conditional (albeit less intuitive). | ||
Attributes | ||
---------- | ||
code_format : CallableStrFormat | ||
:meth:`str.format` method bound to a Python code snippet fully | ||
type-checking the current pith against this kind of type hint. | ||
is_var_random_int_needed : bool | ||
True only if the Python code snippet dynamically generated by calling | ||
the :attr:`code_format` method requires a pseudo-random integer by | ||
accessing the :data:`VAR_NAME_RANDOM_INT` local. If true, the body of | ||
the current wrapper function will be prefixed by a Python statement | ||
assigning such an integer to this local. | ||
pith_child_expr_format : CallableStrFormat | ||
:meth:`str.format` method bound to a Python expression efficiently | ||
yielding the value of the next item (which will then be type-checked) | ||
contained in the **current pith** (which is the parent container | ||
currently being type-checked). | ||
''' | ||
|
||
# ..................{ CLASS VARIABLES }.................. | ||
# Slot all instance variables defined on this object to minimize the time | ||
# complexity of both reading and writing variables across frequently called | ||
# cache dunder methods. Slotting has been shown to reduce read and write | ||
# costs by approximately ~10%, which is non-trivial. | ||
__slots__ = ( | ||
'code_format', | ||
'is_var_random_int_needed', | ||
'pith_child_expr_format', | ||
) | ||
|
||
# Squelch false negatives from mypy. This is absurd. This is mypy. See: | ||
# https://github.com/python/mypy/issues/5941 | ||
if TYPE_CHECKING: | ||
code_format : CallableStrFormat | ||
is_var_random_int_needed : bool | ||
pith_child_expr_format : CallableStrFormat | ||
|
||
# ..................{ INITIALIZERS }.................. | ||
def __init__( | ||
self, | ||
|
||
# Mandatory parameters. | ||
code_format: CallableStrFormat, | ||
|
||
# Optional parameters. | ||
# | ||
# For convenience, permit callers to avoid having to initially define | ||
# all possible parameters all-at-once by defaulting all parameters to | ||
# *REASONABLY* sane defaults. | ||
is_var_random_int_needed: bool = False, | ||
pith_child_expr_format: Optional[CallableStrFormat] = None, | ||
) -> None: | ||
''' | ||
Initialize this hint sign logic. | ||
Parameters | ||
---------- | ||
See the class docstring for further details. | ||
''' | ||
|
||
# Classify all passed parameters. | ||
self.code_format = code_format | ||
self.is_var_random_int_needed = is_var_random_int_needed | ||
self.pith_child_expr_format = pith_child_expr_format # type: ignore[assignment] |
Oops, something went wrong.