wlav / cppyy

Other
405 stars 42 forks source link

Possible to get a list of enum names from a header file? #180

Closed smahm006 closed 1 year ago

smahm006 commented 1 year ago

Greetings,

First of thank you so much for this package. I have a c++ header file which has about 30 or so enums declared in it, and instead of importing all 30 manually I'd like to import all the enums dynamically and save them to a variable.

The problem is that I cannot seem to find the name of the enums to import from cppyy, I have tried something like below but unfortunately the class names are only of the type such as uint8_t or int8_t.

import cppyy
cppyy.include("enums.h")

classes = cppyy.gbl.__dict__
for class_name, class_obj in classes.items():
    if isinstance(class_obj, type) and issubclass(class_obj, int):
        print(class_name)

I was wondering if it was possible to get the names of all the enums in a header file so I can dynamically import them.

wlav commented 1 year ago

Not really sure that I understand the question ... a "header file" isn't a coherent unit as seen by the compiler (certainly not something that persists). Would if they all live in the same namespace, though. Otherwise, any such approach simply identifies all enums seen so far, including ones you may not be interested in.

Specific to the given code, __dict__ is just a place to cache results that have been found. The way to browse contents of a scope would be to use dir(), ie. dir(cppyy.gbl) and then use getattr. However, enums could be anonymous, in which case they won't appear as a type at all in dir() (nor, eventually, __dict__), only their values; or they could be different types, in which case they need not derive from int.

smahm006 commented 1 year ago

When I try to read dir(cppyy.gbl) the enums don't show up in the list. Only if I manually call from cppyy.gbl import Enum1, Enum2 then they show up.

But I would like to avoid calling 30 imports for the 30 enums that exist in my file. The enums in my file are not anonymous and each have a specific name like Enum1, Enum2, etc....

wlav commented 1 year ago

Can you post the file so that I can reproduce? A basic enum.h like so:

enum A { a, b };

shows that enum just fine:

>>> import cppyy
>>> cppyy.include("enum.h")
True
>>> dir(cppyy.gbl)
['A', ...
>>>
smahm006 commented 1 year ago

I cannot post the full file but here is a portion to give you an idea. There are about 30 or so enums in the file and all have the same syntax as below, just different names and values:

enum DebugTypeEnum {
  DebugTypeEnum_UnknownDebugType = 0,
  DebugTypeEnum_LOG_EMERG = 1,
  DebugTypeEnum_LOG_ALERT = 2,
  DebugTypeEnum_LOG_CRIT = 3,
  DebugTypeEnum_LOG_ERR = 4,
  DebugTypeEnum_LOG_WARNING = 5,
  DebugTypeEnum_LOG_NOTICE = 6,
  DebugTypeEnum_LOG_INFO = 7,
  DebugTypeEnum_LOG_DEBUG = 8,
  DebugTypeEnum_LOG_DEVICE = 9,
  DebugTypeEnum_MIN = DebugTypeEnum_UnknownDebugType,
  DebugTypeEnum_MAX = DebugTypeEnum_LOG_DEVICE
};

inline const DebugTypeEnum (&EnumValuesDebugTypeEnum())[10] {
  static const DebugTypeEnum values[] = {
    DebugTypeEnum_UnknownDebugType,
    DebugTypeEnum_LOG_EMERG,
    DebugTypeEnum_LOG_ALERT,
    DebugTypeEnum_LOG_CRIT,
    DebugTypeEnum_LOG_ERR,
    DebugTypeEnum_LOG_WARNING,
    DebugTypeEnum_LOG_NOTICE,
    DebugTypeEnum_LOG_INFO,
    DebugTypeEnum_LOG_DEBUG,
    DebugTypeEnum_LOG_DEVICE
  };
  return values;
}

inline const char * const *EnumNamesDebugTypeEnum() {
  static const char * const names[] = {
    "UnknownDebugType",
    "LOG_EMERG",
    "LOG_ALERT",
    "LOG_CRIT",
    "LOG_ERR",
    "LOG_WARNING",
    "LOG_NOTICE",
    "LOG_INFO",
    "LOG_DEBUG",
    "LOG_DEVICE",
    nullptr
  };
  return names;
}

inline const char *EnumNameDebugTypeEnum(DebugTypeEnum e) {
  if (e < DebugTypeEnum_UnknownDebugType || e > DebugTypeEnum_LOG_DEVICE) return "";
  const size_t index = static_cast<size_t>(e);
  return EnumNamesDebugTypeEnum()[index];
}
wlav commented 1 year ago

It does show up for me:

>>> dir(cppyy.gbl)
['CppyyLegacy', 'DebugTypeEnum', ...
>>> dir(cppyy.gbl.DebugTypeEnum)
['DebugTypeEnum_LOG_ALERT', 'DebugTypeEnum_LOG_CRIT', ...

If it doesn't give you the same result, what version/platform are we speaking here?

smahm006 commented 1 year ago
cppyy==3.0.0
cppyy-backend==1.14.11
cppyy-cling==6.28.0

But I don't think it has to do with the version. The C++ project I am dealing with is quite large and I have many other include paths involved besides just the enums.h file.

smahm006 commented 1 year ago

Closed by mistake, Here is my dir output...

>>> import cppyy
>>> cppyy.include("path_to_folder/enums.h")
True
>>> dir(cppyy.gbl)
['CppyyLegacy', '__add__', '__bool__', '__class__', '__delattr__', '__destruct__', '__dict__', '__dir__', '__dispatch__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__invert__', '__le__', '__lt__', '__module__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__python_owns__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__reshape__', '__rmul__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__smartptr__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__weakref__', 'int8_t', 'std', 'uint8_t']
smahm006 commented 1 year ago

Interesting, so I created my own local test-enums.h with a single enum and that showed up in dir. So then I made a copy of my enums.h and moved it over to my python project repository, but dir() of that local enums.h is not showing the enums still...

Is there a limit to what dir() can show? Maybe there are too many enums for it to show?

smahm006 commented 1 year ago

AHHHH I am such an idiot, the enums are all under a namespace. If I import the namespace then all the enums show up.

Man thank you so much for the help @wlav and thank you again for this package.