Roundup Tracker - Issues

Message6016

Author rouilj
Recipients ezio.melotti, rouilj
Date 2017-09-14.23:20:34
Message-id <20170914232017.005994C0972@itserver6.localdomain>
In-reply-to <1505421313.77.0.0767788137936.issue2550952@psf.upfronthosting.co.za>
Hi Ezio:

In message
<1505421313.77.0.0767788137936.issue2550952@psf.upfronthosting.co.za>,
Ezio Melotti writes:
>
>https://sourceforge.net/p/roundup/code/ci/36630a062fb5 introduced a check 
>that uses inspect.getargspec().  In our instance we were using a callable 
>instance for a check ( https://hg.python.org/tracker/python-
>dev/file/545a7d7ef9e4/schema.py#l251 ) and while updating roundup we got 
>the failure "TypeError: <__builtin__.may_view_spam instance at 
>0x7f2ac7629bd8> is not a Python function" since getargspec() only works 
>with Python functions and not arbitrary callables.

Hmm, from https://bugs.python.org/issue20828 we get something like:

_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

This seems to be best, but could it break on python if they once again
deprecate getfullargspec per
https://docs.python.org/3/library/inspect.html

   Changed in version 3.4: This function is now based on signature(),
   but still ignores __wrapped__ attributes and includes the already
   bound first parameter in the signature output for bound methods.

   Changed in version 3.6: This method was previously documented as
   deprecated in favour of signature() in Python 3.5, but that
   decision has been reversed in order to restore a clearly supported
   standard interface for single-source Python 2/3 code migrating away
   from the legacy getargspec() API.

From
https://www.programcreek.com/python/example/87828/inspect.getfullargspec

[From project xonsh-master, under directory xonsh, in source file
 inspectors.py.]

def getargspec(obj):
    """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
    :func:inspect.getargspec` on Python 2.

    In addition to functions and methods, this can also handle objects with a
    ``__call__`` attribute.
    """
        if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
	        obj = obj.__call__

    return inspect.getfullargspec(obj) if ISPY3K else inspect.getargspec(obj)

They have a fair number of local functions there safe_hasattr and
is_simple_callable but using something like this should fix your
immediate issue right Ezio?

>We fixed this on our end by replacing the callable class with a function 
>that uses a closure to store the klassname, but the fact that arbitrary 
>callables are no longer supported is technically a backward incompatible 
>change that you might want to fix in Roundup.

I don't remember any of the examples in the docs that use anything
other than an actual function. So as you correctly state, technically
it's changed incompatibly.  However it was never advertised that it
would work 8-).

However there is probably no statement that arbitrary callables
shouldn't work so let's try to fix it for your use case at least.

>FWIW getargspec(inst.__call__) works, but there might be better way to 
>fix it.

There are some code ideas above. My thoughts are:

  Add function findargspec to anypy/getarspec_.py that wraps
    getargspec/getfullargspec and checks for __call__ and uses that
    if present.

  Use this function in place of inspect.getargspec in security.py

  Remove the comment to remove the array subscript notation as it looks
    like the field name changes for the 4 fields in common between
    the tuple returned by getargspec and getfullargspec

If I get this done would you be able to add a couple of test cases to
the test suit that exercises both forms of __call__ to see if I got
the code correct?

Have a great day.
History
Date User Action Args
2017-09-14 23:20:35rouiljsetrecipients: + rouilj, ezio.melotti
2017-09-14 23:20:35rouiljlinkissue2550952 messages
2017-09-14 23:20:34rouiljcreate