1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
#!/usr/bin/env python3
# --------------------( LICENSE )--------------------
# Copyright (c) 2014-2025 Beartype authors.
# See "LICENSE" for further details.
'''
Project-wide **wrapper function code snippets** (i.e., triple-quoted pure-Python
string constants formatted and concatenated together to dynamically generate the
implementations of wrapper functions type-checking
:func:`beartype.beartype`-decorated callables).
This private submodule is *not* intended for importation by downstream callers.
'''
# ....................{ IMPORTS }....................
from beartype._data.code.datacodename import (
ARG_NAME_ARGS_NAME_KEYWORDABLE,
ARG_NAME_FUNC,
ARG_NAME_GET_VIOLATION,
VAR_NAME_ARGS_LEN,
VAR_NAME_PITH_ROOT,
)
from beartype._data.code.datacodeindent import CODE_INDENT_1
from beartype._data.typing.datatyping import CallableStrFormat
from beartype._util.func.arg.utilfuncargiter import ArgKind
# ....................{ CODE }....................
CODE_SIGNATURE = f'''{{code_signature_prefix}}def {{func_name}}(
*args,
{{code_signature_scope_args}}{CODE_INDENT_1}**kwargs
):'''
'''
Code snippet declaring the signature of a type-checking callable.
Note that the :func:`beartype._check.signature.make_signature` factory function
internally interpolates these format variables into this string as follows:
* ``code_signature_prefix`` is replaced by:
* For synchronous callables, the empty string.
* For asynchronous coroutines (but *not* asynchronous generators, curiously),
the space-suffixed keyword ``"async "``.
* ``code_signature_scope_args`` is replaced by a comma-delimited string listing
all :mod:`beartype`-specific hidden parameters internally required to
type-check the currently decorated callable.
'''
CODE_INIT_ARGS_LEN = f'''
# Localize the number of passed positional arguments for efficiency.
{VAR_NAME_ARGS_LEN} = len(args)'''
'''
Code snippet localizing the number of passed positional arguments for callables
accepting one or more such arguments.
'''
# ....................{ CODE ~ arg }....................
ARG_KIND_TO_CODE_LOCALIZE = {
# Snippet localizing any positional-only parameter (e.g.,
# "{posonlyarg}, /") by lookup in the wrapper's "*args" dictionary.
ArgKind.POSITIONAL_ONLY: f'''
# If this positional-only parameter was passed...
if {VAR_NAME_ARGS_LEN} > {{arg_index}}:
# Localize this positional-only parameter.
{VAR_NAME_PITH_ROOT} = args[{{arg_index}}]''',
# Snippet localizing any positional or keyword parameter as follows:
#
# * If this parameter's 0-based index (in the parameter list of the
# decorated callable's signature) does *NOT* exceed the number of
# positional parameters passed to the wrapper function, localize this
# positional parameter from the wrapper's variadic "*args" tuple.
# * Else if this parameter's name is in the dictionary of keyword
# parameters passed to the wrapper function, localize this keyword
# parameter from the wrapper's variadic "*kwargs" tuple.
# * Else, this parameter is unpassed. In this case, localize this parameter
# as a placeholder value guaranteed to *NEVER* be passed to any wrapper
# function: the private "__beartypistry" singleton passed to this wrapper
# function as a hidden default parameter and thus accessible here. While
# we could pass a "__beartype_sentinel" parameter to all wrapper
# functions defaulting to "object()" and then use that here instead,
# doing so would slightly reduce efficiency for no tangible gain. *shrug*
ArgKind.POSITIONAL_OR_KEYWORD: f'''
# Localize this positional or keyword parameter if passed *OR* to the
# sentinel "__beartype_raise_exception" guaranteed to never be passed.
{VAR_NAME_PITH_ROOT} = (
args[{{arg_index}}] if {VAR_NAME_ARGS_LEN} > {{arg_index}} else
kwargs.get({{arg_name!r}}, {ARG_NAME_GET_VIOLATION})
)
# If this parameter was passed...
if {VAR_NAME_PITH_ROOT} is not {ARG_NAME_GET_VIOLATION}:''',
# Snippet localizing any keyword-only parameter (e.g., "*, {kwarg}") by
# lookup in the wrapper's variadic "**kwargs" dictionary. (See above.)
ArgKind.KEYWORD_ONLY: f'''
# Localize this keyword-only parameter if passed *OR* to the sentinel value
# "__beartype_raise_exception" guaranteed to never be passed.
{VAR_NAME_PITH_ROOT} = kwargs.get({{arg_name!r}}, {ARG_NAME_GET_VIOLATION})
# If this parameter was passed...
if {VAR_NAME_PITH_ROOT} is not {ARG_NAME_GET_VIOLATION}:''',
#FIXME: [SPEED] Optimize this from a "for" into "while" loop, please.
#"while" loops internally raise *NO* "StopException" whereas "for" loops do.
#Snippet iteratively localizing all variadic positional parameters. *sigh*
ArgKind.VARIADIC_POSITIONAL: f'''
# For all excess positional parameters in the passed "*args" parameter...
for {VAR_NAME_PITH_ROOT} in args[{{arg_index!r}}:]:''',
#FIXME: [SPEED] Optimize this from a "for" into "while" loop. See above!
# Snippet iteratively localizing all variadic keyword parameters.
ArgKind.VARIADIC_KEYWORD: f'''
# For all excess keyword parameters in the passed "**kwargs" parameter,
# decided by subtracting the subset of all keywordable parameters
# explicitly accepted by this callable from the set of all parameters passed
# by keyword to this callable...
for {VAR_NAME_PITH_ROOT} in (
(kwargs[kwarg_name] for kwarg_name in kwargs.keys() - {ARG_NAME_ARGS_NAME_KEYWORDABLE})):''',
}
'''
Dictionary mapping from the type of each callable parameter supported by the
:func:`beartype.beartype` decorator to a code snippet localizing that callable's
next parameter to be type-checked.
'''
# ....................{ CODE ~ return ~ check }....................
CODE_CALL_CHECKED = f'''
# Call this function with all passed parameters and localize the value
# returned from this call.
{VAR_NAME_PITH_ROOT} = {{func_call_prefix}}{ARG_NAME_FUNC}(*args, **kwargs)
# Noop required to artificially increase indentation level. Note that
# CPython implicitly optimizes this conditional away. Isn't that nice?
if True:'''
'''
Code snippet calling the decorated callable and localizing the value returned by
that call.
Note that:
* The :func:`beartype._decor._nontype._wrap.wrapmaingenerate_code` factory
function internally interpolates these format variables into this string as
follows:
* ``func_call_prefix`` is replaced by:
* For synchronous callables, the empty string.
* For asynchronous coroutine factories (but *not* asynchronous generator
factories, curiously), the space-suffixed keyword ``"await "``.
* This snippet intentionally terminates on a noop increasing the indentation
level, enabling subsequent type-checking code to effectively ignore
indentation level and thus uniformly operate on both:
* Parameters localized via values of the
:data:`.PARAM_KIND_TO_PEP_CODE_LOCALIZE` dictionary.
* Return values localized via this snippet.
See Also
--------
https://stackoverflow.com/a/18124151/2809027
Bytecode disassembly demonstrating that CPython optimizes away the spurious
``if True:`` conditional hardcoded into this snippet.
'''
CODE_NORMAL_RETURN_CHECKED = f'''
return {VAR_NAME_PITH_ROOT}'''
'''
Code snippet returning from the wrapper function the successfully type-checked
value returned from the **normal callable** (either synchronous or asynchronous
non-generator callable decorated by :func:`beartype.beartype`).
'''
# ....................{ CODE ~ return ~ uncheck }....................
CODE_NORMAL_RETURN_UNCHECKED_SYNC = f'''
# Call this function with all passed parameters and return the value
# returned from this call as is (without being type-checked).
return {ARG_NAME_FUNC}(*args, **kwargs)'''
'''
Code snippet calling the **normal synchronous callable** (non-generator callable
decorated by :func:`beartype.beartype` defined with the ``def`` rather than
``async def`` keyword) *without* type-checking the value returned by that call
(if any).
'''
CODE_NORMAL_RETURN_UNCHECKED_ASYNC = f'''
# Call this function with all passed parameters and return the value
# returned from this call as is (without being type-checked).
return await {ARG_NAME_FUNC}(*args, **kwargs)'''
'''
Code snippet calling the **normal asynchronous callable** (non-generator
callable decorated by :func:`beartype.beartype` defined with the ``async def``
rather than ``def`` keywords) *without* type-checking the value returned by that
call (if any).
'''
# ..................{ FORMATTERS }..................
# str.format() methods, globalized to avoid inefficient dot lookups elsewhere.
# This is an absurd micro-optimization. *fight me, github developer community*
CODE_CALL_CHECKED_format: CallableStrFormat = CODE_CALL_CHECKED.format
|