PyROOT: Creating custom converter for C++ type

Hi all,

How would I go about creating a custom converter for a C++ type to use in PyROOT?

I have a set of classes that use the nlohmann::json class for passing around configuration information. Now, obviously when I try and use methods on these classes that interact with nlohmann::json PyROOT isn’t particularly happy because it doesn’t know about the class and spits out a warning+error combo

__main__:1: RuntimeWarning: creating converter for unknown type "const nlohmann::basic_json<map,vector,string,bool,long,unsigned long,double,allocator,adl_serializer>&"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: void RDFPlotting::TConfigurable::configure(const nlohmann::basic_json<map,vector,string,bool,long,unsigned long,double,allocator,adl_serializer>& configuration) =>
    could not convert argument 1

Would it be possible for me to write a converter (or whatever would be needed) to convert between a python dict and a C++ nlohmann::json object? Ideally this would work two ways - when a C++ method returns nlohmann::json this would become a dict in PyROOT and when one receives a nlohmann::json it would be provided as a dict in PyROOT.

Cheers,
Jon


ROOT Version: 6.14/04
Platform: Not Provided
Compiler: gcc 5.4.0


@etejedor perhaps you can help here?

Thank you,
Oksana

Hi Jon,

Instead of writing a converter, what you can do is pythonize your cpp type and make it act as a dictionary in python. This basically means injecting to your ROOT.nlohmann.json class, from Python, some behaviour:

https://docs.python.org/3/reference/datamodel.html?emulating-container-types#emulating-container-types

For example, you would do:

ROOT.nlohmann.json.__len__ = your_function_to_get_len_of_lohmannjson

The downside of this is that it only works one way: you can operate with your nlohmann.json as dictionaries from Python, but you can’t pass dictionaries to C++ functions that expect a nlohmann.json object.

On the other hand, adding custom converters to PyROOT is not something that is exposed as a public API. In order to add them, you would need to modify Converters.cxx to add your new converter. If you want to go that way, I can point you to an example:

Starting from that line, a conversion between a Python tuple type and a C++ type is added. Thanks to that code, one can pass Python tuples as C++ initializer lists and the tuple elements will be decomposed to feed the constructor of the target C++ class.

Cheers,
Enric

Hi Enric,

OK, I kind of anticipated that this might be tricky :stuck_out_tongue:.
Needing to modify something inside ROOT itself doesn’t feel particularly portable so I’ll avoid that (this isn’t a showstopper for my code, there are plenty of workarounds).
For pythonizing the code - is there a way to get these functions to be loaded automatically into a pyroot session?

Cheers,
Jon

Hi @burrjona

For your pythonizations to be effective, you will need to call a function of yours that does the injections on the nlohmann.json class at the beginning of your script.

We are working on a new version of PyROOT that will allow you to do the same in an easier way. The basic idea will be to define your “pythonizor functions” like this:

@pythonize('MyCppClass'):
def user_pythonizor_function(class_to_pythonize):
   class_to_pyhonize.__len__ = ...

and the pythonization will happen lazily, only when you use the class from your Python script.

But for the moment you will need to use the first solution I mentioned and pythonize explicitly at the beginning of your script.

Cheers,

Enric

Hi Enric,

OK - it’s not a huge imposition to ask users to import a python file at the beginning of their scripts/sessions anyway I suppose :slight_smile:.

Cheers,
Jon

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.