20gbl_namespace = cppyy.gbl
23from ._generic
import pythonize_generic
28 \ingroup Pythonizations
29 Decorator that allows to pythonize C++ classes. To pythonize means to add
30 some extra behaviour to a C++ class that is used from Python via PyROOT,
31 so that such a class can be used in an easier / more "pythonic" way.
32 When a pythonization is registered with this decorator, the injection of
33 the new behaviour in the C++ class is done immediately, if the class has
34 already been used from the application, or lazily, i.e. only when the class
35 is first accessed from the application.
38 class_name (string/iterable[string]): specifies either a single string or
39 multiple strings, where each string can be either (i) the name of a
40 C++ class to be pythonized, or (ii) a prefix to match all classes
41 whose name starts with that prefix.
42 ns (string): namespace of the classes to be pythonized. Default is the
43 global namespace (`::`).
44 is_prefix (boolean): if True, `class_name` contains one or multiple
45 prefixes, each prefix potentially matching multiple classes.
47 These are examples of prefixes and namespace and what they match:
48 - class_name="", ns="::" : all classes in the global namespace.
49 - class_name="C", ns="::" : all classes in the global namespace
50 whose name starts with "C"
51 - class_name="", ns="NS1::NS2" : all classes in namespace "NS1::NS2"
52 - class_name="C", ns="NS1::NS2" : all classes in namespace
53 "NS1::NS2" whose name starts with "C"
56 function: function that receives the user-defined function and
64 target = _check_target(class_name)
72 def passes_filter(class_name):
73 return any(class_name.startswith(prefix)
76 def passes_filter(class_name):
77 return class_name
in target
79 def pythonization_impl(user_pythonizor):
81 The real decorator. Accepts a user-provided function and decorates it.
82 An inner function - a wrapper of the user function - is registered in
83 cppyy as a pythonizor.
86 user_pythonizor (function): user-provided function to be decorated.
87 It implements some pythonization. It can accept two parameters:
88 the class to be pythonized, i.e. the Python proxy of the class
89 in which new behaviour can be injected, and optionally the name
90 of that class (can be used e.g. to do some more complex
94 function: the user function, after being registered as a
98 npars = _check_num_pars(user_pythonizor)
103 _find_used_classes(ns, passes_filter, user_pythonizor, npars)
105 def cppyy_pythonizor(klass, name):
107 Wrapper function with the parameters that cppyy requires for a
108 pythonizor function (class proxy and class name). It invokes the
109 user function only if the current class - a candidate for being
110 pythonized - matches the `target` argument of the decorator.
113 klass (class type): cppyy proxy of the class that is the
114 current candidate to be pythonized.
115 name (string): name of the class that is the current candidate
119 fqn = klass.__cpp_name__
122 pythonize_generic(klass, fqn)
124 if passes_filter(name):
125 _invoke(user_pythonizor, npars, klass, fqn)
128 cppyy.py.add_pythonization(cppyy_pythonizor, ns)
135 return user_pythonizor
137 return pythonization_impl
141def _check_target(target):
143 Helper function to check the type of the `class name` argument specified by
144 the user in a @pythonization decorator.
147 target (string/iterable[string]): class name(s)/prefix(es).
150 list[string]: class name(s)/prefix(es) in `target`, with no repetitions.
153 if isinstance(target, str):
154 _check_no_namespace(target)
158 if isinstance(name, str):
159 _check_no_namespace(name)
161 raise TypeError(
'Invalid type of "target" argument in '
162 '@pythonization: must be string or iterable of '
165 target = list(set(target))
169def _check_no_namespace(target):
171 Checks that a given target of a pythonizor does not specify a namespace
172 (only the class name / prefix of a class name should be present).
175 target (string): class name/prefix.
178 if target.find(
'::') >= 0:
179 raise ValueError(
'Invalid value of "class_name" argument in '
180 '@pythonization: namespace definition found ("{}"). '
181 'Please use the "ns" parameter to specify the '
182 'namespace'.
format(target))
184def _check_num_pars(f):
186 Checks the number of parameters of the `f` function.
189 f (function): user pythonizor function.
192 int: number of positional parameters of `f`.
194 npars =
len(inspect.getfullargspec(f).args)
195 if npars == 0
or npars > 2:
196 raise TypeError(
'Pythonizor function {} has a wrong number of '
197 'parameters ({}). Allowed parameters are the class to '
198 'be pythonized and (optionally) its name.'
199 .
format(f.__name__, npars))
203def _invoke(user_pythonizor, npars, klass, fqn):
205 Invokes the given user pythonizor function with the right arguments.
208 user_pythonizor (function): user pythonizor function.
209 npars (int): number of parameters of the user pythonizor function.
210 klass (class type): cppyy proxy of the class to be pythonized.
211 fqn (string): fully-qualified name of the class to be pythonized.
216 user_pythonizor(klass)
218 user_pythonizor(klass, fqn)
219 except Exception
as e:
220 print(
'Error pythonizing class {}:'.
format(fqn))
221 traceback.print_exc()
226def _find_used_classes(ns, passes_filter, user_pythonizor, npars):
228 Finds already instantiated classes in namespace `ns` that pass the filter
229 of `passes_filter`. Every matching class is pythonized with the
230 `user_pythonizor` function.
231 This makes sure a pythonizor is also applied to classes that have already
232 been used at the time the pythonizor is registered.
235 ns (string): namespace of the class names of prefixes in `targets`.
236 passes_filter (function): function that determines if a given class
237 is the target of `user_pythonizor`.
238 user_pythonizor (function): user pythonizor function.
239 npars (int): number of parameters of the user pythonizor function.
242 ns_obj = _find_namespace(ns)
247 def pythonize_if_match(name, klass):
249 if passes_filter(name.split(
"::")[-1]):
251 _invoke(user_pythonizor, npars, klass, klass.__cpp_name__)
253 ns_vars = vars(ns_obj)
254 for var_name, var_value
in ns_vars.items():
255 if str(var_value).startswith(
'<class cppyy.gbl.'):
257 pythonize_if_match(var_name, var_value)
259 if str(var_value).startswith(
'<cppyy.Template'):
264 instantiations = getattr(var_value,
"_instantiations", {})
265 for args, instance
in instantiations.items():
269 if not instance
in ns_vars:
270 instance_name = var_name +
"<" +
",".join(args) +
">"
271 pythonize_if_match(instance_name, instance)
273def _find_namespace(ns):
275 Finds and returns the proxy object of the `ns` namespace, if it has already
279 ns (string): a namespace.
282 namespace proxy object, if the namespace has already been accessed,
289 ns_obj = gbl_namespace
291 every_ns = ns.split(
'::')
293 ns_vars = vars(ns_obj)
294 if not ns
in ns_vars:
296 ns_obj = getattr(ns_obj, ns)
300def _register_pythonizations():
302 Registers the ROOT pythonizations with cppyy for lazy injection.
305 exclude = [
'_rdf_utils',
'_rdf_pyz',
'_rdf_conversion_maps' ]
306 for _, module_name, _
in pkgutil.walk_packages(__path__):
307 if module_name
not in exclude:
308 importlib.import_module(__name__ +
'.' + module_name)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t format
pythonization(class_name, ns='::', is_prefix=False)
Decorator that allows to pythonize C++ classes.