Failed Conditions
Pull Request — master (#1990)
by Mischa
01:42
created

coalib/misc/Future.py (1 issue)

1
from functools import partial
2
3
4
# FIXME: Remove `partialmethod` when dropping Python 3.3 support.
5
# This code falls under the Python 3.4.3 license:
6
# https://www.python.org/download/releases/3.4.3/license/
7
# Descriptor version
8
class partialmethod(object):  # pragma: no cover
9
    """Method descriptor with partial application of the given arguments
10
    and keywords.
11
12
    Supports wrapping existing descriptors and handles non-descriptor
13
    callables as instance methods.
14
    """
15
16
    def __init__(self, func, *args, **keywords):
17
        if not callable(func) and not hasattr(func, "__get__"):
18
            raise TypeError("{!r} is not callable or a descriptor"
19
                                 .format(func))
20
21
        # func could be a descriptor like classmethod which isn't callable,
22
        # so we can't inherit from partial (it verifies func is callable)
23
        if isinstance(func, partialmethod):
24
            # flattening is mandatory in order to place cls/self before all
25
            # other arguments
26
            # it's also more efficient since only one function will be called
27
            self.func = func.func
28
            self.args = func.args + args
29
            self.keywords = func.keywords.copy()
30
            self.keywords.update(keywords)
31
        else:
32
            self.func = func
33
            self.args = args
34
            self.keywords = keywords
35
36
    def __repr__(self):
37
        args = ", ".join(map(repr, self.args))
38
        keywords = ", ".join("{}={!r}".format(k, v)
39
                                 for k, v in self.keywords.items())
40
        format_string = "{module}.{cls}({func}, {args}, {keywords})"
41
        return format_string.format(module=self.__class__.__module__,
42
                                    cls=self.__class__.__name__,
43
                                    func=self.func,
44
                                    args=args,
45
                                    keywords=keywords)
46
47
    def _make_unbound_method(self):
48
        def _method(*args, **keywords):
49
            call_keywords = self.keywords.copy()
50
            call_keywords.update(keywords)
51
            cls_or_self, *rest = args
52
            call_args = (cls_or_self,) + self.args + tuple(rest)
53
            return self.func(*call_args, **call_keywords)
54
        _method.__isabstractmethod__ = self.__isabstractmethod__
55
        _method._partialmethod = self
56
        return _method
57
58
    def __get__(self, obj, cls):
59
        get = getattr(self.func, "__get__", None)
60
        result = None
61
        if get is not None:
62
            new_func = get(obj, cls)
63
            if new_func is not self.func:
64
                # Assume __get__ returning something new indicates the
65
                # creation of an appropriate callable
66
                result = partial(new_func, *self.args, **self.keywords)
67
                try:
68
                    result.__self__ = new_func.__self__
69
                except AttributeError:
70
                    pass
71
        if result is None:
72
            # If the underlying descriptor didn't do anything, treat this
73
            # like an instance method
74
            result = self._make_unbound_method().__get__(obj, cls)
75
        return result
76
77
    @property
78
    def __isabstractmethod__(self):
79
        return getattr(self.func, "__isabstractmethod__", False)
0 ignored issues
show
Final newline missing
Loading history...