-
-
Notifications
You must be signed in to change notification settings - Fork 50
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 adding transparent support for the third-party `typing_extensions.Annotated` type hint back-ported to Python < 3.9, en route to resolving #34. Once finalized, this will enable usage of beartype validators under Python < 3.9 via this hint. Specifically, this commit continues disastrously breaking literally everything by continuing to disembowel the feckless `beartype._util.hint.data.pep.datapep` submodule and its untrustworthy `beartype._util.hint.data.pep.proposal` crony subpackage in favour of `beartype._util.hint.data.pep.sign`, which is the only subpackage left standing. Save us from our reckless selves, GitHub! (*Crabby crabapples!*)
- Loading branch information
Showing
11 changed files
with
529 additions
and
568 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright (c) 2014-2021 Beartype authors. | ||
# See "LICENSE" for further details. | ||
|
||
# ....................{ TODO }.................... | ||
#FIXME: [FEATURE] Define the following supplementary decorators: | ||
#* @beartype.beartype_O1(), identical to the current @beartype.beartype() | ||
# decorator but provided for disambiguity. This decorator only type-checks | ||
# exactly one item from each container for each call rather than all items. | ||
#* @beartype.beartype_Ologn(), type-checking log(n) random items from each | ||
# container of "n" items for each call. | ||
#* @beartype.beartype_On(), type-checking all items from each container for | ||
# each call. We have various ideas littered about GitHub on how to optimize | ||
# this for various conditions, but this is never going to be ideal and should | ||
# thus never be the default. | ||
# | ||
#To differentiate between these three strategies, consider: | ||
#* Declare an enumeration in "beartype._decor._data" resembling: | ||
# from enum import Enum | ||
# BeartypeStrategyKind = Enum('BeartypeStrategyKind ('O1', 'Ologn', 'On',)) | ||
#* Define a new "BeartypeData.strategy_kind" instance variable. | ||
#* Set this variable to the corresponding "BeartypeStrategyKind" enumeration | ||
# member based on which of the three decorators listed above was called. | ||
#* Explicitly pass the value of the "BeartypeData.strategy_kind" instance | ||
# variable to the beartype._decor._code._pep._pephint.pep_code_check_hint() | ||
# function as a new memoized "strategy_kind" parameter. | ||
#* Conditionally generate type-checking code throughout that function depending | ||
# on the value of that parameter. | ||
|
||
#FIXME: Ensure that *ALL* calls to memoized callables throughout the codebase | ||
#are called with purely positional rather than keyword arguments. Currently, we | ||
#suspect the inverse is the case. To do so, we'll probably want to augment the | ||
#wrapper closure returned by the @callable_cached decorator to emit non-fatal | ||
#warnings when called with non-empty keyword arguments. | ||
# | ||
#Alternately, we might simply want to prohibit keyword arguments altogether by | ||
#defining a new @callable_cached_positional decorator restricted to positional | ||
#arguments. Right... That probably makes more sense. Make it so, ensign! | ||
# | ||
#Then, for generality: | ||
# | ||
#* Preserve the existing @callable_cached decorator as is. We won't be using | ||
# it, but there's little sense in destroying something beautiful. | ||
#* Globally replace all existing "@callable_cached" substrings with | ||
# "@callable_cached_positional". Voila! | ||
|
||
#FIXME: *CRITICAL EDGE CASE:* If the passed "func" is a coroutine, that | ||
#coroutine *MUST* be called preceded by the "await" keyword rather than merely | ||
#called as is. Detecting coroutines is trivial, thankfully: e.g., | ||
# | ||
# if inspect.iscoroutinefunction(func): | ||
# | ||
#Actually, shouldn't that be the more general-purpose test: | ||
# | ||
# if inspect.isawaitable(func): | ||
# | ||
#The latter seems more correct. In any case, given that: | ||
# | ||
#* Modify the "CODE_CALL_CHECKED" and "CODE_CALL_UNCHECKED" snippets to | ||
# conditionally precede the function call with the substring "await ": e.g., | ||
# CODE_CALL_UNCHECKED = ''' | ||
# return {func_await}__beartype_func(*args, **kwargs) | ||
# ''' | ||
# Note the absence of delimiting space. This is, of course, intentional. | ||
#* Unconditionally format the "func_await" substring into both of those | ||
# snippets, define ala: | ||
# format_await = 'await ' if inspect.iscoroutinefunction(func) else '' | ||
#* Oh, and note that our defined wrapper function must also be preceded by the | ||
# "async " keyword. So, we'll also need to augment "CODE_SIGNATURE". | ||
#FIXME: As a counterargument to the above approach, note this commentary I | ||
#stumbled across while researching an entirely separate topic: | ||
# "...trying to automatically detect whether a function is sync or async | ||
# it’s almost always a bad idea, because it’s very difficult to do reliably. | ||
# Instead it’s almost always better to make the user say explicitly which | ||
# one they mean, for example by having two versions of a decorator and | ||
# telling the user to use @mydecorator_sync on sync functions and | ||
# @mydecorator_async on async functions." | ||
#Is this actually the case? Clearly, we'll need to research just how | ||
#deterministic the inspect.isawaitable() tester is. Does that tester fall down | ||
#(i.e., return false negatives or positives) in well-known edge cases? | ||
#FIXME: Unit test this extensively, please. | ||
|
||
#FIXME: Non-critical optimization: if the active Python interpreter is already | ||
#performing static type checking (e.g., with Pyre or mypy), @beartype should | ||
#unconditionally reduce to a noop for the current process. Note that: | ||
# | ||
#* Detecting static type checking is trivial, as PEP 563 standardizes the newly | ||
# declared "typing.TYPE_CHECKING" boolean constant to be true only if static | ||
# type checking is currently occurring. Note that @beartype supports this now. | ||
#* Detecting whether static type checking just occurred is clearly less | ||
# trivial and possibly even infeasible. We're unclear what exactly separates | ||
# the "static type checking" phase from the runtime phase performed by static | ||
# type checkers, but something clearly does. If all else fails, we can | ||
# probably attempt to detect whether the basename of the command invoked by | ||
# the parent process matches "(Pyre|mypy|pyright|pytype)" or... something. Of | ||
# course, that itself is non-trivial due to Windows, so here we are. *sigh* | ||
|
||
#FIXME: Emit one non-fatal warning for each annotated type that is either: | ||
# | ||
#* "beartype.cave.UnavailableType". | ||
#* "beartype.cave.UnavailableTypes". | ||
# | ||
#Both cases imply user-side misconfiguration, but not sufficiently awful enough | ||
#to warrant fatal exceptions. Moreover, emitting warnings rather than | ||
#exceptions enables end users to unconditionally disable all unwanted warnings, | ||
#whereas no such facilities exist for unwanted exceptions. | ||
#FIXME: Validate all tuple annotations to be non-empty *EXCLUDING* | ||
#"beartype.cave.UnavailableTypes", which is intentionally empty. | ||
#FIXME: Unit test the above edge case. | ||
|
||
#FIXME: Add support for all possible kinds of parameters. @beartype currently | ||
#supports most but *NOT* all types. Specifically: | ||
# | ||
#* Type-check variadic keyword arguments. Currently, only variadic positional | ||
# arguments are type-checked. When doing so, remove the | ||
# "Parameter.VAR_KEYWORD" type from the "_PARAM_KIND_IGNORABLE" set. | ||
#* Type-check positional-only arguments under Python >= 3.8. Note that, since | ||
# C-based callables have *ALWAYS* supported positional-only arguments, the | ||
# "Parameter.POSITIONAL_ONLY" type is defined for *ALL* Python versions | ||
# despite only being usable in actual Python from Python >= 3.8. In other | ||
# words, support for type-checking positional-only arguments should be added | ||
# unconditionally without reference to Python version -- we suspect, anyway. | ||
# When doing so, remove the "Parameter.POSITIONAL_ONLY" type from the | ||
# "_PARAM_KIND_IGNORABLE" set. | ||
#* Remove the "_PARAM_KIND_IGNORABLE" set entirely. | ||
|
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,14 @@ | ||
#!/usr/bin/env python3 | ||
# --------------------( LICENSE )-------------------- | ||
# Copyright (c) 2014-2021 Beartype authors. | ||
# See "LICENSE" for further details. | ||
|
||
''' | ||
Project-wide **PEP-compliant type hint sign mappings** (i.e., dictionary | ||
globals mapping to and fro instances of the | ||
:class:`beartype._util.data.hint.pep.sign.datapepsigncls.HintSign` class, | ||
enabling efficient mapping between non-signs and their associated signs). | ||
This private submodule is *not* intended for importation by downstream callers. | ||
''' | ||
|
Oops, something went wrong.