File: robustapply.py

package info (click to toggle)
python-scrapy 0.24.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 3,240 kB
  • ctags: 4,259
  • sloc: python: 21,170; xml: 199; makefile: 67; sh: 44
file content (55 lines) | stat: -rw-r--r-- 1,967 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"""Robust apply mechanism

Provides a function "call", which can sort out
what arguments a given callable object can take,
and subset the given arguments to match only
those which are acceptable.
"""

import inspect

def function(receiver):
    """Get function-like callable object for given receiver

    returns (function_or_method, codeObject, fromMethod)

    If fromMethod is true, then the callable already
    has its first argument bound
    """
    if inspect.isclass(receiver) and hasattr(receiver, '__call__'):
        # receiver is a class instance; assume it is callable.
        # Reassign receiver to the actual method that will be called.
        if hasattr(receiver.__call__, 'im_func') or \
           hasattr(receiver.__call__, 'im_code'):
            receiver = receiver.__call__

    if hasattr( receiver, 'im_func' ):
        # an instance-method...
        return receiver, receiver.im_func.func_code, 1
    elif not hasattr(receiver, 'func_code'):
        raise ValueError('unknown receiver type %s %s'%(receiver, type(receiver)))

    return receiver, receiver.func_code, 0

def robustApply(receiver, *arguments, **named):
    """Call receiver with arguments and an appropriate subset of named
    """
    receiver, codeObject, startIndex = function(receiver)
    acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]
    for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:
        if named.has_key(name):
            raise TypeError(
                """Argument %r specified both positionally and as a keyword for calling %r"""% (
                    name, receiver,
                )
            )

    if not (codeObject.co_flags & 8):
        # fc does not have a **kwds type parameter, therefore 
        # remove unacceptable arguments.
        for arg in named.keys():
            if arg not in acceptable:
                del named[arg]

    return receiver(*arguments, **named)