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
ff385b89
Kaydet (Commit)
ff385b89
authored
Şub 19, 2014
tarafından
Yury Selivanov
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
inspect: Fix getfullargspec() to not to follow __wrapped__ chains
Initial patch by Nick Coghlan.
üst
eaeb623a
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
109 additions
and
46 deletions
+109
-46
inspect.py
Lib/inspect.py
+65
-46
test_inspect.py
Lib/test/test_inspect.py
+40
-0
NEWS
Misc/NEWS
+4
-0
No files found.
Lib/inspect.py
Dosyayı görüntüle @
ff385b89
...
@@ -949,9 +949,9 @@ def getfullargspec(func):
...
@@ -949,9 +949,9 @@ def getfullargspec(func):
The first four items in the tuple correspond to getargspec().
The first four items in the tuple correspond to getargspec().
"""
"""
builtin_method_param
=
None
try
:
# Re: `skip_bound_arg=False`
if
ismethod
(
func
):
#
# There is a notable difference in behaviour between getfullargspec
# There is a notable difference in behaviour between getfullargspec
# and Signature: the former always returns 'self' parameter for bound
# and Signature: the former always returns 'self' parameter for bound
# methods, whereas the Signature always shows the actual calling
# methods, whereas the Signature always shows the actual calling
...
@@ -960,20 +960,15 @@ def getfullargspec(func):
...
@@ -960,20 +960,15 @@ def getfullargspec(func):
# To simulate this behaviour, we "unbind" bound methods, to trick
# To simulate this behaviour, we "unbind" bound methods, to trick
# inspect.signature to always return their first parameter ("self",
# inspect.signature to always return their first parameter ("self",
# usually)
# usually)
func
=
func
.
__func__
elif
isbuiltin
(
func
):
# Re: `follow_wrapper_chains=False`
# We have a builtin function or method. For that, we check the
#
# special '__text_signature__' attribute, provided by the
# getfullargspec() historically ignored __wrapped__ attributes,
# Argument Clinic. If it's a method, we'll need to make sure
# so we ensure that remains the case in 3.3+
# that its first parameter (usually "self") is always returned
# (see the previous comment).
text_signature
=
getattr
(
func
,
'__text_signature__'
,
None
)
if
text_signature
and
text_signature
.
startswith
(
'($'
):
builtin_method_param
=
_signature_get_bound_param
(
text_signature
)
try
:
sig
=
_signature_internal
(
func
,
sig
=
signature
(
func
)
follow_wrapper_chains
=
False
,
skip_bound_arg
=
False
)
except
Exception
as
ex
:
except
Exception
as
ex
:
# Most of the times 'signature' will raise ValueError.
# Most of the times 'signature' will raise ValueError.
# But, it can also raise AttributeError, and, maybe something
# But, it can also raise AttributeError, and, maybe something
...
@@ -1023,13 +1018,6 @@ def getfullargspec(func):
...
@@ -1023,13 +1018,6 @@ def getfullargspec(func):
# compatibility with 'func.__defaults__'
# compatibility with 'func.__defaults__'
defaults
=
None
defaults
=
None
if
builtin_method_param
and
(
not
args
or
args
[
0
]
!=
builtin_method_param
):
# `func` is a method, and we always need to return its
# first parameter -- usually "self" (to be backwards
# compatible with the previous implementation of
# getfullargspec)
args
.
insert
(
0
,
builtin_method_param
)
return
FullArgSpec
(
args
,
varargs
,
varkw
,
defaults
,
return
FullArgSpec
(
args
,
varargs
,
varkw
,
defaults
,
kwonlyargs
,
kwdefaults
,
annotations
)
kwonlyargs
,
kwdefaults
,
annotations
)
...
@@ -1719,7 +1707,7 @@ def _signature_strip_non_python_syntax(signature):
...
@@ -1719,7 +1707,7 @@ def _signature_strip_non_python_syntax(signature):
return
clean_signature
,
self_parameter
,
last_positional_only
return
clean_signature
,
self_parameter
,
last_positional_only
def
_signature_fromstr
(
cls
,
obj
,
s
):
def
_signature_fromstr
(
cls
,
obj
,
s
,
skip_bound_arg
=
True
):
# Internal helper to parse content of '__text_signature__'
# Internal helper to parse content of '__text_signature__'
# and return a Signature based on it
# and return a Signature based on it
Parameter
=
cls
.
_parameter_cls
Parameter
=
cls
.
_parameter_cls
...
@@ -1840,7 +1828,7 @@ def _signature_fromstr(cls, obj, s):
...
@@ -1840,7 +1828,7 @@ def _signature_fromstr(cls, obj, s):
if
self_parameter
is
not
None
:
if
self_parameter
is
not
None
:
assert
parameters
assert
parameters
if
getattr
(
obj
,
'__self__'
,
None
):
if
getattr
(
obj
,
'__self__'
,
None
)
and
skip_bound_arg
:
# strip off self, it's already been bound
# strip off self, it's already been bound
parameters
.
pop
(
0
)
parameters
.
pop
(
0
)
else
:
else
:
...
@@ -1851,8 +1839,21 @@ def _signature_fromstr(cls, obj, s):
...
@@ -1851,8 +1839,21 @@ def _signature_fromstr(cls, obj, s):
return
cls
(
parameters
,
return_annotation
=
cls
.
empty
)
return
cls
(
parameters
,
return_annotation
=
cls
.
empty
)
def
signature
(
obj
):
def
_signature_from_builtin
(
cls
,
func
,
skip_bound_arg
=
True
):
'''Get a signature object for the passed callable.'''
# Internal helper function to get signature for
# builtin callables
if
not
_signature_is_builtin
(
func
):
raise
TypeError
(
"{!r} is not a Python builtin "
"function"
.
format
(
func
))
s
=
getattr
(
func
,
"__text_signature__"
,
None
)
if
not
s
:
raise
ValueError
(
"no signature found for builtin {!r}"
.
format
(
func
))
return
_signature_fromstr
(
cls
,
func
,
s
,
skip_bound_arg
)
def
_signature_internal
(
obj
,
follow_wrapper_chains
=
True
,
skip_bound_arg
=
True
):
if
not
callable
(
obj
):
if
not
callable
(
obj
):
raise
TypeError
(
'{!r} is not a callable object'
.
format
(
obj
))
raise
TypeError
(
'{!r} is not a callable object'
.
format
(
obj
))
...
@@ -1860,11 +1861,17 @@ def signature(obj):
...
@@ -1860,11 +1861,17 @@ def signature(obj):
if
isinstance
(
obj
,
types
.
MethodType
):
if
isinstance
(
obj
,
types
.
MethodType
):
# In this case we skip the first parameter of the underlying
# In this case we skip the first parameter of the underlying
# function (usually `self` or `cls`).
# function (usually `self` or `cls`).
sig
=
signature
(
obj
.
__func__
)
sig
=
_signature_internal
(
obj
.
__func__
,
return
_signature_bound_method
(
sig
)
follow_wrapper_chains
,
skip_bound_arg
)
if
skip_bound_arg
:
return
_signature_bound_method
(
sig
)
else
:
return
sig
# Was this function wrapped by a decorator?
# Was this function wrapped by a decorator?
obj
=
unwrap
(
obj
,
stop
=
(
lambda
f
:
hasattr
(
f
,
"__signature__"
)))
if
follow_wrapper_chains
:
obj
=
unwrap
(
obj
,
stop
=
(
lambda
f
:
hasattr
(
f
,
"__signature__"
)))
try
:
try
:
sig
=
obj
.
__signature__
sig
=
obj
.
__signature__
...
@@ -1887,7 +1894,9 @@ def signature(obj):
...
@@ -1887,7 +1894,9 @@ def signature(obj):
# (usually `self`, or `cls`) will not be passed
# (usually `self`, or `cls`) will not be passed
# automatically (as for boundmethods)
# automatically (as for boundmethods)
wrapped_sig
=
signature
(
partialmethod
.
func
)
wrapped_sig
=
_signature_internal
(
partialmethod
.
func
,
follow_wrapper_chains
,
skip_bound_arg
)
sig
=
_signature_get_partial
(
wrapped_sig
,
partialmethod
,
(
None
,))
sig
=
_signature_get_partial
(
wrapped_sig
,
partialmethod
,
(
None
,))
first_wrapped_param
=
tuple
(
wrapped_sig
.
parameters
.
values
())[
0
]
first_wrapped_param
=
tuple
(
wrapped_sig
.
parameters
.
values
())[
0
]
...
@@ -1896,7 +1905,8 @@ def signature(obj):
...
@@ -1896,7 +1905,8 @@ def signature(obj):
return
sig
.
replace
(
parameters
=
new_params
)
return
sig
.
replace
(
parameters
=
new_params
)
if
_signature_is_builtin
(
obj
):
if
_signature_is_builtin
(
obj
):
return
Signature
.
from_builtin
(
obj
)
return
_signature_from_builtin
(
Signature
,
obj
,
skip_bound_arg
=
skip_bound_arg
)
if
isfunction
(
obj
)
or
_signature_is_functionlike
(
obj
):
if
isfunction
(
obj
)
or
_signature_is_functionlike
(
obj
):
# If it's a pure Python function, or an object that is duck type
# If it's a pure Python function, or an object that is duck type
...
@@ -1904,7 +1914,9 @@ def signature(obj):
...
@@ -1904,7 +1914,9 @@ def signature(obj):
return
Signature
.
from_function
(
obj
)
return
Signature
.
from_function
(
obj
)
if
isinstance
(
obj
,
functools
.
partial
):
if
isinstance
(
obj
,
functools
.
partial
):
wrapped_sig
=
signature
(
obj
.
func
)
wrapped_sig
=
_signature_internal
(
obj
.
func
,
follow_wrapper_chains
,
skip_bound_arg
)
return
_signature_get_partial
(
wrapped_sig
,
obj
)
return
_signature_get_partial
(
wrapped_sig
,
obj
)
sig
=
None
sig
=
None
...
@@ -1915,17 +1927,23 @@ def signature(obj):
...
@@ -1915,17 +1927,23 @@ def signature(obj):
# in its metaclass
# in its metaclass
call
=
_signature_get_user_defined_method
(
type
(
obj
),
'__call__'
)
call
=
_signature_get_user_defined_method
(
type
(
obj
),
'__call__'
)
if
call
is
not
None
:
if
call
is
not
None
:
sig
=
signature
(
call
)
sig
=
_signature_internal
(
call
,
follow_wrapper_chains
,
skip_bound_arg
)
else
:
else
:
# Now we check if the 'obj' class has a '__new__' method
# Now we check if the 'obj' class has a '__new__' method
new
=
_signature_get_user_defined_method
(
obj
,
'__new__'
)
new
=
_signature_get_user_defined_method
(
obj
,
'__new__'
)
if
new
is
not
None
:
if
new
is
not
None
:
sig
=
signature
(
new
)
sig
=
_signature_internal
(
new
,
follow_wrapper_chains
,
skip_bound_arg
)
else
:
else
:
# Finally, we should have at least __init__ implemented
# Finally, we should have at least __init__ implemented
init
=
_signature_get_user_defined_method
(
obj
,
'__init__'
)
init
=
_signature_get_user_defined_method
(
obj
,
'__init__'
)
if
init
is
not
None
:
if
init
is
not
None
:
sig
=
signature
(
init
)
sig
=
_signature_internal
(
init
,
follow_wrapper_chains
,
skip_bound_arg
)
if
sig
is
None
:
if
sig
is
None
:
# At this point we know, that `obj` is a class, with no user-
# At this point we know, that `obj` is a class, with no user-
...
@@ -1967,7 +1985,9 @@ def signature(obj):
...
@@ -1967,7 +1985,9 @@ def signature(obj):
call
=
_signature_get_user_defined_method
(
type
(
obj
),
'__call__'
)
call
=
_signature_get_user_defined_method
(
type
(
obj
),
'__call__'
)
if
call
is
not
None
:
if
call
is
not
None
:
try
:
try
:
sig
=
signature
(
call
)
sig
=
_signature_internal
(
call
,
follow_wrapper_chains
,
skip_bound_arg
)
except
ValueError
as
ex
:
except
ValueError
as
ex
:
msg
=
'no signature found for {!r}'
.
format
(
obj
)
msg
=
'no signature found for {!r}'
.
format
(
obj
)
raise
ValueError
(
msg
)
from
ex
raise
ValueError
(
msg
)
from
ex
...
@@ -1975,7 +1995,10 @@ def signature(obj):
...
@@ -1975,7 +1995,10 @@ def signature(obj):
if
sig
is
not
None
:
if
sig
is
not
None
:
# For classes and objects we skip the first parameter of their
# For classes and objects we skip the first parameter of their
# __call__, __new__, or __init__ methods
# __call__, __new__, or __init__ methods
return
_signature_bound_method
(
sig
)
if
skip_bound_arg
:
return
_signature_bound_method
(
sig
)
else
:
return
sig
if
isinstance
(
obj
,
types
.
BuiltinFunctionType
):
if
isinstance
(
obj
,
types
.
BuiltinFunctionType
):
# Raise a nicer error message for builtins
# Raise a nicer error message for builtins
...
@@ -1984,6 +2007,10 @@ def signature(obj):
...
@@ -1984,6 +2007,10 @@ def signature(obj):
raise
ValueError
(
'callable {!r} is not supported by signature'
.
format
(
obj
))
raise
ValueError
(
'callable {!r} is not supported by signature'
.
format
(
obj
))
def
signature
(
obj
):
'''Get a signature object for the passed callable.'''
return
_signature_internal
(
obj
)
class
_void
:
class
_void
:
'''A private marker - used in Parameter & Signature'''
'''A private marker - used in Parameter & Signature'''
...
@@ -2417,15 +2444,7 @@ class Signature:
...
@@ -2417,15 +2444,7 @@ class Signature:
@classmethod
@classmethod
def
from_builtin
(
cls
,
func
):
def
from_builtin
(
cls
,
func
):
if
not
_signature_is_builtin
(
func
):
return
_signature_from_builtin
(
cls
,
func
)
raise
TypeError
(
"{!r} is not a Python builtin "
"function"
.
format
(
func
))
s
=
getattr
(
func
,
"__text_signature__"
,
None
)
if
not
s
:
raise
ValueError
(
"no signature found for builtin {!r}"
.
format
(
func
))
return
_signature_fromstr
(
cls
,
func
,
s
)
@property
@property
def
parameters
(
self
):
def
parameters
(
self
):
...
...
Lib/test/test_inspect.py
Dosyayı görüntüle @
ff385b89
...
@@ -577,6 +577,46 @@ class TestClassesAndFunctions(unittest.TestCase):
...
@@ -577,6 +577,46 @@ class TestClassesAndFunctions(unittest.TestCase):
kwonlyargs_e
=
[
'arg'
],
kwonlyargs_e
=
[
'arg'
],
formatted
=
'(*, arg)'
)
formatted
=
'(*, arg)'
)
def
test_argspec_api_ignores_wrapped
(
self
):
# Issue 20684: low level introspection API must ignore __wrapped__
@functools.wraps
(
mod
.
spam
)
def
ham
(
x
,
y
):
pass
# Basic check
self
.
assertArgSpecEquals
(
ham
,
[
'x'
,
'y'
],
formatted
=
'(x, y)'
)
self
.
assertFullArgSpecEquals
(
ham
,
[
'x'
,
'y'
],
formatted
=
'(x, y)'
)
self
.
assertFullArgSpecEquals
(
functools
.
partial
(
ham
),
[
'x'
,
'y'
],
formatted
=
'(x, y)'
)
# Other variants
def
check_method
(
f
):
self
.
assertArgSpecEquals
(
f
,
[
'self'
,
'x'
,
'y'
],
formatted
=
'(self, x, y)'
)
class
C
:
@functools.wraps
(
mod
.
spam
)
def
ham
(
self
,
x
,
y
):
pass
pham
=
functools
.
partialmethod
(
ham
)
@functools.wraps
(
mod
.
spam
)
def
__call__
(
self
,
x
,
y
):
pass
check_method
(
C
())
check_method
(
C
.
ham
)
check_method
(
C
()
.
ham
)
check_method
(
C
.
pham
)
check_method
(
C
()
.
pham
)
class
C_new
:
@functools.wraps
(
mod
.
spam
)
def
__new__
(
self
,
x
,
y
):
pass
check_method
(
C_new
)
class
C_init
:
@functools.wraps
(
mod
.
spam
)
def
__init__
(
self
,
x
,
y
):
pass
check_method
(
C_init
)
def
test_getfullargspec_signature_attr
(
self
):
def
test_getfullargspec_signature_attr
(
self
):
def
test
():
def
test
():
pass
pass
...
...
Misc/NEWS
Dosyayı görüntüle @
ff385b89
...
@@ -26,6 +26,10 @@ Core and Builtins
...
@@ -26,6 +26,10 @@ Core and Builtins
Library
Library
-------
-------
- Issue #20684: Fix inspect.getfullargspec() to not to follow __wrapped__
chains. Make its behaviour consistent with bound methods first argument.
Patch by Nick Coghlan and Yury Selivanov.
- Issue #20681: Add new error handling API in asyncio. New APIs:
- Issue #20681: Add new error handling API in asyncio. New APIs:
loop.set_exception_handler(), loop.default_exception_handler(), and
loop.set_exception_handler(), loop.default_exception_handler(), and
loop.call_exception_handler().
loop.call_exception_handler().
...
...
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