Access std.map( str, MyClass )

Dear PyROOTers,

I am having troubles to access STL containers in PyROOT. The task is to get certain pieces of legacy code accessible in Python, using PyROOT (I also looked into SWIG and BoostPython, but PyROOT seems to be incredibly flexible).

Currently I am trying to get my head around how to deal with STL maps as return values. The C++ code looks like this:

class Legacy
{
public:

    struct MyClass
    {
        char type;
        std::string value;
        std::string comment;

        template<typename T>
            T Get() const
        {
            T t;
            std::istringstream str(value);
            str >> t;
            return t;
        }
    };
    
    std::map<std::string, MyClass> map;
    
    Legacy( const char* filename)
    {
        // opens the file and fills the map...
    }
    
    const std::map<std::string, MyClass>& GetMap() const
    {
        return map;
    }

}

In Python, I do mostly this:

>>> from ROOT import gSystem
>>> gSystem.Load('legacy_h.so')
>>> from ROOT import *
>>> l = Lecacy("some file name")
>>> m = l.GetMap()
>>> m
<ROOT.map<string,Legacy::MyClass> object at 0x...>
>>> len(m)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'map<string,Legacy::MyClass,less<string>,allocator<pair<const string,Legacy::MyClass> > >' has no len()
>>> for thing in m:
...   print m
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'map<string,Legacy::MyClass,less<string>,allocator<pair<const string,Legacy::MyClass> > >' object is not iterable

Creating and Accessing STL maps of simple types works

>>> import ROOT
>>> m = ROOT.std.map(str,int)()
>>> m['test1'] = 1
>>> m['test2'] = 2
>>> len(m)
2
>>> for i in m:
...   print i.first, i.second
... 
test1 1
test2 2

The next thing I tested was, what happens If I create a ROOT.std.map(str, Legacy.MyClass) manually instead of using the return value, with the same result. For completeness I did:

>>> import ROOT
>>> ROOT.gSystem.Load("legacy_h.so")
>>> from ROOT import Legacy
>>> m = ROOT.std.map(str, Legacy.MyClass)()
[...took some seconds...]
>>> len(m)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'map<string,Legacy::MyClass,less<string>,allocator<pair<const string,Legacy::MyClass> > >' has no len()

Some AutoDict files were created, I assume during the “m = ROOT.std.map(str, Legacy.MyClass)()” step. They look like:
AutoDict_allocator_pair_const_string_Legacy__MyClass___.cxx

#include "vector"
#include "string"
#include "legacy.h"
#ifdef __CINT__ 
#pragma link C++ nestedclasses;
#pragma link C++ nestedtypedefs;
#pragma link C++ class allocator<pair<const string,Legacy::MyClass> >+;
#pragma link C++ class allocator<pair<const string,Legacy::MyClass> >::*+;
#endif

AutoDict_pair_const_string_Legacy__MyClass_.cxx

#include "vector"
#include "string"
#include "legacy.h"
#ifdef __CINT__ 
#pragma link C++ nestedclasses;
#pragma link C++ nestedtypedefs;
#pragma link C++ class pair<const string,Legacy::MyClass>+;
#pragma link C++ class pair<const string,Legacy::MyClass>::*+;
#endif

I wonder If I have to generate some dictionaries myself, before working with these maps(str, Legacy.MyClass) or if the AutoDicts, which are made are actually enough.

Thanks you for your time.

I figured it out :smiley: I had to create Dictionaries before I tried to work with these maps.

This post helped me a lot.

So what I do now, is this:

import ROOT
ROOT.gROOT.ProcessLine(".L legacy.h+O")
ROOT.gInterpreter.GenerateDictionary("map<string,MyClass>","map;string;legacy.h")
ROOT.gSystem.Load("legacy_h.so")

Again some AutoDict files are generated of course, they look equal to the ones that were created, when I tried to create a map with

m = ROOT.std.map(str, ROOT.Legacy.MyClass)()

but this time it works. I guess the order matters a lot.

I still feel not quite sure what I am doing here and wonder if there is any good book/manual about this matter. So in case you know anything please let me know.
Thank you for your time.

Hi,

yes, that’s pretty much it. Perhaps some more details here.

Cheers,
Wim