Skip to content

Commit 86cda43

Browse files
committed
[pyroot] Fix and speed up the used-class scan in _find_used_classes
`_find_used_classes()` called `str()` on every variable of the target namespace to detect class proxies by their string prefix. For a namespace like `cppyy.gbl` that may also hold bound C++ *instances* (e.g. `gInterpreter), `str()` of an instance triggers C++ overload resolution for `operator<<`, which may attempt candidate implicit conversions via JIT-compiled constructor calls. This is expensive and we want to avoid it. More importantly, if the JIT compilation fails, it results is unexpected hard-to-debug errors. Skip bound instances entirely and only stringify actual types for the class-proxy check. This is also a general speedup of pythonization registration on all platforms. The loop is restructured into mutually exclusive if/elif branches, one per kind of value (class proxy, bound instance, template proxy). Template proxies keep being recognized by their repr: they are not Python types and cannot be reliably detected with isinstance, since `cppyy.types.Template` is the backend proxy class, which the `cppyy.Template` wrapper does not derive from.
1 parent b6f8d4d commit 86cda43

1 file changed

Lines changed: 20 additions & 8 deletions

File tree

  • bindings/pyroot/pythonizations/python/ROOT/_pythonization

bindings/pyroot/pythonizations/python/ROOT/_pythonization/__init__.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,16 +272,28 @@ def get_class_name(instantiation):
272272
f"The template instantiation '{instantiation}' cannot be properly pythonized. Please report this as a bug."
273273
)
274274

275+
import cppyy.types
276+
275277
ns_vars = vars(ns_obj)
276278
for var_name, var_value in ns_vars.items():
277-
if str(var_value).startswith("<class cppyy.gbl.") and not hasattr(var_value, "__cpp_template__"):
278-
# It's a class proxy. Exclude template instantiations, because they
279-
# will be traversed in the next step.
280-
pythonize_if_match(var_name, var_value)
281-
282-
if str(var_value).startswith("<cppyy.Template"):
283-
# If this is a template, pythonize the instances. Note that in
284-
# older cppyy, template instantiations are cached by
279+
if isinstance(var_value, type):
280+
if str(var_value).startswith("<class cppyy.gbl.") and not hasattr(var_value, "__cpp_template__"):
281+
# It's a class proxy (possibly a template instantiation cached
282+
# in the namespace).
283+
pythonize_if_match(var_name, var_value)
284+
elif isinstance(var_value, cppyy.types.Instance):
285+
# Never call str() on a bound C++ *instance* (e.g. cppyy.gbl holds
286+
# the gInterpreter instance): its string conversion triggers C++
287+
# overload resolution for operator<<, which can JIT-compile
288+
# candidate implicit conversions.
289+
continue
290+
elif str(var_value).startswith("<cppyy.Template"):
291+
# Template proxies are not Python types and cannot be reliably
292+
# detected with isinstance (cppyy.types.Template is the backend
293+
# proxy class, which the cppyy.Template wrapper does not derive
294+
# from), so they are recognized by their repr instead.
295+
# Pythonize the cached instantiations of the template. Note that
296+
# in older cppyy, template instantiations are cached by
285297
# fully-qualified name directly in the namespace, so they are
286298
# covered by the code branch above.
287299
instantiations = getattr(var_value, "_instantiations", {})

0 commit comments

Comments
 (0)