Update from Yury.
This commit is contained in:
parent
e22d1112c4
commit
5f54b726b5
164
pep-0362.txt
164
pep-0362.txt
|
@ -51,12 +51,13 @@ A Signature object has the following public attributes and methods:
|
||||||
as listed in ``code.co_varnames``).
|
as listed in ``code.co_varnames``).
|
||||||
* bind(\*args, \*\*kwargs) -> BoundArguments
|
* bind(\*args, \*\*kwargs) -> BoundArguments
|
||||||
Creates a mapping from positional and keyword arguments to
|
Creates a mapping from positional and keyword arguments to
|
||||||
parameters. Raises a ``BindError`` (subclass of ``TypeError``)
|
parameters. Raises a ``TypeError`` if the passed arguments do
|
||||||
if the passed arguments do not match the signature.
|
not match the signature.
|
||||||
* bind_partial(\*args, \*\*kwargs) -> BoundArguments
|
* bind_partial(\*args, \*\*kwargs) -> BoundArguments
|
||||||
Works the same way as ``bind()``, but allows the omission
|
Works the same way as ``bind()``, but allows the omission
|
||||||
of some required arguments (mimics ``functools.partial``
|
of some required arguments (mimics ``functools.partial``
|
||||||
behavior.)
|
behavior.) Raises a ``TypeError`` if the passed arguments do
|
||||||
|
not match the signature.
|
||||||
* format(...) -> str
|
* format(...) -> str
|
||||||
Formats the Signature object to a string. Optional arguments allow
|
Formats the Signature object to a string. Optional arguments allow
|
||||||
for custom render functions for parameter names,
|
for custom render functions for parameter names,
|
||||||
|
@ -84,27 +85,53 @@ The structure of the Parameter object is:
|
||||||
|
|
||||||
* name : str
|
* name : str
|
||||||
The name of the parameter as a string.
|
The name of the parameter as a string.
|
||||||
|
|
||||||
* default : object
|
* default : object
|
||||||
The default value for the parameter, if specified. If the
|
The default value for the parameter, if specified. If the
|
||||||
parameter has no default value, this attribute is not set.
|
parameter has no default value, this attribute is not set.
|
||||||
|
|
||||||
* annotation : object
|
* annotation : object
|
||||||
The annotation for the parameter if specified. If the
|
The annotation for the parameter if specified. If the
|
||||||
parameter has no annotation, this attribute is not set.
|
parameter has no annotation, this attribute is not set.
|
||||||
* is_keyword_only : bool
|
|
||||||
True if the parameter is keyword-only, else False.
|
* kind : str
|
||||||
* is_args : bool
|
Describes how argument values are bound to the parameter.
|
||||||
True if the parameter accepts variable number of arguments
|
Possible values:
|
||||||
(``*args``-like), else False.
|
|
||||||
* is_kwargs : bool
|
* ``Parameter.POSITIONAL_ONLY`` - value must be supplied
|
||||||
True if the parameter accepts variable number of keyword
|
as a positional argument.
|
||||||
arguments (``**kwargs``-like), else False.
|
|
||||||
* is_implemented : bool
|
Python has no explicit syntax for defining positional-only
|
||||||
|
parameters, but many builtin and extension module functions
|
||||||
|
(especially those that accept only one or two parameters)
|
||||||
|
accept them.
|
||||||
|
|
||||||
|
* ``Parameter.POSITIONAL_OR_KEYWORD`` - value may be
|
||||||
|
supplied as either a keyword or positional argument
|
||||||
|
(this is the standard binding behaviour for functions
|
||||||
|
implemented in Python.)
|
||||||
|
|
||||||
|
* ``Parameter.KEYWORD_ONLY`` - value must be supplied
|
||||||
|
as a keyword argument. Keyword only parameters are those
|
||||||
|
which appear after a "*" or "\*args" entry in a Python
|
||||||
|
function definition.
|
||||||
|
|
||||||
|
* ``Parameter.VAR_POSITIONAL`` - a tuple of positional
|
||||||
|
arguments that aren't bound to any other parameter.
|
||||||
|
This corresponds to a "\*args" parameter in a Python
|
||||||
|
function definition.
|
||||||
|
|
||||||
|
* ``Parameter.VAR_KEYWORD`` - a dict of keyword arguments
|
||||||
|
that aren't bound to any other parameter. This corresponds
|
||||||
|
to a "\*\*kwds" parameter in a Python function definition.
|
||||||
|
|
||||||
|
* implemented : bool
|
||||||
True if the parameter is implemented for use. Some platforms
|
True if the parameter is implemented for use. Some platforms
|
||||||
implement functions but can't support specific parameters
|
implement functions but can't support specific parameters
|
||||||
(e.g. "mode" for ``os.mkdir``). Passing in an unimplemented
|
(e.g. "mode" for ``os.mkdir``). Passing in an unimplemented
|
||||||
parameter may result in the parameter being ignored,
|
parameter may result in the parameter being ignored,
|
||||||
or in NotImplementedError being raised. It is intended that
|
or in NotImplementedError being raised. It is intended that
|
||||||
all conditions where ``is_implemented`` may be False be
|
all conditions where ``implemented`` may be False be
|
||||||
thoroughly documented.
|
thoroughly documented.
|
||||||
|
|
||||||
Two parameters are equal when all their attributes are equal.
|
Two parameters are equal when all their attributes are equal.
|
||||||
|
@ -159,12 +186,11 @@ The function implements the following algorithm:
|
||||||
- If it is ``None`` and the object is an instance of
|
- If it is ``None`` and the object is an instance of
|
||||||
``BuiltinFunction``, raise a ``ValueError``
|
``BuiltinFunction``, raise a ``ValueError``
|
||||||
|
|
||||||
- If the object is a an instance of ``FunctionType``:
|
- If it has a ``__wrapped__`` attribute, return
|
||||||
|
``signature(object.__wrapped__)``
|
||||||
|
|
||||||
- If it has a ``__wrapped__`` attribute, return
|
- If the object is a an instance of ``FunctionType`` construct
|
||||||
``signature(object.__wrapped__)``
|
and return a new ``Signature`` for it
|
||||||
|
|
||||||
- Or else construct a new ``Signature`` object and return it
|
|
||||||
|
|
||||||
- If the object is a method or a classmethod, construct and return
|
- If the object is a method or a classmethod, construct and return
|
||||||
a new ``Signature`` object, with its first parameter (usually
|
a new ``Signature`` object, with its first parameter (usually
|
||||||
|
@ -223,6 +249,9 @@ Examples
|
||||||
|
|
||||||
Visualizing Callable Objects' Signature
|
Visualizing Callable Objects' Signature
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
Let's define some classes and functions:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
from inspect import signature
|
from inspect import signature
|
||||||
|
@ -245,25 +274,62 @@ Visualizing Callable Objects' Signature
|
||||||
return a, b, c
|
return a, b, c
|
||||||
|
|
||||||
|
|
||||||
print('FooMeta >', str(signature(FooMeta)))
|
def shared_vars(*shared_args):
|
||||||
print('Foo >', str(signature(Foo)))
|
"""Decorator factory that defines shared variables that are
|
||||||
print('Foo.__call__ >', str(signature(Foo.__call__)))
|
passed to every invocation of the function"""
|
||||||
print('Foo().__call__ >', str(signature(Foo().__call__)))
|
|
||||||
print('partial(Foo().__call__, 1, c=3) >',
|
def decorator(f):
|
||||||
str(signature(partial(Foo().__call__, 1, c=3))))
|
@wraps(f)
|
||||||
print('partial(partial(Foo().__call__, 1, c=3), 2, c=20) >',
|
def wrapper(*args, **kwds):
|
||||||
str(signature(partial(partial(Foo().__call__, 1, c=3), 2, c=20))))
|
full_args = shared_args + args
|
||||||
|
return f(*full_args, **kwds)
|
||||||
|
# Override signature
|
||||||
|
sig = wrapper.__signature__ = signature(f)
|
||||||
|
for __ in shared_args:
|
||||||
|
sig.parameters.popitem(last=False)
|
||||||
|
return wrapper
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
The script will output:
|
@shared_vars({})
|
||||||
|
def example(_state, a, b, c):
|
||||||
|
return _state, a, b, c
|
||||||
|
|
||||||
|
|
||||||
|
def format_signature(obj):
|
||||||
|
return str(signature(obj))
|
||||||
|
|
||||||
|
|
||||||
|
Now, in the python REPL:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
FooMeta > (name, bases, dct, *, bar:bool=False)
|
>>> format_signature(FooMeta)
|
||||||
Foo > (spam:int=42)
|
'(name, bases, dct, *, bar:bool=False)'
|
||||||
Foo.__call__ > (self, a, b, *, c) -> tuple
|
|
||||||
Foo().__call__ > (a, b, *, c) -> tuple
|
>>> format_signature(Foo)
|
||||||
partial(Foo().__call__, 1, c=3) > (b, *, c=3) -> tuple
|
'(spam:int=42)'
|
||||||
partial(partial(Foo().__call__, 1, c=3), 2, c=20) > (*, c=20) -> tuple
|
|
||||||
|
>>> format_signature(Foo.__call__)
|
||||||
|
'(self, a, b, *, c) -> tuple'
|
||||||
|
|
||||||
|
>>> format_signature(Foo().__call__)
|
||||||
|
'(a, b, *, c) -> tuple'
|
||||||
|
|
||||||
|
>>> format_signature(partial(Foo().__call__, 1, c=3))
|
||||||
|
'(b, *, c=3) -> tuple'
|
||||||
|
|
||||||
|
>>> format_signature(partial(partial(Foo().__call__, 1, c=3), 2, c=20))
|
||||||
|
'(*, c=20) -> tuple'
|
||||||
|
|
||||||
|
>>> format_signature(example)
|
||||||
|
'(a, b, c)'
|
||||||
|
|
||||||
|
>>> format_signature(partial(example, 1, 2))
|
||||||
|
'(c)'
|
||||||
|
|
||||||
|
>>> format_signature(partial(partial(example, 1, b=2), c=3))
|
||||||
|
'(b=2, c=3)'
|
||||||
|
|
||||||
|
|
||||||
Annotation Checker
|
Annotation Checker
|
||||||
|
@ -317,14 +383,14 @@ Annotation Checker
|
||||||
else:
|
else:
|
||||||
if not isinstance(default, type_):
|
if not isinstance(default, type_):
|
||||||
raise ValueError("{func}: wrong type of a default value for {arg!r}". \
|
raise ValueError("{func}: wrong type of a default value for {arg!r}". \
|
||||||
format(func=sig.qualname, arg=param.name))
|
format(func=func.__qualname__, arg=param.name))
|
||||||
|
|
||||||
def check_type(sig, arg_name, arg_type, arg_value):
|
def check_type(sig, arg_name, arg_type, arg_value):
|
||||||
# Internal function that encapsulates arguments type checking
|
# Internal function that encapsulates arguments type checking
|
||||||
if not isinstance(arg_value, arg_type):
|
if not isinstance(arg_value, arg_type):
|
||||||
raise ValueError("{func}: wrong type of {arg!r} argument, " \
|
raise ValueError("{func}: wrong type of {arg!r} argument, " \
|
||||||
"{exp!r} expected, got {got!r}". \
|
"{exp!r} expected, got {got!r}". \
|
||||||
format(func=sig.qualname, arg=arg_name,
|
format(func=func.__qualname__, arg=arg_name,
|
||||||
exp=arg_type.__name__, got=type(arg_value).__name__))
|
exp=arg_type.__name__, got=type(arg_value).__name__))
|
||||||
|
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
|
@ -341,12 +407,12 @@ Annotation Checker
|
||||||
# OK, we have a type for the argument, lets get the corresponding
|
# OK, we have a type for the argument, lets get the corresponding
|
||||||
# parameter description from the signature object
|
# parameter description from the signature object
|
||||||
param = sig.parameters[arg_name]
|
param = sig.parameters[arg_name]
|
||||||
if param.is_args:
|
if param.kind == param.VAR_POSITIONAL:
|
||||||
# If this parameter is a variable-argument parameter,
|
# If this parameter is a variable-argument parameter,
|
||||||
# then we need to check each of its values
|
# then we need to check each of its values
|
||||||
for value in arg:
|
for value in arg:
|
||||||
check_type(sig, arg_name, type_, value)
|
check_type(sig, arg_name, type_, value)
|
||||||
elif param.is_kwargs:
|
elif param.kind == param.VAR_KEYWORD:
|
||||||
# If this parameter is a variable-keyword-argument parameter:
|
# If this parameter is a variable-keyword-argument parameter:
|
||||||
for subname, value in arg.items():
|
for subname, value in arg.items():
|
||||||
check_type(sig, arg_name + ':' + subname, type_, value)
|
check_type(sig, arg_name + ':' + subname, type_, value)
|
||||||
|
@ -364,13 +430,35 @@ Annotation Checker
|
||||||
else:
|
else:
|
||||||
if isinstance(return_type, type) and not isinstance(result, return_type):
|
if isinstance(return_type, type) and not isinstance(result, return_type):
|
||||||
raise ValueError('{func}: wrong return type, {exp} expected, got {got}'. \
|
raise ValueError('{func}: wrong return type, {exp} expected, got {got}'. \
|
||||||
format(func=sig.qualname, exp=return_type.__name__,
|
format(func=func.__qualname__, exp=return_type.__name__,
|
||||||
got=type(result).__name__))
|
got=type(result).__name__))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
Render Function Signature to HTML
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
def format_to_html(func):
|
||||||
|
sig = inspect.signature(func)
|
||||||
|
|
||||||
|
html = sig.format(token_params_separator='<span class="t-comma">,</span>',
|
||||||
|
token_colon='<span class="t-colon">:</span>',
|
||||||
|
token_eq='<span class="t-eq">=</span>',
|
||||||
|
token_return_annotation='<span class="t-ra">-></span>',
|
||||||
|
token_left_paren='<span class="t-lp">(</span>',
|
||||||
|
token_right_paren='<span class="t-lp">)</span>',
|
||||||
|
token_kwonly_separator='<span class="t-ast">*</span>',
|
||||||
|
format_name=lambda name: '<span class="name">'+name+'</span>')
|
||||||
|
|
||||||
|
return '<span class="py-func">{}</span>'.format(html)
|
||||||
|
|
||||||
|
|
||||||
References
|
References
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue