Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wirerope/callable.py: 65%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import absolute_import
3import types
4import six
5from ._util import cached_property
6from ._compat import inspect
8__all__ = ('Callable', )
11_inspect_iscoroutinefunction = getattr(
12 inspect, 'iscoroutinefunction', lambda f: False)
15class _Reagent(object):
16 pass
19_reagent = _Reagent()
22def _f(owner):
23 return owner
26def _name_binder(descriptor, obj, type):
27 return type, None
30def _type_binder(descriptor, obj, type):
31 return type, type
34def _obj_binder(descriptor, obj, type):
35 return obj, obj
38_descriptor_binder_cache = {}
41class Descriptor(object):
43 def __init__(self, descriptor):
44 self.descriptor = descriptor
45 self.descriptor_class = type(descriptor)
47 def detect_function_attr_name(self):
48 indicator = object()
49 descriptor = self.descriptor_class(indicator)
50 for name in dir(descriptor):
51 try:
52 attr = getattr(descriptor, name)
53 except AttributeError:
54 continue
55 if attr is indicator:
56 # detected!
57 return name
58 else:
59 raise RuntimeError(
60 "The given function doesn't hold the given function as an "
61 "attribute. Is it a correct descriptor?")
63 def detect_property(self, obj, type_):
64 d = self.descriptor_class(_f)
65 method_or_value = d.__get__(obj, type_)
66 return method_or_value is obj or method_or_value is type_
68 def detect_binder(self, obj, type_):
69 key = (self.descriptor_class, obj is not None)
70 if key not in _descriptor_binder_cache:
71 d = self.descriptor_class(_f)
72 method = d.__get__(obj, type_)
73 if isinstance(method, types.FunctionType):
74 # not a boundmethod - probably staticmethod
75 binder = _name_binder
76 elif method is obj:
77 binder = _obj_binder
78 elif method is type_:
79 binder = _type_binder
80 elif callable(method):
81 owner = method()
82 if owner is type_:
83 binder = _type_binder
84 elif owner is obj:
85 binder = _obj_binder
86 else:
87 binder = None
88 elif method is d:
89 # some non-method descriptor
90 binder = _name_binder
91 else:
92 binder = None
93 if binder is None:
94 raise TypeError(
95 "'descriptor_bind' fails to auto-detect binding rule "
96 "of the given descriptor. Specify the rule by "
97 "'wirerope.wire.descriptor_bind.register'.")
98 _descriptor_binder_cache[key] = binder
99 else:
100 binder = _descriptor_binder_cache[key]
101 return binder
104class Callable(object):
105 """A wrapper object including more information of callables."""
107 def __init__(self, f):
108 self.wrapped_object = f
109 self.is_function_type = type(self) is types.FunctionType # noqa
110 if self.is_descriptor:
111 self.descriptor = Descriptor(f)
112 f = getattr(f, self.descriptor.detect_function_attr_name())
113 else:
114 self.descriptor = None
115 self.wrapped_callable = f
116 self.is_wrapped_coroutine = getattr(f, '_is_coroutine', None)
117 self.is_coroutine = self.is_wrapped_coroutine or \
118 _inspect_iscoroutinefunction(f)
120 @cached_property
121 def signature(self):
122 return inspect.signature(self.wrapped_callable)
124 @cached_property
125 def parameters(self):
126 return list(self.signature.parameters.values())
128 @property
129 def first_parameter(self):
130 return self.parameters[0] if self.parameters else None
132 @cached_property
133 def is_boundmethod(self):
134 if self.is_function_type or self.is_builtin_property:
135 return False
136 new_bound = self.wrapped_object.__get__(object())
137 try:
138 if six.PY2:
139 return new_bound is self.wrapped_object
140 else:
141 return type(new_bound) is type(self.wrapped_object) # noqa
142 except Exception:
143 return False
145 if six.PY2:
146 @property
147 def is_unboundmethod(self):
148 return type(self.wrapped_object) is type(Callable.__init__) # noqa
150 @cached_property
151 def is_descriptor(self):
152 if self.is_boundmethod:
153 return False
154 is_descriptor = type(self.wrapped_object).__get__ \
155 is not types.FunctionType.__get__ # noqa
156 if six.PY2:
157 is_descriptor = is_descriptor and \
158 not (self.is_unboundmethod or self.is_boundmethod)
159 return is_descriptor
161 @cached_property
162 def is_builtin_property(self):
163 return issubclass(type(self.wrapped_object), property)
165 @cached_property
166 def is_property(self):
167 return self.is_builtin_property or \
168 (self.is_descriptor and self.descriptor.detect_property(
169 _reagent, _Reagent))
171 if six.PY34:
172 @cached_property
173 def is_barefunction(self):
174 cc = self.wrapped_callable
175 method_name = cc.__qualname__.split('<locals>.')[-1]
176 if method_name == cc.__name__:
177 return True
178 return False
179 else:
180 @cached_property
181 def is_barefunction(self):
182 # im_class does not exist at this point
183 if self.is_descriptor:
184 return False
185 if six.PY2:
186 if self.is_unboundmethod:
187 return False
188 return not (self.is_membermethod or self.is_classmethod)
190 @cached_property
191 def is_member(self):
192 """Test given argument is a method or not.
194 :rtype: bool
196 :note: The test is partially based on the first parameter name.
197 The test result might be wrong.
198 """
199 if six.PY34:
200 if self.is_barefunction:
201 return False
202 if not self.is_descriptor:
203 return True
204 return self.first_parameter is not None \
205 and self.first_parameter.name == 'self'
207 @cached_property
208 def is_membermethod(self):
209 """Test given argument is a method or not.
211 :rtype: bool
213 :note: The test is partially based on the first parameter name.
214 The test result might be wrong.
215 """
216 if self.is_boundmethod:
217 return False
218 if self.is_property:
219 return False
220 return self.is_member
222 @cached_property
223 def is_classmethod(self):
224 """Test given argument is a classmethod or not.
226 :rtype: bool
228 :note: The test is partially based on the first parameter name.
229 The test result might be wrong.
230 """
231 if isinstance(self.wrapped_object, classmethod):
232 return True
233 if six.PY34:
234 if self.is_barefunction:
235 return False
236 if not self.is_descriptor:
237 return False
239 return self.first_parameter is not None \
240 and self.first_parameter.name == 'cls'