ROOT  6.06/09
Reference Guide
_pythonization.py
Go to the documentation of this file.
1 """ Pythonization API.
2 """
3 
4 # TODO: externalize this (have PythonizationScope and UserPythonizations as
5 # globals here and picked up from this module
6 
7 # TODO: set explicit export list
8 
9 # TODO: move cast to cppyy.lowlevel or some sort
10 
11 # TODO: remove all need for accessing _backend
12 def _set_backend( backend ):
13  global _backend
14  _backend = backend
15 
17  _backend.PythonizationScope = scope
18  if scope not in _backend.UserPythonizations:
19  _backend.UserPythonizations[scope] = []
20 
21 
22 def add_pythonization(pythonizor):
23  """Takes a callable that should take two arguments -- the class proxy,
24  and its C++ name -- and which is called the first time the named
25  class is bound.
26  """
27  scope = _backend.PythonizationScope
28  #scope = _pythonization_scope
29  if pythonizor and not callable(pythonizor):
30  raise TypeError("given '%s' object is not callable" % str(pythonizor))
31  if pythonizor:
32  # _pythonizations[scope]
33  _backend.UserPythonizations[scope].append(pythonizor)
34 
35 
36 def pin_type(derived_type, base_type):
37  _backend.SetTypePinning(derived_type, base_type)
38 
39 
40 def make_interface(base_type):
41  pin_type(base_type, base_type)
42 
43 
44 def ignore_type_pinning(some_type):
45  _backend.IgnoreTypePinning(some_type)
46 
47 
48 def cast(some_object, new_type):
49  return _backend.Cast(some_object, new_type)
50 
51 
52 def add_exception_mapping(cpp_exception, py_exception):
53  _backend.UserExceptions[cpp_exception] = py_exception
54 
55 
56 
57 #--- Pythonization factories --------------------------------------------
58 
59 def set_gil_policy(match_class, match_method, release_gil=True):
60  return set_method_property(match_class, match_method, '_threaded', int(release_gil))
61 
62 
63 def set_ownership_policy(match_class, match_method, python_owns_result):
64  return set_method_property(match_class, match_method,
65  '_creates', int(python_owns_result))
66 
67 def set_smart_ptr_policy(match_class, match_method, manage_smart_ptr=False):
68  return set_method_property(match_class, match_method,
69  '_manage_smart_ptr', bool(manage_smart_ptr))
70 
71 
72 # NB: Ideally, we'd use the version commented out below, but for now, we
73 # make do with the hackier version here.
74 def rename_attribute(match_class, orig_attribute, new_attribute, keep_orig=False):
75  class attribute_pythonizor(object):
76  class getter(object):
77  def __init__(self, attr):
78  self.attr = attr
79  def __call__(self, obj):
80  return getattr(obj, self.attr)
81 
82  class setter(object):
83  def __init__(self, attr):
84  self.attr = attr
85  def __call__(self, obj, value):
86  return setattr(obj, self.attr, value)
87 
88  class deleter(object):
89  def __init__(self, attr):
90  self.attr = attr
91  def __call__(self, obj):
92  return delattr(obj, self.attr)
93 
94  def __init__(self, match_class, orig_attribute, new_attribute, keep_orig):
95  import re
96  self.match_class = re.compile(match_class)
97  self.match_attr = re.compile(orig_attribute)
98  self.new_attr = new_attribute
99  self.keep_orig = keep_orig
100 
101  def __call__(self, obj, name):
102  if not self.match_class.match(name):
103  return
104  for k in dir(obj): #.__dict__:
105  if self.match_attr.match(k):
106  tmp = property(self.getter(k), self.setter(k), self.deleter(k))
107  setattr(obj, self.new_attr, tmp)
108  #if not self.keep_orig: delattr(obj, k)
109  return attribute_pythonizor(match_class, orig_attribute, new_attribute, keep_orig)
110 
111 # def rename_attribute(match_class, orig_attribute, new_attribute, keep_orig=False):
112 # class method_pythonizor:
113 # def __init__(self, match_class, orig_attribute, new_attribute, keep_orig):
114 # import re
115 # self.match_class = re.compile(match_class)
116 # self.match_attr = re.compile(orig_attribute)
117 # self.new_attr = new_attribute
118 # self.keep_orig = keep_orig
119 
120 # def __call__(self, obj, name):
121 # import sys
122 # if not self.match_class.match(name):
123 # return
124 # sys.stderr.write("%s %s %s %s" % ("!!!", obj, name, "\n"))
125 # for k in dir(obj): #obj.__dict__:
126 # if not self.match_attr.match(k): continue
127 # try:
128 # tmp = getattr(obj, k)
129 # except Exception as e:
130 # continue
131 # setattr(obj, self.new_attr, tmp)
132 # if not self.keep_orig: delattr(obj, k)
133 # return method_pythonizor(match_class, orig_attribute, new_attribute, keep_orig)
134 
135 
136 # Shared with PyPy:
137 
138 def add_overload(match_class, match_method, overload):
139  class method_pythonizor(object):
140  def __init__(self, match_class, match_method, overload):
141  import re
142  self.match_class = re.compile(match_class)
143  self.match_method = re.compile(match_method)
144  self.overload = overload
145 
146  def __call__(self, obj, name):
147  if not self.match_class.match(name):
148  return
149  for k in dir(obj): #.__dict__:
150  try:
151  tmp = getattr(obj, k)
152  except:
153  continue
154  if self.match_method.match(k):
155  try:
156  tmp.__add_overload__(overload)
157  except AttributeError: pass
158  return method_pythonizor(match_class, match_method, overload)
159 
160 
161 def compose_method(match_class, match_method, g):
162  class composition_pythonizor(object):
163  def __init__(self, match_class, match_method, g):
164  import re
165  self.match_class = re.compile(match_class)
166  self.match_method = re.compile(match_method)
167  self.g = g
168 
169  def __call__(self, obj, name):
170  if not self.match_class.match(name):
171  return
172  g = self.g
173  for k in dir(obj): #.__dict__:
174  if not self.match_method.match(k):
175  continue
176  try:
177  f = getattr(obj, k)
178  except:
179  continue
180  def h(self, *args, **kwargs):
181  return g(self, f(self, *args, **kwargs))
182  setattr(obj, k, h)
183  return composition_pythonizor(match_class, match_method, g)
184 
185 
186 def set_method_property(match_class, match_method, prop, value):
187  class method_pythonizor(object):
188  def __init__(self, match_class, match_method, prop, value):
189  import re
190  self.match_class = re.compile(match_class)
191  self.match_method = re.compile(match_method)
192  self.prop = prop
193  self.value = value
194 
195  def __call__(self, obj, name):
196  if not self.match_class.match(name):
197  return
198  for k in dir(obj): #.__dict__:
199  try:
200  tmp = getattr(obj, k)
201  except:
202  continue
203  if self.match_method.match(k):
204  setattr(tmp, self.prop, self.value)
205  return method_pythonizor(match_class, match_method, prop, value)
206 
207 
208 def make_property(match_class, match_get, match_set=None, match_del=None, prop_name=None):
209  class property_pythonizor(object):
210  def __init__(self, match_class, match_get, match_set, match_del, prop_name):
211  import re
212  self.match_class = re.compile(match_class)
213 
214  self.match_get = re.compile(match_get)
215  match_many_getters = self.match_get.groups == 1
216 
217  if match_set:
218  self.match_set = re.compile(match_set)
219  match_many_setters = self.match_set.groups == 1
220  if match_many_getters ^ match_many_setters:
221  raise ValueError('Must match getters and setters equally')
222  else:
223  self.match_set = None
224 
225  if match_del:
226  self.match_del = re.compile(match_del)
227  match_many_deleters = self.match_del.groups == 1
228  if match_many_getters ^ match_many_deleters:
229  raise ValueError('Must match getters and deleters equally')
230  else:
231  self.match_del = None
232 
233  self.match_many = match_many_getters
234  if not (self.match_many or prop_name):
235  raise ValueError("If not matching properties by regex, need a property name with exactly one substitution field")
236  if self.match_many and prop_name:
237  if prop_name.format(').!:(') == prop_name:
238  raise ValueError("If matching properties by regex and providing a property name, the name needs exactly one substitution field")
239 
240  self.prop_name = prop_name
241 
242  def make_get_del_proxy(self, getter):
243  class proxy(object):
244  def __init__(self, getter):
245  self.getter = getter
246 
247  def __call__(self, obj):
248  return getattr(obj, self.getter)()
249  return proxy(getter)
250 
251  def make_set_proxy(self, setter):
252  class proxy(object):
253  def __init__(self, setter):
254  self.setter = setter
255 
256  def __call__(self, obj, arg):
257  return getattr(obj, self.setter)(arg)
258  return proxy(setter)
259 
260  def __call__(self, obj, name):
261  if not self.match_class.match(name):
262  return
263 
264  names = []
265  named_getters = {}
266  named_setters = {}
267  named_deleters = {}
268 
269  if not self.match_many:
270  fget, fset, fdel = None, None, None
271 
272  for k in dir(obj): #.__dict__:
273  match = self.match_get.match(k)
274  try:
275  tmp = getattr(obj, k)
276  except:
277  continue
278  if match and hasattr(tmp, '__call__'):
279  if self.match_many:
280  name = match.group(1)
281  named_getters[name] = k
282  else:
283  fget = self.make_get_del_proxy(k)
284  break
285 
286  if self.match_set:
287  for k in dir(obj): #.__dict__:
288  match = self.match_set.match(k)
289  try:
290  tmp = getattr(obj, k)
291  except:
292  continue
293  if match and hasattr(tmp, '__call__'):
294  if self.match_many:
295  name = match.group(1)
296  named_setters[name] = k
297  else:
298  fset = self.make_set_proxy(k)
299  break
300 
301  if self.match_del:
302  for k in dir(obj): #.__dict__:
303  match = self.match_del.match(k)
304  try:
305  tmp = getattr(obj, k)
306  except:
307  continue
308  if match and hasattr(tmp, '__call__'):
309  if self.match_many:
310  name = match.group(1)
311  named_deleters[name] = k
312  else:
313  fdel = self.make_get_del_proxy(k)
314  break
315 
316  if not self.match_many:
317  new_prop = property(fget, fset, fdel)
318  setattr(obj, self.prop_name, new_prop)
319  return
320 
321  names += list(named_getters.keys())
322  names += list(named_setters.keys())
323  names += list(named_deleters.keys())
324  names = set(names)
325 
326  properties = []
327  for name in names:
328  if name in named_getters:
329  fget = self.make_get_del_proxy(named_getters[name])
330  else:
331  fget = None
332 
333  if name in named_setters:
334  fset = self.make_set_proxy(named_setters[name])
335  else:
336  fset = None
337 
338  if name in named_deleters:
339  fdel = self.make_get_del_proxy(named_deleters[name])
340  else:
341  fdel = None
342 
343  new_prop = property(fget, fset, fdel)
344  if self.prop_name:
345  prop_name = self.prop_name.format(name)
346  else:
347  prop_name = name
348 
349  setattr(obj, prop_name, new_prop)
350 
351  return property_pythonizor(match_class, match_get, match_set, match_del, prop_name)
352 
def add_pythonization(pythonizor)
TH1 * h
Definition: legend2.C:5
def add_exception_mapping(cpp_exception, py_exception)
def set_pythonization_scope(scope)
def make_interface(base_type)
def set_method_property(match_class, match_method, prop, value)
def cast(some_object, new_type)
def _set_backend(backend)
def compose_method(match_class, match_method, g)
def add_overload(match_class, match_method, overload)
def set_ownership_policy(match_class, match_method, python_owns_result)
double f(double x)
def ignore_type_pinning(some_type)
def pin_type(derived_type, base_type)