-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds shallow type-checking support for **PEP 675 – Arbitrary Literal String Type** (i.e., `typing.LiteralString`). As PEP 675 advises for runtime type-checkers, @beartype now reduces (i.e., aliases) all `typing.LiteralString` type hints to the standard `str` type. Sadly, deeply type-checking literal strings is intractable for runtime type-checkers and is the textbook example of validation that can be performed *only* by static type-checkers. Type-checking literal strings requires: * Efficiently parsing abstract syntax trees (ASTs) at runtime (which is technically feasible, given sufficiently aggressive caching). * Correctly transitively inferring literal strings across operations and calls (which requires parsing the entire codebase of the app stack and constructing an in-memory graph of all type relations, which is pragmatically infeasible). This isn't to say that PEP 675 is bad, however. PEP 675 is actually *incredible*, reducing the attack surface of database injection attacks at static analysis time with *no* harmful tradeoffs. And... who knows? With enough intestinal fortitude, handlebar mustaches, and monocled eyepieces, perhaps even @beartype can surmount this Hill of Thorns. (*Nuanced dance of the prancing nougat!*)
- Loading branch information
Showing
7 changed files
with
172 additions
and
18 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
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,39 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright (c) 2014-2023 Beartype authors. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
Project-wide :pep:`647`-compliant **type hint** (i.e., objects created by | ||
subscripting the :obj:`typing.Final` type hint factory) utilities. | ||
This private submodule is *not* intended for importation by downstream callers. | ||
''' | ||
|
||
# ....................{ IMPORTS }.................... | ||
from beartype.typing import Type | ||
|
||
# ....................{ REDUCERS }.................... | ||
#FIXME: Unit test us up, please. | ||
def reduce_hint_pep675(*args, **kwargs) -> Type[str]: | ||
''' | ||
Reduce the passed :pep:`675`-compliant **literal string type hint** (i.e., | ||
the :obj:`typing.LiteralString` singleton) to the builtin :class:`str` class | ||
as advised by :pep:`675` when performing runtime type-checking. | ||
This reducer is intentionally *not* memoized (e.g., by the | ||
:func:`callable_cached` decorator), as the implementation trivially reduces | ||
to an efficient one-liner. | ||
Parameters | ||
---------- | ||
All passed arguments are silently ignored. | ||
Returns | ||
---------- | ||
Type[str] | ||
Builtin :class:`str` class. | ||
''' | ||
|
||
# Unconditionally reduce this hint to the builtin "str" class. | ||
return str |
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
84 changes: 84 additions & 0 deletions
84
beartype_test/a00_unit/data/hint/pep/proposal/_data_pep675.py
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,84 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright (c) 2014-2023 Beartype authors. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
Project-wide :pep:`604`-compliant **type hint test data.** | ||
''' | ||
|
||
# ....................{ IMPORTS }.................... | ||
from beartype._util.py.utilpyversion import IS_PYTHON_AT_LEAST_3_11 | ||
|
||
# ....................{ ADDERS }.................... | ||
def add_data(data_module: 'ModuleType') -> None: | ||
''' | ||
Add :pep:`604`-compliant type hint test data to various global containers | ||
declared by the passed module. | ||
Parameters | ||
---------- | ||
data_module : ModuleType | ||
Module to be added to. | ||
''' | ||
|
||
# If the active Python interpreter targets Python < 3.11, this interpreter | ||
# fails to support PEP 675. In this case, reduce to a noop. | ||
if not IS_PYTHON_AT_LEAST_3_11: | ||
return | ||
# Else, this interpreter supports PEP 675. | ||
|
||
# ..................{ IMPORTS }.................. | ||
# Defer attribute-dependent imports. | ||
from beartype._data.hint.pep.sign.datapepsigns import ( | ||
HintSignLiteralString) | ||
from beartype_test.a00_unit.data.hint.util.data_hintmetacls import ( | ||
HintPepMetadata, | ||
HintPithSatisfiedMetadata, | ||
HintPithUnsatisfiedMetadata, | ||
) | ||
from beartype.typing import LiteralString | ||
|
||
# ..................{ TUPLES }.................. | ||
# Add PEP 675-specific test type hints to this tuple global. | ||
data_module.HINTS_PEP_META.extend(( | ||
# ................{ PEP 675 }................ | ||
# Literal string type hint. | ||
HintPepMetadata( | ||
hint=LiteralString, | ||
pep_sign=HintSignLiteralString, | ||
piths_meta=( | ||
# Literal string statically defined from a literal string. | ||
HintPithSatisfiedMetadata( | ||
'All overgrown with azure moss and flowers'), | ||
# Literal string dynamically defined from the concatenation of | ||
# multiple literal strings, inducing type inference in PEP 675. | ||
HintPithSatisfiedMetadata( | ||
'So sweet, ' + 'the sense faints picturing them! ' + 'Thou' | ||
), | ||
# Non-literal string dynamically defined from a literal integer. | ||
# Ideally, @beartype should reject this non-literal; | ||
# pragmatically, runtime type-checkers are incapable of doing | ||
# so in the general case. For example, str() could have been | ||
# shadowed by a user-defined function of the same name returning | ||
# a valid literal string. | ||
HintPithSatisfiedMetadata(str(0xFEEDFACE)), | ||
|
||
# Literal byte string. | ||
HintPithUnsatisfiedMetadata( | ||
pith=b"For whose path the Atlantic's level powers", | ||
# Match that the exception message raised for this object | ||
# declares the types *NOT* satisfied by this object. | ||
exception_str_match_regexes=( | ||
r'\bstr\b', | ||
), | ||
# Match that the exception message raised for this object | ||
# does *NOT* contain a newline or bullet delimiter. | ||
exception_str_not_match_regexes=( | ||
r'\n', | ||
r'\*', | ||
), | ||
), | ||
), | ||
), | ||
)) |
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