Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
7c7cbfc0
Kaydet (Commit)
7c7cbfc0
authored
Haz 22, 2012
tarafından
Larry Hastings
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Issue #15008: Implement PEP 362 "Signature Objects".
Patch by Yury Selivanov.
üst
8e0d2550
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1697 additions
and
4 deletions
+1697
-4
inspect.py
Lib/inspect.py
+772
-3
test_inspect.py
Lib/test/test_inspect.py
+922
-1
NEWS
Misc/NEWS
+3
-0
No files found.
Lib/inspect.py
Dosyayı görüntüle @
7c7cbfc0
...
...
@@ -22,12 +22,14 @@ Here are some of the useful functions provided by this module:
getouterframes(), getinnerframes() - get info about frames
currentframe() - get the current stack frame
stack(), trace() - get info about frames on the stack or in a traceback
signature() - get a Signature object for the callable
"""
# This module is in the public domain. No warranties.
__author__
=
'Ka-Ping Yee <ping@lfw.org>'
__date__
=
'1 Jan 2001'
__author__
=
(
'Ka-Ping Yee <ping@lfw.org>'
,
'Yury Selivanov <yselivanov@sprymix.com>'
)
import
imp
import
importlib.machinery
...
...
@@ -39,8 +41,9 @@ import sys
import
tokenize
import
types
import
warnings
import
functools
from
operator
import
attrgetter
from
collections
import
namedtuple
from
collections
import
namedtuple
,
OrderedDict
# Create constants for the compiler flags in Include/code.h
# We try to get them from dis to avoid duplication, but fall
...
...
@@ -1223,3 +1226,769 @@ def getgeneratorstate(generator):
if
generator
.
gi_frame
.
f_lasti
==
-
1
:
return
GEN_CREATED
return
GEN_SUSPENDED
###############################################################################
### Function Signature Object (PEP 362)
###############################################################################
_WrapperDescriptor
=
type
(
type
.
__call__
)
_MethodWrapper
=
type
(
all
.
__call__
)
_NonUserDefinedCallables
=
(
_WrapperDescriptor
,
_MethodWrapper
,
types
.
BuiltinFunctionType
)
def
_get_user_defined_method
(
cls
,
method_name
):
try
:
meth
=
getattr
(
cls
,
method_name
)
except
AttributeError
:
return
else
:
if
not
isinstance
(
meth
,
_NonUserDefinedCallables
):
# Once '__signature__' will be added to 'C'-level
# callables, this check won't be necessary
return
meth
def
signature
(
obj
):
'''Get a signature object for the passed callable.'''
if
not
callable
(
obj
):
raise
TypeError
(
'{!r} is not a callable object'
.
format
(
obj
))
if
isinstance
(
obj
,
types
.
MethodType
):
# In this case we skip the first parameter of the underlying
# function (usually `self` or `cls`).
sig
=
signature
(
obj
.
__func__
)
return
sig
.
replace
(
parameters
=
tuple
(
sig
.
parameters
.
values
())[
1
:])
try
:
sig
=
obj
.
__signature__
except
AttributeError
:
pass
else
:
if
sig
is
not
None
:
return
sig
try
:
# Was this function wrapped by a decorator?
wrapped
=
obj
.
__wrapped__
except
AttributeError
:
pass
else
:
return
signature
(
wrapped
)
if
isinstance
(
obj
,
types
.
FunctionType
):
return
Signature
.
from_function
(
obj
)
if
isinstance
(
obj
,
functools
.
partial
):
sig
=
signature
(
obj
.
func
)
new_params
=
OrderedDict
(
sig
.
parameters
.
items
())
partial_args
=
obj
.
args
or
()
partial_keywords
=
obj
.
keywords
or
{}
try
:
ba
=
sig
.
bind_partial
(
*
partial_args
,
**
partial_keywords
)
except
TypeError
as
ex
:
msg
=
'partial object {!r} has incorrect arguments'
.
format
(
obj
)
raise
ValueError
(
msg
)
from
ex
for
arg_name
,
arg_value
in
ba
.
arguments
.
items
():
param
=
new_params
[
arg_name
]
if
arg_name
in
partial_keywords
:
# We set a new default value, because the following code
# is correct:
#
# >>> def foo(a): print(a)
# >>> print(partial(partial(foo, a=10), a=20)())
# 20
# >>> print(partial(partial(foo, a=10), a=20)(a=30))
# 30
#
# So, with 'partial' objects, passing a keyword argument is
# like setting a new default value for the corresponding
# parameter
#
# We also mark this parameter with '_partial_kwarg'
# flag. Later, in '_bind', the 'default' value of this
# parameter will be added to 'kwargs', to simulate
# the 'functools.partial' real call.
new_params
[
arg_name
]
=
param
.
replace
(
default
=
arg_value
,
_partial_kwarg
=
True
)
elif
(
param
.
kind
not
in
(
_VAR_KEYWORD
,
_VAR_POSITIONAL
)
and
not
param
.
_partial_kwarg
):
new_params
.
pop
(
arg_name
)
return
sig
.
replace
(
parameters
=
new_params
.
values
())
sig
=
None
if
isinstance
(
obj
,
type
):
# obj is a class or a metaclass
# First, let's see if it has an overloaded __call__ defined
# in its metaclass
call
=
_get_user_defined_method
(
type
(
obj
),
'__call__'
)
if
call
is
not
None
:
sig
=
signature
(
call
)
else
:
# Now we check if the 'obj' class has a '__new__' method
new
=
_get_user_defined_method
(
obj
,
'__new__'
)
if
new
is
not
None
:
sig
=
signature
(
new
)
else
:
# Finally, we should have at least __init__ implemented
init
=
_get_user_defined_method
(
obj
,
'__init__'
)
if
init
is
not
None
:
sig
=
signature
(
init
)
elif
not
isinstance
(
obj
,
_NonUserDefinedCallables
):
# An object with __call__
# We also check that the 'obj' is not an instance of
# _WrapperDescriptor or _MethodWrapper to avoid
# infinite recursion (and even potential segfault)
call
=
_get_user_defined_method
(
type
(
obj
),
'__call__'
)
if
call
is
not
None
:
sig
=
signature
(
call
)
if
sig
is
not
None
:
# For classes and objects we skip the first parameter of their
# __call__, __new__, or __init__ methods
return
sig
.
replace
(
parameters
=
tuple
(
sig
.
parameters
.
values
())[
1
:])
if
isinstance
(
obj
,
types
.
BuiltinFunctionType
):
# Raise a nicer error message for builtins
msg
=
'no signature found for builtin function {!r}'
.
format
(
obj
)
raise
ValueError
(
msg
)
raise
ValueError
(
'callable {!r} is not supported by signature'
.
format
(
obj
))
class
_void
:
'''A private marker - used in Parameter & Signature'''
class
_empty
:
pass
class
_ParameterKind
(
int
):
def
__new__
(
self
,
*
args
,
name
):
obj
=
int
.
__new__
(
self
,
*
args
)
obj
.
_name
=
name
return
obj
def
__str__
(
self
):
return
self
.
_name
def
__repr__
(
self
):
return
'<_ParameterKind: {!r}>'
.
format
(
self
.
_name
)
_POSITIONAL_ONLY
=
_ParameterKind
(
0
,
name
=
'POSITIONAL_ONLY'
)
_POSITIONAL_OR_KEYWORD
=
_ParameterKind
(
1
,
name
=
'POSITIONAL_OR_KEYWORD'
)
_VAR_POSITIONAL
=
_ParameterKind
(
2
,
name
=
'VAR_POSITIONAL'
)
_KEYWORD_ONLY
=
_ParameterKind
(
3
,
name
=
'KEYWORD_ONLY'
)
_VAR_KEYWORD
=
_ParameterKind
(
4
,
name
=
'VAR_KEYWORD'
)
class
Parameter
:
'''Represents a parameter in a function signature.
Has the following public attributes:
* name : str
The name of the parameter as a string.
* default : object
The default value for the parameter if specified. If the
parameter has no default value, this attribute is not set.
* annotation
The annotation for the parameter if specified. If the
parameter has no annotation, this attribute is not set.
* kind : str
Describes how argument values are bound to the parameter.
Possible values: `Parameter.POSITIONAL_ONLY`,
`Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
`Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
'''
__slots__
=
(
'_name'
,
'_kind'
,
'_default'
,
'_annotation'
,
'_partial_kwarg'
)
POSITIONAL_ONLY
=
_POSITIONAL_ONLY
POSITIONAL_OR_KEYWORD
=
_POSITIONAL_OR_KEYWORD
VAR_POSITIONAL
=
_VAR_POSITIONAL
KEYWORD_ONLY
=
_KEYWORD_ONLY
VAR_KEYWORD
=
_VAR_KEYWORD
empty
=
_empty
def
__init__
(
self
,
name
,
kind
,
*
,
default
=
_empty
,
annotation
=
_empty
,
_partial_kwarg
=
False
):
if
kind
not
in
(
_POSITIONAL_ONLY
,
_POSITIONAL_OR_KEYWORD
,
_VAR_POSITIONAL
,
_KEYWORD_ONLY
,
_VAR_KEYWORD
):
raise
ValueError
(
"invalid value for 'Parameter.kind' attribute"
)
self
.
_kind
=
kind
if
default
is
not
_empty
:
if
kind
in
(
_VAR_POSITIONAL
,
_VAR_KEYWORD
):
msg
=
'{} parameters cannot have default values'
.
format
(
kind
)
raise
ValueError
(
msg
)
self
.
_default
=
default
self
.
_annotation
=
annotation
if
name
is
None
:
if
kind
!=
_POSITIONAL_ONLY
:
raise
ValueError
(
"None is not a valid name for a "
"non-positional-only parameter"
)
self
.
_name
=
name
else
:
name
=
str
(
name
)
if
kind
!=
_POSITIONAL_ONLY
and
not
name
.
isidentifier
():
msg
=
'{!r} is not a valid parameter name'
.
format
(
name
)
raise
ValueError
(
msg
)
self
.
_name
=
name
self
.
_partial_kwarg
=
_partial_kwarg
@property
def
name
(
self
):
return
self
.
_name
@property
def
default
(
self
):
return
self
.
_default
@property
def
annotation
(
self
):
return
self
.
_annotation
@property
def
kind
(
self
):
return
self
.
_kind
def
replace
(
self
,
*
,
name
=
_void
,
kind
=
_void
,
annotation
=
_void
,
default
=
_void
,
_partial_kwarg
=
_void
):
'''Creates a customized copy of the Parameter.'''
if
name
is
_void
:
name
=
self
.
_name
if
kind
is
_void
:
kind
=
self
.
_kind
if
annotation
is
_void
:
annotation
=
self
.
_annotation
if
default
is
_void
:
default
=
self
.
_default
if
_partial_kwarg
is
_void
:
_partial_kwarg
=
self
.
_partial_kwarg
return
type
(
self
)(
name
,
kind
,
default
=
default
,
annotation
=
annotation
,
_partial_kwarg
=
_partial_kwarg
)
def
__str__
(
self
):
kind
=
self
.
kind
formatted
=
self
.
_name
if
kind
==
_POSITIONAL_ONLY
:
if
formatted
is
None
:
formatted
=
''
formatted
=
'<{}>'
.
format
(
formatted
)
# Add annotation and default value
if
self
.
_annotation
is
not
_empty
:
formatted
=
'{}:{}'
.
format
(
formatted
,
formatannotation
(
self
.
_annotation
))
if
self
.
_default
is
not
_empty
:
formatted
=
'{}={}'
.
format
(
formatted
,
repr
(
self
.
_default
))
if
kind
==
_VAR_POSITIONAL
:
formatted
=
'*'
+
formatted
elif
kind
==
_VAR_KEYWORD
:
formatted
=
'**'
+
formatted
return
formatted
def
__repr__
(
self
):
return
'<{} at {:#x} {!r}>'
.
format
(
self
.
__class__
.
__name__
,
id
(
self
),
self
.
name
)
def
__eq__
(
self
,
other
):
return
(
issubclass
(
other
.
__class__
,
Parameter
)
and
self
.
_name
==
other
.
_name
and
self
.
_kind
==
other
.
_kind
and
self
.
_default
==
other
.
_default
and
self
.
_annotation
==
other
.
_annotation
)
def
__ne__
(
self
,
other
):
return
not
self
.
__eq__
(
other
)
class
BoundArguments
:
'''Result of `Signature.bind` call. Holds the mapping of arguments
to the function's parameters.
Has the following public attributes:
* arguments : OrderedDict
An ordered mutable mapping of parameters' names to arguments' values.
Does not contain arguments' default values.
* signature : Signature
The Signature object that created this instance.
* args : tuple
Tuple of positional arguments values.
* kwargs : dict
Dict of keyword arguments values.
'''
def
__init__
(
self
,
signature
,
arguments
):
self
.
arguments
=
arguments
self
.
_signature
=
signature
@property
def
signature
(
self
):
return
self
.
_signature
@property
def
args
(
self
):
args
=
[]
for
param_name
,
param
in
self
.
_signature
.
parameters
.
items
():
if
(
param
.
kind
in
(
_VAR_KEYWORD
,
_KEYWORD_ONLY
)
or
param
.
_partial_kwarg
):
# Keyword arguments mapped by 'functools.partial'
# (Parameter._partial_kwarg is True) are mapped
# in 'BoundArguments.kwargs', along with VAR_KEYWORD &
# KEYWORD_ONLY
break
try
:
arg
=
self
.
arguments
[
param_name
]
except
KeyError
:
# We're done here. Other arguments
# will be mapped in 'BoundArguments.kwargs'
break
else
:
if
param
.
kind
==
_VAR_POSITIONAL
:
# *args
args
.
extend
(
arg
)
else
:
# plain argument
args
.
append
(
arg
)
return
tuple
(
args
)
@property
def
kwargs
(
self
):
kwargs
=
{}
kwargs_started
=
False
for
param_name
,
param
in
self
.
_signature
.
parameters
.
items
():
if
not
kwargs_started
:
if
(
param
.
kind
in
(
_VAR_KEYWORD
,
_KEYWORD_ONLY
)
or
param
.
_partial_kwarg
):
kwargs_started
=
True
else
:
if
param_name
not
in
self
.
arguments
:
kwargs_started
=
True
continue
if
not
kwargs_started
:
continue
try
:
arg
=
self
.
arguments
[
param_name
]
except
KeyError
:
pass
else
:
if
param
.
kind
==
_VAR_KEYWORD
:
# **kwargs
kwargs
.
update
(
arg
)
else
:
# plain keyword argument
kwargs
[
param_name
]
=
arg
return
kwargs
def
__eq__
(
self
,
other
):
return
(
issubclass
(
other
.
__class__
,
BoundArguments
)
and
self
.
signature
==
other
.
signature
and
self
.
arguments
==
other
.
arguments
)
def
__ne__
(
self
,
other
):
return
not
self
.
__eq__
(
other
)
class
Signature
:
'''A Signature object represents the overall signature of a function.
It stores a Parameter object for each parameter accepted by the
function, as well as information specific to the function itself.
A Signature object has the following public attributes and methods:
* parameters : OrderedDict
An ordered mapping of parameters' names to the corresponding
Parameter objects (keyword-only arguments are in the same order
as listed in `code.co_varnames`).
* return_annotation : object
The annotation for the return type of the function if specified.
If the function has no annotation for its return type, this
attribute is not set.
* bind(*args, **kwargs) -> BoundArguments
Creates a mapping from positional and keyword arguments to
parameters.
* bind_partial(*args, **kwargs) -> BoundArguments
Creates a partial mapping from positional and keyword arguments
to parameters (simulating 'functools.partial' behavior.)
'''
__slots__
=
(
'_return_annotation'
,
'_parameters'
)
_parameter_cls
=
Parameter
_bound_arguments_cls
=
BoundArguments
empty
=
_empty
def
__init__
(
self
,
parameters
=
None
,
*
,
return_annotation
=
_empty
,
__validate_parameters__
=
True
):
'''Constructs Signature from the given list of Parameter
objects and 'return_annotation'. All arguments are optional.
'''
if
parameters
is
None
:
params
=
OrderedDict
()
else
:
if
__validate_parameters__
:
params
=
OrderedDict
()
top_kind
=
_POSITIONAL_ONLY
for
idx
,
param
in
enumerate
(
parameters
):
kind
=
param
.
kind
if
kind
<
top_kind
:
msg
=
'wrong parameter order: {} before {}'
msg
=
msg
.
format
(
top_kind
,
param
.
kind
)
raise
ValueError
(
msg
)
else
:
top_kind
=
kind
name
=
param
.
name
if
name
is
None
:
name
=
str
(
idx
)
param
=
param
.
replace
(
name
=
name
)
if
name
in
params
:
msg
=
'duplicate parameter name: {!r}'
.
format
(
name
)
raise
ValueError
(
msg
)
params
[
name
]
=
param
else
:
params
=
OrderedDict
(((
param
.
name
,
param
)
for
param
in
parameters
))
self
.
_parameters
=
types
.
MappingProxyType
(
params
)
self
.
_return_annotation
=
return_annotation
@classmethod
def
from_function
(
cls
,
func
):
'''Constructs Signature for the given python function'''
if
not
isinstance
(
func
,
types
.
FunctionType
):
raise
TypeError
(
'{!r} is not a Python function'
.
format
(
func
))
Parameter
=
cls
.
_parameter_cls
# Parameter information.
func_code
=
func
.
__code__
pos_count
=
func_code
.
co_argcount
arg_names
=
func_code
.
co_varnames
positional
=
tuple
(
arg_names
[:
pos_count
])
keyword_only_count
=
func_code
.
co_kwonlyargcount
keyword_only
=
arg_names
[
pos_count
:(
pos_count
+
keyword_only_count
)]
annotations
=
func
.
__annotations__
defaults
=
func
.
__defaults__
kwdefaults
=
func
.
__kwdefaults__
if
defaults
:
pos_default_count
=
len
(
defaults
)
else
:
pos_default_count
=
0
parameters
=
[]
# Non-keyword-only parameters w/o defaults.
non_default_count
=
pos_count
-
pos_default_count
for
name
in
positional
[:
non_default_count
]:
annotation
=
annotations
.
get
(
name
,
_empty
)
parameters
.
append
(
Parameter
(
name
,
annotation
=
annotation
,
kind
=
_POSITIONAL_OR_KEYWORD
))
# ... w/ defaults.
for
offset
,
name
in
enumerate
(
positional
[
non_default_count
:]):
annotation
=
annotations
.
get
(
name
,
_empty
)
parameters
.
append
(
Parameter
(
name
,
annotation
=
annotation
,
kind
=
_POSITIONAL_OR_KEYWORD
,
default
=
defaults
[
offset
]))
# *args
if
func_code
.
co_flags
&
0x04
:
name
=
arg_names
[
pos_count
+
keyword_only_count
]
annotation
=
annotations
.
get
(
name
,
_empty
)
parameters
.
append
(
Parameter
(
name
,
annotation
=
annotation
,
kind
=
_VAR_POSITIONAL
))
# Keyword-only parameters.
for
name
in
keyword_only
:
default
=
_empty
if
kwdefaults
is
not
None
:
default
=
kwdefaults
.
get
(
name
,
_empty
)
annotation
=
annotations
.
get
(
name
,
_empty
)
parameters
.
append
(
Parameter
(
name
,
annotation
=
annotation
,
kind
=
_KEYWORD_ONLY
,
default
=
default
))
# **kwargs
if
func_code
.
co_flags
&
0x08
:
index
=
pos_count
+
keyword_only_count
if
func_code
.
co_flags
&
0x04
:
index
+=
1
name
=
arg_names
[
index
]
annotation
=
annotations
.
get
(
name
,
_empty
)
parameters
.
append
(
Parameter
(
name
,
annotation
=
annotation
,
kind
=
_VAR_KEYWORD
))
return
cls
(
parameters
,
return_annotation
=
annotations
.
get
(
'return'
,
_empty
),
__validate_parameters__
=
False
)
@property
def
parameters
(
self
):
return
self
.
_parameters
@property
def
return_annotation
(
self
):
return
self
.
_return_annotation
def
replace
(
self
,
*
,
parameters
=
_void
,
return_annotation
=
_void
):
'''Creates a customized copy of the Signature.
Pass 'parameters' and/or 'return_annotation' arguments
to override them in the new copy.
'''
if
parameters
is
_void
:
parameters
=
self
.
parameters
.
values
()
if
return_annotation
is
_void
:
return_annotation
=
self
.
_return_annotation
return
type
(
self
)(
parameters
,
return_annotation
=
return_annotation
)
def
__eq__
(
self
,
other
):
if
(
not
issubclass
(
type
(
other
),
Signature
)
or
self
.
return_annotation
!=
other
.
return_annotation
or
len
(
self
.
parameters
)
!=
len
(
other
.
parameters
)):
return
False
other_positions
=
{
param
:
idx
for
idx
,
param
in
enumerate
(
other
.
parameters
.
keys
())}
for
idx
,
(
param_name
,
param
)
in
enumerate
(
self
.
parameters
.
items
()):
if
param
.
kind
==
_KEYWORD_ONLY
:
try
:
other_param
=
other
.
parameters
[
param_name
]
except
KeyError
:
return
False
else
:
if
param
!=
other_param
:
return
False
else
:
try
:
other_idx
=
other_positions
[
param_name
]
except
KeyError
:
return
False
else
:
if
(
idx
!=
other_idx
or
param
!=
other
.
parameters
[
param_name
]):
return
False
return
True
def
__ne__
(
self
,
other
):
return
not
self
.
__eq__
(
other
)
def
_bind
(
self
,
args
,
kwargs
,
*
,
partial
=
False
):
'''Private method. Don't use directly.'''
arguments
=
OrderedDict
()
parameters
=
iter
(
self
.
parameters
.
values
())
parameters_ex
=
()
arg_vals
=
iter
(
args
)
if
partial
:
# Support for binding arguments to 'functools.partial' objects.
# See 'functools.partial' case in 'signature()' implementation
# for details.
for
param_name
,
param
in
self
.
parameters
.
items
():
if
(
param
.
_partial_kwarg
and
param_name
not
in
kwargs
):
# Simulating 'functools.partial' behavior
kwargs
[
param_name
]
=
param
.
default
while
True
:
# Let's iterate through the positional arguments and corresponding
# parameters
try
:
arg_val
=
next
(
arg_vals
)
except
StopIteration
:
# No more positional arguments
try
:
param
=
next
(
parameters
)
except
StopIteration
:
# No more parameters. That's it. Just need to check that
# we have no `kwargs` after this while loop
break
else
:
if
param
.
kind
==
_VAR_POSITIONAL
:
# That's OK, just empty *args. Let's start parsing
# kwargs
break
elif
param
.
name
in
kwargs
:
if
param
.
kind
==
_POSITIONAL_ONLY
:
msg
=
'{arg!r} parameter is positional only, '
\
'but was passed as a keyword'
msg
=
msg
.
format
(
arg
=
param
.
name
)
raise
TypeError
(
msg
)
from
None
parameters_ex
=
(
param
,)
break
elif
(
param
.
kind
==
_VAR_KEYWORD
or
param
.
default
is
not
_empty
):
# That's fine too - we have a default value for this
# parameter. So, lets start parsing `kwargs`, starting
# with the current parameter
parameters_ex
=
(
param
,)
break
else
:
if
partial
:
parameters_ex
=
(
param
,)
break
else
:
msg
=
'{arg!r} parameter lacking default value'
msg
=
msg
.
format
(
arg
=
param
.
name
)
raise
TypeError
(
msg
)
from
None
else
:
# We have a positional argument to process
try
:
param
=
next
(
parameters
)
except
StopIteration
:
raise
TypeError
(
'too many positional arguments'
)
from
None
else
:
if
param
.
kind
in
(
_VAR_KEYWORD
,
_KEYWORD_ONLY
):
# Looks like we have no parameter for this positional
# argument
raise
TypeError
(
'too many positional arguments'
)
if
param
.
kind
==
_VAR_POSITIONAL
:
# We have an '*args'-like argument, let's fill it with
# all positional arguments we have left and move on to
# the next phase
values
=
[
arg_val
]
values
.
extend
(
arg_vals
)
arguments
[
param
.
name
]
=
tuple
(
values
)
break
if
param
.
name
in
kwargs
:
raise
TypeError
(
'multiple values for argument '
'{arg!r}'
.
format
(
arg
=
param
.
name
))
arguments
[
param
.
name
]
=
arg_val
# Now, we iterate through the remaining parameters to process
# keyword arguments
kwargs_param
=
None
for
param
in
itertools
.
chain
(
parameters_ex
,
parameters
):
if
param
.
kind
==
_POSITIONAL_ONLY
:
# This should never happen in case of a properly built
# Signature object (but let's have this check here
# to ensure correct behaviour just in case)
raise
TypeError
(
'{arg!r} parameter is positional only, '
'but was passed as a keyword'
.
\
format
(
arg
=
param
.
name
))
if
param
.
kind
==
_VAR_KEYWORD
:
# Memorize that we have a '**kwargs'-like parameter
kwargs_param
=
param
continue
param_name
=
param
.
name
try
:
arg_val
=
kwargs
.
pop
(
param_name
)
except
KeyError
:
# We have no value for this parameter. It's fine though,
# if it has a default value, or it is an '*args'-like
# parameter, left alone by the processing of positional
# arguments.
if
(
not
partial
and
param
.
kind
!=
_VAR_POSITIONAL
and
param
.
default
is
_empty
):
raise
TypeError
(
'{arg!r} parameter lacking default value'
.
\
format
(
arg
=
param_name
))
from
None
else
:
arguments
[
param_name
]
=
arg_val
if
kwargs
:
if
kwargs_param
is
not
None
:
# Process our '**kwargs'-like parameter
arguments
[
kwargs_param
.
name
]
=
kwargs
else
:
raise
TypeError
(
'too many keyword arguments'
)
return
self
.
_bound_arguments_cls
(
self
,
arguments
)
def
bind
(
self
,
*
args
,
**
kwargs
):
'''Get a BoundArguments object, that maps the passed `args`
and `kwargs` to the function's signature. Raises `TypeError`
if the passed arguments can not be bound.
'''
return
self
.
_bind
(
args
,
kwargs
)
def
bind_partial
(
self
,
*
args
,
**
kwargs
):
'''Get a BoundArguments object, that partially maps the
passed `args` and `kwargs` to the function's signature.
Raises `TypeError` if the passed arguments can not be bound.
'''
return
self
.
_bind
(
args
,
kwargs
,
partial
=
True
)
def
__str__
(
self
):
result
=
[]
render_kw_only_separator
=
True
for
idx
,
param
in
enumerate
(
self
.
parameters
.
values
()):
formatted
=
str
(
param
)
kind
=
param
.
kind
if
kind
==
_VAR_POSITIONAL
:
# OK, we have an '*args'-like parameter, so we won't need
# a '*' to separate keyword-only arguments
render_kw_only_separator
=
False
elif
kind
==
_KEYWORD_ONLY
and
render_kw_only_separator
:
# We have a keyword-only parameter to render and we haven't
# rendered an '*args'-like parameter before, so add a '*'
# separator to the parameters list ("foo(arg1, *, arg2)" case)
result
.
append
(
'*'
)
# This condition should be only triggered once, so
# reset the flag
render_kw_only_separator
=
False
result
.
append
(
formatted
)
rendered
=
'({})'
.
format
(
', '
.
join
(
result
))
if
self
.
return_annotation
is
not
_empty
:
anno
=
formatannotation
(
self
.
return_annotation
)
rendered
+=
' -> {}'
.
format
(
anno
)
return
rendered
Lib/test/test_inspect.py
Dosyayı görüntüle @
7c7cbfc0
...
...
@@ -1173,13 +1173,934 @@ class TestGetGeneratorState(unittest.TestCase):
self
.
assertIn
(
name
,
str
(
state
))
class
TestSignatureObject
(
unittest
.
TestCase
):
@staticmethod
def
signature
(
func
):
sig
=
inspect
.
signature
(
func
)
return
(
tuple
((
param
.
name
,
(
...
if
param
.
default
is
param
.
empty
else
param
.
default
),
(
...
if
param
.
annotation
is
param
.
empty
else
param
.
annotation
),
str
(
param
.
kind
)
.
lower
())
for
param
in
sig
.
parameters
.
values
()),
(
...
if
sig
.
return_annotation
is
sig
.
empty
else
sig
.
return_annotation
))
def
test_signature_object
(
self
):
S
=
inspect
.
Signature
P
=
inspect
.
Parameter
self
.
assertEqual
(
str
(
S
()),
'()'
)
def
test
(
po
,
pk
,
*
args
,
ko
,
**
kwargs
):
pass
sig
=
inspect
.
signature
(
test
)
po
=
sig
.
parameters
[
'po'
]
.
replace
(
kind
=
P
.
POSITIONAL_ONLY
)
pk
=
sig
.
parameters
[
'pk'
]
args
=
sig
.
parameters
[
'args'
]
ko
=
sig
.
parameters
[
'ko'
]
kwargs
=
sig
.
parameters
[
'kwargs'
]
S
((
po
,
pk
,
args
,
ko
,
kwargs
))
with
self
.
assertRaisesRegexp
(
ValueError
,
'wrong parameter order'
):
S
((
pk
,
po
,
args
,
ko
,
kwargs
))
with
self
.
assertRaisesRegexp
(
ValueError
,
'wrong parameter order'
):
S
((
po
,
args
,
pk
,
ko
,
kwargs
))
with
self
.
assertRaisesRegexp
(
ValueError
,
'wrong parameter order'
):
S
((
args
,
po
,
pk
,
ko
,
kwargs
))
with
self
.
assertRaisesRegexp
(
ValueError
,
'wrong parameter order'
):
S
((
po
,
pk
,
args
,
kwargs
,
ko
))
kwargs2
=
kwargs
.
replace
(
name
=
'args'
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'duplicate parameter name'
):
S
((
po
,
pk
,
args
,
kwargs2
,
ko
))
def
test_signature_immutability
(
self
):
def
test
(
a
):
pass
sig
=
inspect
.
signature
(
test
)
with
self
.
assertRaises
(
AttributeError
):
sig
.
foo
=
'bar'
with
self
.
assertRaises
(
TypeError
):
sig
.
parameters
[
'a'
]
=
None
def
test_signature_on_noarg
(
self
):
def
test
():
pass
self
.
assertEqual
(
self
.
signature
(
test
),
((),
...
))
def
test_signature_on_wargs
(
self
):
def
test
(
a
,
b
:
'foo'
)
->
123
:
pass
self
.
assertEqual
(
self
.
signature
(
test
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
...
,
'foo'
,
"positional_or_keyword"
)),
123
))
def
test_signature_on_wkwonly
(
self
):
def
test
(
*
,
a
:
float
,
b
:
str
)
->
int
:
pass
self
.
assertEqual
(
self
.
signature
(
test
),
(((
'a'
,
...
,
float
,
"keyword_only"
),
(
'b'
,
...
,
str
,
"keyword_only"
)),
int
))
def
test_signature_on_complex_args
(
self
):
def
test
(
a
,
b
:
'foo'
=
10
,
*
args
:
'bar'
,
spam
:
'baz'
,
ham
=
123
,
**
kwargs
:
int
):
pass
self
.
assertEqual
(
self
.
signature
(
test
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
10
,
'foo'
,
"positional_or_keyword"
),
(
'args'
,
...
,
'bar'
,
"var_positional"
),
(
'spam'
,
...
,
'baz'
,
"keyword_only"
),
(
'ham'
,
123
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
int
,
"var_keyword"
)),
...
))
def
test_signature_on_builtin_function
(
self
):
with
self
.
assertRaisesRegexp
(
ValueError
,
'not supported by signature'
):
inspect
.
signature
(
type
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'not supported by signature'
):
# support for 'wrapper_descriptor'
inspect
.
signature
(
type
.
__call__
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'not supported by signature'
):
# support for 'method-wrapper'
inspect
.
signature
(
min
.
__call__
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'no signature found for builtin function'
):
# support for 'method-wrapper'
inspect
.
signature
(
min
)
def
test_signature_on_non_function
(
self
):
with
self
.
assertRaisesRegexp
(
TypeError
,
'is not a callable object'
):
inspect
.
signature
(
42
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'is not a Python function'
):
inspect
.
Signature
.
from_function
(
42
)
def
test_signature_on_method
(
self
):
class
Test
:
def
foo
(
self
,
arg1
,
arg2
=
1
)
->
int
:
pass
meth
=
Test
()
.
foo
self
.
assertEqual
(
self
.
signature
(
meth
),
(((
'arg1'
,
...
,
...
,
"positional_or_keyword"
),
(
'arg2'
,
1
,
...
,
"positional_or_keyword"
)),
int
))
def
test_signature_on_classmethod
(
self
):
class
Test
:
@classmethod
def
foo
(
cls
,
arg1
,
*
,
arg2
=
1
):
pass
meth
=
Test
()
.
foo
self
.
assertEqual
(
self
.
signature
(
meth
),
(((
'arg1'
,
...
,
...
,
"positional_or_keyword"
),
(
'arg2'
,
1
,
...
,
"keyword_only"
)),
...
))
meth
=
Test
.
foo
self
.
assertEqual
(
self
.
signature
(
meth
),
(((
'arg1'
,
...
,
...
,
"positional_or_keyword"
),
(
'arg2'
,
1
,
...
,
"keyword_only"
)),
...
))
def
test_signature_on_staticmethod
(
self
):
class
Test
:
@staticmethod
def
foo
(
cls
,
*
,
arg
):
pass
meth
=
Test
()
.
foo
self
.
assertEqual
(
self
.
signature
(
meth
),
(((
'cls'
,
...
,
...
,
"positional_or_keyword"
),
(
'arg'
,
...
,
...
,
"keyword_only"
)),
...
))
meth
=
Test
.
foo
self
.
assertEqual
(
self
.
signature
(
meth
),
(((
'cls'
,
...
,
...
,
"positional_or_keyword"
),
(
'arg'
,
...
,
...
,
"keyword_only"
)),
...
))
def
test_signature_on_partial
(
self
):
from
functools
import
partial
def
test
():
pass
self
.
assertEqual
(
self
.
signature
(
partial
(
test
)),
((),
...
))
with
self
.
assertRaisesRegexp
(
ValueError
,
"has incorrect arguments"
):
inspect
.
signature
(
partial
(
test
,
1
))
with
self
.
assertRaisesRegexp
(
ValueError
,
"has incorrect arguments"
):
inspect
.
signature
(
partial
(
test
,
a
=
1
))
def
test
(
a
,
b
,
*
,
c
,
d
):
pass
self
.
assertEqual
(
self
.
signature
(
partial
(
test
)),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
...
,
...
,
"positional_or_keyword"
),
(
'c'
,
...
,
...
,
"keyword_only"
),
(
'd'
,
...
,
...
,
"keyword_only"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
)),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),
(
'c'
,
...
,
...
,
"keyword_only"
),
(
'd'
,
...
,
...
,
"keyword_only"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
,
c
=
2
)),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),
(
'c'
,
2
,
...
,
"keyword_only"
),
(
'd'
,
...
,
...
,
"keyword_only"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
b
=
1
,
c
=
2
)),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
1
,
...
,
"positional_or_keyword"
),
(
'c'
,
2
,
...
,
"keyword_only"
),
(
'd'
,
...
,
...
,
"keyword_only"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
0
,
b
=
1
,
c
=
2
)),
(((
'b'
,
1
,
...
,
"positional_or_keyword"
),
(
'c'
,
2
,
...
,
"keyword_only"
),
(
'd'
,
...
,
...
,
"keyword_only"
),),
...
))
def
test
(
a
,
*
args
,
b
,
**
kwargs
):
pass
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
)),
(((
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
...
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
,
2
,
3
)),
(((
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
...
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
,
2
,
3
,
test
=
True
)),
(((
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
...
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
1
,
2
,
3
,
test
=
1
,
b
=
0
)),
(((
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
0
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
b
=
0
)),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
0
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
partial
(
test
,
b
=
0
,
test
=
1
)),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'args'
,
...
,
...
,
"var_positional"
),
(
'b'
,
0
,
...
,
"keyword_only"
),
(
'kwargs'
,
...
,
...
,
"var_keyword"
)),
...
))
def
test
(
a
,
b
,
c
:
int
)
->
42
:
pass
sig
=
test
.
__signature__
=
inspect
.
signature
(
test
)
self
.
assertEqual
(
self
.
signature
(
partial
(
partial
(
test
,
1
))),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),
(
'c'
,
...
,
int
,
"positional_or_keyword"
)),
42
))
self
.
assertEqual
(
self
.
signature
(
partial
(
partial
(
test
,
1
),
2
)),
(((
'c'
,
...
,
int
,
"positional_or_keyword"
),),
42
))
psig
=
inspect
.
signature
(
partial
(
partial
(
test
,
1
),
2
))
def
foo
(
a
):
return
a
_foo
=
partial
(
partial
(
foo
,
a
=
10
),
a
=
20
)
self
.
assertEqual
(
self
.
signature
(
_foo
),
(((
'a'
,
20
,
...
,
"positional_or_keyword"
),),
...
))
# check that we don't have any side-effects in signature(),
# and the partial object is still functioning
self
.
assertEqual
(
_foo
(),
20
)
def
foo
(
a
,
b
,
c
):
return
a
,
b
,
c
_foo
=
partial
(
partial
(
foo
,
1
,
b
=
20
),
b
=
30
)
self
.
assertEqual
(
self
.
signature
(
_foo
),
(((
'b'
,
30
,
...
,
"positional_or_keyword"
),
(
'c'
,
...
,
...
,
"positional_or_keyword"
)),
...
))
self
.
assertEqual
(
_foo
(
c
=
10
),
(
1
,
30
,
10
))
_foo
=
partial
(
_foo
,
2
)
# now 'b' has two values -
# positional and keyword
with
self
.
assertRaisesRegexp
(
ValueError
,
"has incorrect arguments"
):
inspect
.
signature
(
_foo
)
def
foo
(
a
,
b
,
c
,
*
,
d
):
return
a
,
b
,
c
,
d
_foo
=
partial
(
partial
(
foo
,
d
=
20
,
c
=
20
),
b
=
10
,
d
=
30
)
self
.
assertEqual
(
self
.
signature
(
_foo
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
10
,
...
,
"positional_or_keyword"
),
(
'c'
,
20
,
...
,
"positional_or_keyword"
),
(
'd'
,
30
,
...
,
"keyword_only"
)),
...
))
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
a
=
200
,
b
=
11
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
200
,
11
,
20
,
30
))
def
foo
(
a
=
1
,
b
=
2
,
c
=
3
):
return
a
,
b
,
c
_foo
=
partial
(
foo
,
a
=
10
,
c
=
13
)
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
11
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
11
,
2
,
13
))
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
11
,
12
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
11
,
12
,
13
))
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
11
,
b
=
12
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
11
,
12
,
13
))
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
b
=
12
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
10
,
12
,
13
))
_foo
=
partial
(
_foo
,
b
=
10
)
ba
=
inspect
.
signature
(
_foo
)
.
bind
(
12
,
14
)
self
.
assertEqual
(
_foo
(
*
ba
.
args
,
**
ba
.
kwargs
),
(
12
,
14
,
13
))
def
test_signature_on_decorated
(
self
):
import
functools
def
decorator
(
func
):
@functools.wraps
(
func
)
def
wrapper
(
*
args
,
**
kwargs
)
->
int
:
return
func
(
*
args
,
**
kwargs
)
return
wrapper
class
Foo
:
@decorator
def
bar
(
self
,
a
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
Foo
.
bar
),
(((
'self'
,
...
,
...
,
"positional_or_keyword"
),
(
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
...
,
...
,
"positional_or_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
Foo
()
.
bar
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
...
,
...
,
"positional_or_keyword"
)),
...
))
# Test that we handle method wrappers correctly
def
decorator
(
func
):
@functools.wraps
(
func
)
def
wrapper
(
*
args
,
**
kwargs
)
->
int
:
return
func
(
42
,
*
args
,
**
kwargs
)
sig
=
inspect
.
signature
(
func
)
new_params
=
tuple
(
sig
.
parameters
.
values
())[
1
:]
wrapper
.
__signature__
=
sig
.
replace
(
parameters
=
new_params
)
return
wrapper
class
Foo
:
@decorator
def
__call__
(
self
,
a
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
Foo
.
__call__
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),
(
'b'
,
...
,
...
,
"positional_or_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
Foo
()
.
__call__
),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
def
test_signature_on_class
(
self
):
class
C
:
def
__init__
(
self
,
a
):
pass
self
.
assertEqual
(
self
.
signature
(
C
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
class
CM
(
type
):
def
__call__
(
cls
,
a
):
pass
class
C
(
metaclass
=
CM
):
def
__init__
(
self
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
C
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
class
CM
(
type
):
def
__new__
(
mcls
,
name
,
bases
,
dct
,
*
,
foo
=
1
):
return
super
()
.
__new__
(
mcls
,
name
,
bases
,
dct
)
class
C
(
metaclass
=
CM
):
def
__init__
(
self
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
C
),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
self
.
assertEqual
(
self
.
signature
(
CM
),
(((
'name'
,
...
,
...
,
"positional_or_keyword"
),
(
'bases'
,
...
,
...
,
"positional_or_keyword"
),
(
'dct'
,
...
,
...
,
"positional_or_keyword"
),
(
'foo'
,
1
,
...
,
"keyword_only"
)),
...
))
class
CMM
(
type
):
def
__new__
(
mcls
,
name
,
bases
,
dct
,
*
,
foo
=
1
):
return
super
()
.
__new__
(
mcls
,
name
,
bases
,
dct
)
def
__call__
(
cls
,
nm
,
bs
,
dt
):
return
type
(
nm
,
bs
,
dt
)
class
CM
(
type
,
metaclass
=
CMM
):
def
__new__
(
mcls
,
name
,
bases
,
dct
,
*
,
bar
=
2
):
return
super
()
.
__new__
(
mcls
,
name
,
bases
,
dct
)
class
C
(
metaclass
=
CM
):
def
__init__
(
self
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
CMM
),
(((
'name'
,
...
,
...
,
"positional_or_keyword"
),
(
'bases'
,
...
,
...
,
"positional_or_keyword"
),
(
'dct'
,
...
,
...
,
"positional_or_keyword"
),
(
'foo'
,
1
,
...
,
"keyword_only"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
CM
),
(((
'nm'
,
...
,
...
,
"positional_or_keyword"
),
(
'bs'
,
...
,
...
,
"positional_or_keyword"
),
(
'dt'
,
...
,
...
,
"positional_or_keyword"
)),
...
))
self
.
assertEqual
(
self
.
signature
(
C
),
(((
'b'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
class
CM
(
type
):
def
__init__
(
cls
,
name
,
bases
,
dct
,
*
,
bar
=
2
):
return
super
()
.
__init__
(
name
,
bases
,
dct
)
class
C
(
metaclass
=
CM
):
def
__init__
(
self
,
b
):
pass
self
.
assertEqual
(
self
.
signature
(
CM
),
(((
'name'
,
...
,
...
,
"positional_or_keyword"
),
(
'bases'
,
...
,
...
,
"positional_or_keyword"
),
(
'dct'
,
...
,
...
,
"positional_or_keyword"
),
(
'bar'
,
2
,
...
,
"keyword_only"
)),
...
))
def
test_signature_on_callable_objects
(
self
):
class
Foo
:
def
__call__
(
self
,
a
):
pass
self
.
assertEqual
(
self
.
signature
(
Foo
()),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
class
Spam
:
pass
with
self
.
assertRaisesRegexp
(
TypeError
,
"is not a callable object"
):
inspect
.
signature
(
Spam
())
class
Bar
(
Spam
,
Foo
):
pass
self
.
assertEqual
(
self
.
signature
(
Bar
()),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
class
ToFail
:
__call__
=
type
with
self
.
assertRaisesRegexp
(
ValueError
,
"not supported by signature"
):
inspect
.
signature
(
ToFail
())
class
Wrapped
:
pass
Wrapped
.
__wrapped__
=
lambda
a
:
None
self
.
assertEqual
(
self
.
signature
(
Wrapped
),
(((
'a'
,
...
,
...
,
"positional_or_keyword"
),),
...
))
def
test_signature_on_lambdas
(
self
):
self
.
assertEqual
(
self
.
signature
((
lambda
a
=
10
:
a
)),
(((
'a'
,
10
,
...
,
"positional_or_keyword"
),),
...
))
def
test_signature_equality
(
self
):
def
foo
(
a
,
*
,
b
:
int
)
->
float
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
42
)
def
bar
(
a
,
*
,
b
:
int
)
->
float
:
pass
self
.
assertEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
bar
(
a
,
*
,
b
:
int
)
->
int
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
bar
(
a
,
*
,
b
:
int
):
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
bar
(
a
,
*
,
b
:
int
=
42
)
->
float
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
bar
(
a
,
*
,
c
)
->
float
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
bar
(
a
,
b
:
int
)
->
float
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
spam
(
b
:
int
,
a
)
->
float
:
pass
self
.
assertNotEqual
(
inspect
.
signature
(
spam
),
inspect
.
signature
(
bar
))
def
foo
(
*
,
a
,
b
,
c
):
pass
def
bar
(
*
,
c
,
b
,
a
):
pass
self
.
assertEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
foo
(
*
,
a
=
1
,
b
,
c
):
pass
def
bar
(
*
,
c
,
b
,
a
=
1
):
pass
self
.
assertEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
foo
(
pos
,
*
,
a
=
1
,
b
,
c
):
pass
def
bar
(
pos
,
*
,
c
,
b
,
a
=
1
):
pass
self
.
assertEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
foo
(
pos
,
*
,
a
,
b
,
c
):
pass
def
bar
(
pos
,
*
,
c
,
b
,
a
=
1
):
pass
self
.
assertNotEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
foo
(
pos
,
*
args
,
a
=
42
,
b
,
c
,
**
kwargs
:
int
):
pass
def
bar
(
pos
,
*
args
,
c
,
b
,
a
=
42
,
**
kwargs
:
int
):
pass
self
.
assertEqual
(
inspect
.
signature
(
foo
),
inspect
.
signature
(
bar
))
def
test_signature_unhashable
(
self
):
def
foo
(
a
):
pass
sig
=
inspect
.
signature
(
foo
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'unhashable type'
):
hash
(
sig
)
def
test_signature_str
(
self
):
def
foo
(
a
:
int
=
1
,
*
,
b
,
c
=
None
,
**
kwargs
)
->
42
:
pass
self
.
assertEqual
(
str
(
inspect
.
signature
(
foo
)),
'(a:int=1, *, b, c=None, **kwargs) -> 42'
)
def
foo
(
a
:
int
=
1
,
*
args
,
b
,
c
=
None
,
**
kwargs
)
->
42
:
pass
self
.
assertEqual
(
str
(
inspect
.
signature
(
foo
)),
'(a:int=1, *args, b, c=None, **kwargs) -> 42'
)
def
foo
():
pass
self
.
assertEqual
(
str
(
inspect
.
signature
(
foo
)),
'()'
)
def
test_signature_str_positional_only
(
self
):
P
=
inspect
.
Parameter
def
test
(
a_po
,
*
,
b
,
**
kwargs
):
return
a_po
,
kwargs
sig
=
inspect
.
signature
(
test
)
new_params
=
list
(
sig
.
parameters
.
values
())
new_params
[
0
]
=
new_params
[
0
]
.
replace
(
kind
=
P
.
POSITIONAL_ONLY
)
test
.
__signature__
=
sig
.
replace
(
parameters
=
new_params
)
self
.
assertEqual
(
str
(
inspect
.
signature
(
test
)),
'(<a_po>, *, b, **kwargs)'
)
sig
=
inspect
.
signature
(
test
)
new_params
=
list
(
sig
.
parameters
.
values
())
new_params
[
0
]
=
new_params
[
0
]
.
replace
(
name
=
None
)
test
.
__signature__
=
sig
.
replace
(
parameters
=
new_params
)
self
.
assertEqual
(
str
(
inspect
.
signature
(
test
)),
'(<0>, *, b, **kwargs)'
)
def
test_signature_replace_anno
(
self
):
def
test
()
->
42
:
pass
sig
=
inspect
.
signature
(
test
)
sig
=
sig
.
replace
(
return_annotation
=
None
)
self
.
assertIs
(
sig
.
return_annotation
,
None
)
sig
=
sig
.
replace
(
return_annotation
=
sig
.
empty
)
self
.
assertIs
(
sig
.
return_annotation
,
sig
.
empty
)
sig
=
sig
.
replace
(
return_annotation
=
42
)
self
.
assertEqual
(
sig
.
return_annotation
,
42
)
self
.
assertEqual
(
sig
,
inspect
.
signature
(
test
))
class
TestParameterObject
(
unittest
.
TestCase
):
def
test_signature_parameter_kinds
(
self
):
P
=
inspect
.
Parameter
self
.
assertTrue
(
P
.
POSITIONAL_ONLY
<
P
.
POSITIONAL_OR_KEYWORD
<
\
P
.
VAR_POSITIONAL
<
P
.
KEYWORD_ONLY
<
P
.
VAR_KEYWORD
)
self
.
assertEqual
(
str
(
P
.
POSITIONAL_ONLY
),
'POSITIONAL_ONLY'
)
self
.
assertTrue
(
'POSITIONAL_ONLY'
in
repr
(
P
.
POSITIONAL_ONLY
))
def
test_signature_parameter_object
(
self
):
p
=
inspect
.
Parameter
(
'foo'
,
default
=
10
,
kind
=
inspect
.
Parameter
.
POSITIONAL_ONLY
)
self
.
assertEqual
(
p
.
name
,
'foo'
)
self
.
assertEqual
(
p
.
default
,
10
)
self
.
assertIs
(
p
.
annotation
,
p
.
empty
)
self
.
assertEqual
(
p
.
kind
,
inspect
.
Parameter
.
POSITIONAL_ONLY
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'invalid value'
):
inspect
.
Parameter
(
'foo'
,
default
=
10
,
kind
=
'123'
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'not a valid parameter name'
):
inspect
.
Parameter
(
'1'
,
kind
=
inspect
.
Parameter
.
VAR_KEYWORD
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'non-positional-only parameter'
):
inspect
.
Parameter
(
None
,
kind
=
inspect
.
Parameter
.
VAR_KEYWORD
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'cannot have default values'
):
inspect
.
Parameter
(
'a'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
VAR_KEYWORD
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'cannot have default values'
):
inspect
.
Parameter
(
'a'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
VAR_POSITIONAL
)
p
=
inspect
.
Parameter
(
'a'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
POSITIONAL_OR_KEYWORD
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'cannot have default values'
):
p
.
replace
(
kind
=
inspect
.
Parameter
.
VAR_POSITIONAL
)
self
.
assertTrue
(
repr
(
p
)
.
startswith
(
'<Parameter'
))
def
test_signature_parameter_equality
(
self
):
P
=
inspect
.
Parameter
p
=
P
(
'foo'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
KEYWORD_ONLY
)
self
.
assertEqual
(
p
,
p
)
self
.
assertNotEqual
(
p
,
42
)
self
.
assertEqual
(
p
,
P
(
'foo'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
KEYWORD_ONLY
))
def
test_signature_parameter_unhashable
(
self
):
p
=
inspect
.
Parameter
(
'foo'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
KEYWORD_ONLY
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'unhashable type'
):
hash
(
p
)
def
test_signature_parameter_replace
(
self
):
p
=
inspect
.
Parameter
(
'foo'
,
default
=
42
,
kind
=
inspect
.
Parameter
.
KEYWORD_ONLY
)
self
.
assertIsNot
(
p
,
p
.
replace
())
self
.
assertEqual
(
p
,
p
.
replace
())
p2
=
p
.
replace
(
annotation
=
1
)
self
.
assertEqual
(
p2
.
annotation
,
1
)
p2
=
p2
.
replace
(
annotation
=
p2
.
empty
)
self
.
assertEqual
(
p
,
p2
)
p2
=
p2
.
replace
(
name
=
'bar'
)
self
.
assertEqual
(
p2
.
name
,
'bar'
)
self
.
assertNotEqual
(
p2
,
p
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'not a valid parameter name'
):
p2
=
p2
.
replace
(
name
=
p2
.
empty
)
p2
=
p2
.
replace
(
name
=
'foo'
,
default
=
None
)
self
.
assertIs
(
p2
.
default
,
None
)
self
.
assertNotEqual
(
p2
,
p
)
p2
=
p2
.
replace
(
name
=
'foo'
,
default
=
p2
.
empty
)
self
.
assertIs
(
p2
.
default
,
p2
.
empty
)
p2
=
p2
.
replace
(
default
=
42
,
kind
=
p2
.
POSITIONAL_OR_KEYWORD
)
self
.
assertEqual
(
p2
.
kind
,
p2
.
POSITIONAL_OR_KEYWORD
)
self
.
assertNotEqual
(
p2
,
p
)
with
self
.
assertRaisesRegexp
(
ValueError
,
'invalid value for'
):
p2
=
p2
.
replace
(
kind
=
p2
.
empty
)
p2
=
p2
.
replace
(
kind
=
p2
.
KEYWORD_ONLY
)
self
.
assertEqual
(
p2
,
p
)
def
test_signature_parameter_positional_only
(
self
):
p
=
inspect
.
Parameter
(
None
,
kind
=
inspect
.
Parameter
.
POSITIONAL_ONLY
)
self
.
assertEqual
(
str
(
p
),
'<>'
)
p
=
p
.
replace
(
name
=
'1'
)
self
.
assertEqual
(
str
(
p
),
'<1>'
)
def
test_signature_parameter_immutability
(
self
):
p
=
inspect
.
Parameter
(
None
,
kind
=
inspect
.
Parameter
.
POSITIONAL_ONLY
)
with
self
.
assertRaises
(
AttributeError
):
p
.
foo
=
'bar'
with
self
.
assertRaises
(
AttributeError
):
p
.
kind
=
123
class
TestSignatureBind
(
unittest
.
TestCase
):
@staticmethod
def
call
(
func
,
*
args
,
**
kwargs
):
sig
=
inspect
.
signature
(
func
)
ba
=
sig
.
bind
(
*
args
,
**
kwargs
)
return
func
(
*
ba
.
args
,
**
ba
.
kwargs
)
def
test_signature_bind_empty
(
self
):
def
test
():
return
42
self
.
assertEqual
(
self
.
call
(
test
),
42
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
,
spam
=
10
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many keyword arguments'
):
self
.
call
(
test
,
spam
=
1
)
def
test_signature_bind_var
(
self
):
def
test
(
*
args
,
**
kwargs
):
return
args
,
kwargs
self
.
assertEqual
(
self
.
call
(
test
),
((),
{}))
self
.
assertEqual
(
self
.
call
(
test
,
1
),
((
1
,),
{}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
),
((
1
,
2
),
{}))
self
.
assertEqual
(
self
.
call
(
test
,
foo
=
'bar'
),
((),
{
'foo'
:
'bar'
}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
foo
=
'bar'
),
((
1
,),
{
'foo'
:
'bar'
}))
self
.
assertEqual
(
self
.
call
(
test
,
args
=
10
),
((),
{
'args'
:
10
}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
foo
=
'bar'
),
((
1
,
2
),
{
'foo'
:
'bar'
}))
def
test_signature_bind_just_args
(
self
):
def
test
(
a
,
b
,
c
):
return
a
,
b
,
c
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
3
),
(
1
,
2
,
3
))
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
,
2
,
3
,
4
)
with
self
.
assertRaisesRegexp
(
TypeError
,
"'b' parameter lacking default"
):
self
.
call
(
test
,
1
)
with
self
.
assertRaisesRegexp
(
TypeError
,
"'a' parameter lacking default"
):
self
.
call
(
test
)
def
test
(
a
,
b
,
c
=
10
):
return
a
,
b
,
c
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
3
),
(
1
,
2
,
3
))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
),
(
1
,
2
,
10
))
def
test
(
a
=
1
,
b
=
2
,
c
=
3
):
return
a
,
b
,
c
self
.
assertEqual
(
self
.
call
(
test
,
a
=
10
,
c
=
13
),
(
10
,
2
,
13
))
self
.
assertEqual
(
self
.
call
(
test
,
a
=
10
),
(
10
,
2
,
3
))
self
.
assertEqual
(
self
.
call
(
test
,
b
=
10
),
(
1
,
10
,
3
))
def
test_signature_bind_varargs_order
(
self
):
def
test
(
*
args
):
return
args
self
.
assertEqual
(
self
.
call
(
test
),
())
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
3
),
(
1
,
2
,
3
))
def
test_signature_bind_args_and_varargs
(
self
):
def
test
(
a
,
b
,
c
=
3
,
*
args
):
return
a
,
b
,
c
,
args
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
3
,
4
,
5
),
(
1
,
2
,
3
,
(
4
,
5
)))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
),
(
1
,
2
,
3
,
()))
self
.
assertEqual
(
self
.
call
(
test
,
b
=
1
,
a
=
2
),
(
2
,
1
,
3
,
()))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
b
=
2
),
(
1
,
2
,
3
,
()))
with
self
.
assertRaisesRegexp
(
TypeError
,
"multiple values for argument 'c'"
):
self
.
call
(
test
,
1
,
2
,
3
,
c
=
4
)
def
test_signature_bind_just_kwargs
(
self
):
def
test
(
**
kwargs
):
return
kwargs
self
.
assertEqual
(
self
.
call
(
test
),
{})
self
.
assertEqual
(
self
.
call
(
test
,
foo
=
'bar'
,
spam
=
'ham'
),
{
'foo'
:
'bar'
,
'spam'
:
'ham'
})
def
test_signature_bind_args_and_kwargs
(
self
):
def
test
(
a
,
b
,
c
=
3
,
**
kwargs
):
return
a
,
b
,
c
,
kwargs
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
),
(
1
,
2
,
3
,
{}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
foo
=
'bar'
,
spam
=
'ham'
),
(
1
,
2
,
3
,
{
'foo'
:
'bar'
,
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
b
=
2
,
a
=
1
,
foo
=
'bar'
,
spam
=
'ham'
),
(
1
,
2
,
3
,
{
'foo'
:
'bar'
,
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
a
=
1
,
b
=
2
,
foo
=
'bar'
,
spam
=
'ham'
),
(
1
,
2
,
3
,
{
'foo'
:
'bar'
,
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
b
=
2
,
foo
=
'bar'
,
spam
=
'ham'
),
(
1
,
2
,
3
,
{
'foo'
:
'bar'
,
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
b
=
2
,
c
=
4
,
foo
=
'bar'
,
spam
=
'ham'
),
(
1
,
2
,
4
,
{
'foo'
:
'bar'
,
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
4
,
foo
=
'bar'
),
(
1
,
2
,
4
,
{
'foo'
:
'bar'
}))
self
.
assertEqual
(
self
.
call
(
test
,
c
=
5
,
a
=
4
,
b
=
3
),
(
4
,
3
,
5
,
{}))
def
test_signature_bind_kwonly
(
self
):
def
test
(
*
,
foo
):
return
foo
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
)
self
.
assertEqual
(
self
.
call
(
test
,
foo
=
1
),
1
)
def
test
(
a
,
*
,
foo
=
1
,
bar
):
return
foo
with
self
.
assertRaisesRegexp
(
TypeError
,
"'bar' parameter lacking default value"
):
self
.
call
(
test
,
1
)
def
test
(
foo
,
*
,
bar
):
return
foo
,
bar
self
.
assertEqual
(
self
.
call
(
test
,
1
,
bar
=
2
),
(
1
,
2
))
self
.
assertEqual
(
self
.
call
(
test
,
bar
=
2
,
foo
=
1
),
(
1
,
2
))
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many keyword arguments'
):
self
.
call
(
test
,
bar
=
2
,
foo
=
1
,
spam
=
10
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
,
2
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many positional arguments'
):
self
.
call
(
test
,
1
,
2
,
bar
=
2
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'too many keyword arguments'
):
self
.
call
(
test
,
1
,
bar
=
2
,
spam
=
'ham'
)
with
self
.
assertRaisesRegexp
(
TypeError
,
"'bar' parameter lacking default value"
):
self
.
call
(
test
,
1
)
def
test
(
foo
,
*
,
bar
,
**
bin
):
return
foo
,
bar
,
bin
self
.
assertEqual
(
self
.
call
(
test
,
1
,
bar
=
2
),
(
1
,
2
,
{}))
self
.
assertEqual
(
self
.
call
(
test
,
foo
=
1
,
bar
=
2
),
(
1
,
2
,
{}))
self
.
assertEqual
(
self
.
call
(
test
,
1
,
bar
=
2
,
spam
=
'ham'
),
(
1
,
2
,
{
'spam'
:
'ham'
}))
self
.
assertEqual
(
self
.
call
(
test
,
spam
=
'ham'
,
foo
=
1
,
bar
=
2
),
(
1
,
2
,
{
'spam'
:
'ham'
}))
with
self
.
assertRaisesRegexp
(
TypeError
,
"'foo' parameter lacking default value"
):
self
.
call
(
test
,
spam
=
'ham'
,
bar
=
2
)
self
.
assertEqual
(
self
.
call
(
test
,
1
,
bar
=
2
,
bin
=
1
,
spam
=
10
),
(
1
,
2
,
{
'bin'
:
1
,
'spam'
:
10
}))
def
test_signature_bind_arguments
(
self
):
def
test
(
a
,
*
args
,
b
,
z
=
100
,
**
kwargs
):
pass
sig
=
inspect
.
signature
(
test
)
ba
=
sig
.
bind
(
10
,
20
,
b
=
30
,
c
=
40
,
args
=
50
,
kwargs
=
60
)
# we won't have 'z' argument in the bound arguments object, as we didn't
# pass it to the 'bind'
self
.
assertEqual
(
tuple
(
ba
.
arguments
.
items
()),
((
'a'
,
10
),
(
'args'
,
(
20
,)),
(
'b'
,
30
),
(
'kwargs'
,
{
'c'
:
40
,
'args'
:
50
,
'kwargs'
:
60
})))
self
.
assertEqual
(
ba
.
kwargs
,
{
'b'
:
30
,
'c'
:
40
,
'args'
:
50
,
'kwargs'
:
60
})
self
.
assertEqual
(
ba
.
args
,
(
10
,
20
))
def
test_signature_bind_positional_only
(
self
):
P
=
inspect
.
Parameter
def
test
(
a_po
,
b_po
,
c_po
=
3
,
foo
=
42
,
*
,
bar
=
50
,
**
kwargs
):
return
a_po
,
b_po
,
c_po
,
foo
,
bar
,
kwargs
sig
=
inspect
.
signature
(
test
)
new_params
=
collections
.
OrderedDict
(
tuple
(
sig
.
parameters
.
items
()))
for
name
in
(
'a_po'
,
'b_po'
,
'c_po'
):
new_params
[
name
]
=
new_params
[
name
]
.
replace
(
kind
=
P
.
POSITIONAL_ONLY
)
new_sig
=
sig
.
replace
(
parameters
=
new_params
.
values
())
test
.
__signature__
=
new_sig
self
.
assertEqual
(
self
.
call
(
test
,
1
,
2
,
4
,
5
,
bar
=
6
),
(
1
,
2
,
4
,
5
,
6
,
{}))
with
self
.
assertRaisesRegexp
(
TypeError
,
"parameter is positional only"
):
self
.
call
(
test
,
1
,
2
,
c_po
=
4
)
with
self
.
assertRaisesRegexp
(
TypeError
,
"parameter is positional only"
):
self
.
call
(
test
,
a_po
=
1
,
b_po
=
2
)
class
TestBoundArguments
(
unittest
.
TestCase
):
def
test_signature_bound_arguments_unhashable
(
self
):
def
foo
(
a
):
pass
ba
=
inspect
.
signature
(
foo
)
.
bind
(
1
)
with
self
.
assertRaisesRegexp
(
TypeError
,
'unhashable type'
):
hash
(
ba
)
def
test_signature_bound_arguments_equality
(
self
):
def
foo
(
a
):
pass
ba
=
inspect
.
signature
(
foo
)
.
bind
(
1
)
self
.
assertEqual
(
ba
,
ba
)
ba2
=
inspect
.
signature
(
foo
)
.
bind
(
1
)
self
.
assertEqual
(
ba
,
ba2
)
ba3
=
inspect
.
signature
(
foo
)
.
bind
(
2
)
self
.
assertNotEqual
(
ba
,
ba3
)
ba3
.
arguments
[
'a'
]
=
1
self
.
assertEqual
(
ba
,
ba3
)
def
bar
(
b
):
pass
ba4
=
inspect
.
signature
(
bar
)
.
bind
(
1
)
self
.
assertNotEqual
(
ba
,
ba4
)
def
test_main
():
run_unittest
(
TestDecorators
,
TestRetrievingSourceCode
,
TestOneliners
,
TestBuggyCases
,
TestInterpreterStack
,
TestClassesAndFunctions
,
TestPredicates
,
TestGetcallargsFunctions
,
TestGetcallargsMethods
,
TestGetcallargsUnboundMethods
,
TestGetattrStatic
,
TestGetGeneratorState
,
TestNoEOL
TestNoEOL
,
TestSignatureObject
,
TestSignatureBind
,
TestParameterObject
,
TestBoundArguments
)
if
__name__
==
"__main__"
:
...
...
Misc/NEWS
Dosyayı görüntüle @
7c7cbfc0
...
...
@@ -40,6 +40,9 @@ Core and Builtins
Library
-------
-
Issue
#
15008
:
Implement
PEP
362
"Signature Objects"
.
Patch
by
Yury
Selivanov
.
-
Issue
:
#
15138
:
base64
.
urlsafe_
{
en
,
de
}
code
()
are
now
3
-
4
x
faster
.
-
Issue
#
444582
:
Add
shutil
.
which
,
for
finding
programs
on
the
system
path
.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment