Issue 20828: inspect.getargspec() returns wrong answer with datetime.today.call() (original) (raw)
Created on 2014-03-02 15:10 by zzzeek, last changed 2022-04-11 14:57 by admin. This issue is now closed.
Messages (6)
Author: mike bayer (zzzeek) *
Date: 2014-03-02 15:10
this appears like it may be related to http://bugs.python.org/issue20786, at least in terms of inspect.getargspec() seems to be returning answers in 3.4 where it used to raise TypeError, however like in 20786 it's again returning the wrong answer. I'm a little concerned that some change was made to allow inspection of lots of builtins that wasn't before, but the argument lists haven't been checked.
test case:
import inspect import datetime
try: insp = inspect.getargspec(datetime.datetime.today.call) except TypeError: pass else: print(insp) assert insp == (["self"], "args", "kwargs", None)
# claims to accept "args" and "kwargs", ok let's try...
datetime.datetime.today.__call__(1, 2, foo='bar')
# raises:
# TypeError: today() takes no keyword arguments
Author: mike bayer (zzzeek) *
Date: 2014-03-02 15:38
I've also worked around this on my end, so if my poking into today.call() isn't really a good idea anyway, I'm not doing that anymore.
Author: Yury Selivanov (yselivanov) *
Date: 2014-03-02 17:12
Why are you trying to get signature of 'datetime.datetime.today.call'?
call in this case is a generic python object -- method-wrapper. It is used to make a classmethod. And the signature that getargspec is returning for it is correct.
Author: mike bayer (zzzeek) *
Date: 2014-03-02 18:07
we basically need to be able to get the argument signature for anything that passes callable(); function, method, class, object with call. So this is the logic we use:
import inspect
def get_callable_argspec(fn): if inspect.isfunction(fn) or inspect.ismethod(fn): inspectable = fn elif inspect.isclass(fn): inspectable = fn.init elif hasattr(fn, 'call'): inspectable = fn.call else: inspectable = fn
try:
return inspect.getargspec(inspectable)
except TypeError:
raise
def callable1(self, x, y): pass
class SomeClass(object): def init(self, x, y): pass
def callable2(self, x, y):
pass
def __call__(self, x, y):
pass
callable3 = SomeClass callable4 = SomeClass(2, 3)
for callable_ in (callable1, SomeClass(1, 2).callable2, callable3, callable4): assert callable(callable_) # the interpreter can tell me this
# how can it reliably tell me this?
assert get_callable_argspec(callable_) == (["self", "x", "y"], None, None, None)
If you pass a builtin like datetime.datetime.today to it, isfunction()/ismethod()/isclass() return false, but it does have a call().
I'm working around this now by just refusing to act on anything that is types.BuiltinMethodType or types.BuiltinFunctionType.
Any guidance on what the proper way is to get the argument signature for any object that returns True for callable() would be very helpful (py2.6-3.x compatible). I'm not sure if there's a stdlib call for this.
Author: Yury Selivanov (yselivanov) *
Date: 2014-03-02 21:17
OK, I see.
I'd recommend you to take a look how inspect.signature is implemented in 3.3 or 3.4 (and maybe backport it to python 2 and use the new API).
To quickly fix your code, I'd suggest the following modifications:
_WrapperDescriptor = type(type.call) _MethodWrapper = type(all.call) _ClassMethodWrapper = type(int.dict['from_bytes'])
def get_callable_argspec(fn): if inspect.isfunction(fn) or inspect.ismethod(fn): inspectable = fn elif inspect.isclass(fn): inspectable = fn.init elif hasattr(fn, 'call'): inspectable = fn.call else: inspectable = fn
if isinstance(fn, (_WrapperDescriptor, _MethodWrapper, _ClassMethodWrapper)):
raise ValueError('unsupported callable {!r}'.format(fn))
try:
return inspect.getargspec(inspectable)
except TypeError:
raise
I'm closing this issue, as there is no real bug or regression in getargspec.
Author: mike bayer (zzzeek) *
Date: 2014-03-02 22:04
I've got something like that going on right now, but am doing it in the other direction; when I look at call(), I only do anything with it if it passes inspect.ismethod(). Since I only want plain Python call() functions on plain Python objects.
History
Date
User
Action
Args
2022-04-11 14:57:59
admin
set
github: 65027
2014-03-02 22:04:51
zzzeek
set
messages: +
2014-03-02 21:17:12
yselivanov
set
status: open -> closed
resolution: not a bug
messages: +
2014-03-02 19:52:05
Arfrever
set
nosy: + Arfrever
2014-03-02 18:07:40
zzzeek
set
messages: +
2014-03-02 17:13:04
yselivanov
set
nosy: + ncoghlan
2014-03-02 17:12:51
yselivanov
set
nosy: + yselivanov
messages: +
2014-03-02 15:38:39
zzzeek
set
messages: +
2014-03-02 15:19:26
r.david.murray
set
nosy: + larry
2014-03-02 15:10:47
zzzeek
create