Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
d82eddcf
Commit
d82eddcf
authored
Jan 29, 2014
by
Yury Selivanov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
inspect.getfullargspec: Use inspect.signature API behind the scenes #17481
parent
07a9e452
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
155 additions
and
7 deletions
+155
-7
Doc/whatsnew/3.4.rst
Doc/whatsnew/3.4.rst
+7
-0
Lib/inspect.py
Lib/inspect.py
+105
-6
Lib/test/test_inspect.py
Lib/test/test_inspect.py
+41
-1
Misc/NEWS
Misc/NEWS
+2
-0
No files found.
Doc/whatsnew/3.4.rst
View file @
d82eddcf
...
...
@@ -786,6 +786,13 @@ As part of the implementation of the new :mod:`enum` module, the
metaclasses (Contributed by Ethan Furman in :issue:`18929` and
:issue:`19030`)
:func:`~inspect.getfullargspec` and :func:`~inspect.getargspec`
now use the :func:`~inspect.signature` API. This allows them to
support much broader range of functions, including some builtins and
callables that follow ``__signature__`` protocol. It is still
recommended to update your code to use :func:`~inspect.signature`
directly. (Contributed by Yury Selivanov in :issue:`17481`)
logging
-------
...
...
Lib/inspect.py
View file @
d82eddcf
...
...
@@ -934,7 +934,7 @@ FullArgSpec = namedtuple('FullArgSpec',
'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations'
)
def
getfullargspec
(
func
):
"""Get the names and default values of a
function
's arguments.
"""Get the names and default values of a
callable object
's arguments.
A tuple of seven things is returned:
(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations).
...
...
@@ -948,13 +948,90 @@ def getfullargspec(func):
The first four items in the tuple correspond to getargspec().
"""
builtin_method_param
=
None
if
ismethod
(
func
):
# There is a notable difference in behaviour between getfullargspec
# and Signature: the former always returns 'self' parameter for bound
# methods, whereas the Signature always shows the actual calling
# signature of the passed object.
#
# To simulate this behaviour, we "unbind" bound methods, to trick
# inspect.signature to always return their first parameter ("self",
# usually)
func
=
func
.
__func__
if
not
isfunction
(
func
):
raise
TypeError
(
'{!r} is not a Python function'
.
format
(
func
))
args
,
varargs
,
kwonlyargs
,
varkw
=
_getfullargs
(
func
.
__code__
)
return
FullArgSpec
(
args
,
varargs
,
varkw
,
func
.
__defaults__
,
kwonlyargs
,
func
.
__kwdefaults__
,
func
.
__annotations__
)
elif
isbuiltin
(
func
):
# We have a builtin function or method. For that, we check the
# special '__text_signature__' attribute, provided by the
# Argument Clinic. If it's a method, we'll need to make sure
# 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
(
func
)
except
Exception
as
ex
:
# Most of the times 'signature' will raise ValueError.
# But, it can also raise AttributeError, and, maybe something
# else. So to be fully backwards compatible, we catch all
# possible exceptions here, and reraise a TypeError.
raise
TypeError
(
'unsupported callable'
)
from
ex
args
=
[]
varargs
=
None
varkw
=
None
kwonlyargs
=
[]
defaults
=
()
annotations
=
{}
defaults
=
()
kwdefaults
=
{}
if
sig
.
return_annotation
is
not
sig
.
empty
:
annotations
[
'return'
]
=
sig
.
return_annotation
for
param
in
sig
.
parameters
.
values
():
kind
=
param
.
kind
name
=
param
.
name
if
kind
is
_POSITIONAL_ONLY
:
args
.
append
(
name
)
elif
kind
is
_POSITIONAL_OR_KEYWORD
:
args
.
append
(
name
)
if
param
.
default
is
not
param
.
empty
:
defaults
+=
(
param
.
default
,)
elif
kind
is
_VAR_POSITIONAL
:
varargs
=
name
elif
kind
is
_KEYWORD_ONLY
:
kwonlyargs
.
append
(
name
)
if
param
.
default
is
not
param
.
empty
:
kwdefaults
[
name
]
=
param
.
default
elif
kind
is
_VAR_KEYWORD
:
varkw
=
name
if
param
.
annotation
is
not
param
.
empty
:
annotations
[
name
]
=
param
.
annotation
if
not
kwdefaults
:
# compatibility with 'func.__kwdefaults__'
kwdefaults
=
None
if
not
defaults
:
# compatibility with 'func.__defaults__'
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
,
kwonlyargs
,
kwdefaults
,
annotations
)
ArgInfo
=
namedtuple
(
'ArgInfo'
,
'args varargs keywords locals'
)
...
...
@@ -1524,6 +1601,28 @@ def _signature_is_builtin(obj):
obj
in
(
type
,
object
))
def
_signature_get_bound_param
(
spec
):
# Internal helper to get first parameter name from a
# __text_signature__ of a builtin method, which should
# be in the following format: '($param1, ...)'.
# Assumptions are that the first argument won't have
# a default value or an annotation.
assert
spec
.
startswith
(
'($'
)
pos
=
spec
.
find
(
','
)
if
pos
==
-
1
:
pos
=
spec
.
find
(
')'
)
cpos
=
spec
.
find
(
':'
)
assert
cpos
==
-
1
or
cpos
>
pos
cpos
=
spec
.
find
(
'='
)
assert
cpos
==
-
1
or
cpos
>
pos
return
spec
[
2
:
pos
]
def
signature
(
obj
):
'''Get a signature object for the passed callable.'''
...
...
Lib/test/test_inspect.py
View file @
d82eddcf
...
...
@@ -578,6 +578,36 @@ class TestClassesAndFunctions(unittest.TestCase):
kwonlyargs_e
=
[
'arg'
],
formatted
=
'(*, arg)'
)
def
test_getfullargspec_signature_attr
(
self
):
def
test
():
pass
spam_param
=
inspect
.
Parameter
(
'spam'
,
inspect
.
Parameter
.
POSITIONAL_ONLY
)
test
.
__signature__
=
inspect
.
Signature
(
parameters
=
(
spam_param
,))
self
.
assertFullArgSpecEquals
(
test
,
args_e
=
[
'spam'
],
formatted
=
'(spam)'
)
@
unittest
.
skipIf
(
MISSING_C_DOCSTRINGS
,
"Signature information for builtins requires docstrings"
)
def
test_getfullargspec_builtin_methods
(
self
):
self
.
assertFullArgSpecEquals
(
_pickle
.
Pickler
.
dump
,
args_e
=
[
'self'
,
'obj'
],
formatted
=
'(self, obj)'
)
self
.
assertFullArgSpecEquals
(
_pickle
.
Pickler
(
io
.
BytesIO
()).
dump
,
args_e
=
[
'self'
,
'obj'
],
formatted
=
'(self, obj)'
)
@
unittest
.
skipIf
(
MISSING_C_DOCSTRINGS
,
"Signature information for builtins requires docstrings"
)
def
test_getfullagrspec_builtin_func
(
self
):
builtin
=
_testcapi
.
docstring_with_signature_with_defaults
spec
=
inspect
.
getfullargspec
(
builtin
)
self
.
assertEqual
(
spec
.
defaults
[
0
],
'avocado'
)
@
unittest
.
skipIf
(
MISSING_C_DOCSTRINGS
,
"Signature information for builtins requires docstrings"
)
def
test_getfullagrspec_builtin_func_no_signature
(
self
):
builtin
=
_testcapi
.
docstring_no_signature
with
self
.
assertRaises
(
TypeError
):
inspect
.
getfullargspec
(
builtin
)
def
test_getargspec_method
(
self
):
class
A
(
object
):
...
...
@@ -2614,6 +2644,15 @@ class TestBoundArguments(unittest.TestCase):
self
.
assertNotEqual
(
ba
,
ba4
)
class
TestSignaturePrivateHelpers
(
unittest
.
TestCase
):
def
test_signature_get_bound_param
(
self
):
getter
=
inspect
.
_signature_get_bound_param
self
.
assertEqual
(
getter
(
'($self)'
),
'self'
)
self
.
assertEqual
(
getter
(
'($self, obj)'
),
'self'
)
self
.
assertEqual
(
getter
(
'($cls, /, obj)'
),
'cls'
)
class
TestUnwrap
(
unittest
.
TestCase
):
def
test_unwrap_one
(
self
):
...
...
@@ -2719,7 +2758,8 @@ def test_main():
TestGetcallargsFunctions
,
TestGetcallargsMethods
,
TestGetcallargsUnboundMethods
,
TestGetattrStatic
,
TestGetGeneratorState
,
TestNoEOL
,
TestSignatureObject
,
TestSignatureBind
,
TestParameterObject
,
TestBoundArguments
,
TestGetClosureVars
,
TestUnwrap
,
TestMain
TestBoundArguments
,
TestSignaturePrivateHelpers
,
TestGetClosureVars
,
TestUnwrap
,
TestMain
)
if
__name__
==
"__main__"
:
...
...
Misc/NEWS
View file @
d82eddcf
...
...
@@ -47,6 +47,8 @@ Library
- Issue #20105: the codec exception chaining now correctly sets the
traceback of the original exception as its __traceback__ attribute.
- Issue #17481: inspect.getfullargspec() now uses inspect.signature() API.
IDLE
----
...
...
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