@@ -24,19 +24,55 @@ inline std::string getline(const std::string& fileName)
2424 return line;
2525}
2626
27- inline std::string findClassName (const std::string& fileName)
28- {
29- std::string line;
30- std::ifstream infile (fileName);
31- std::string regexStr (R"( ^class (\w+)\(\s*Fmi3Slave\s*\)\s*:)" );
32- while (getline (infile, line)) {
33- std::smatch m;
34- std::regex re (regexStr);
35- if (std::regex_search (line, m, re)) {
36- return m[1 ];
27+ std::string getClassName (PyObject * pModule)
28+ {
29+ std::string className = " " ;
30+ PyObject* dict = PyModule_GetDict (pModule);
31+ PyObject* keys = PyDict_Keys (dict);
32+ // Iterate through the dictionary keys to find classes derived from Fmi3Slave
33+ for (int i = 0 ; i < PyList_Size (keys); i++) {
34+ PyObject* key = PyList_GetItem (keys, i);
35+ if (PyUnicode_Check (key)) {
36+ PyObject* utf8Str = PyUnicode_AsEncodedString (key, " utf-8" , nullptr );
37+ if (utf8Str == nullptr ) {
38+ return " " ;
39+ }
40+ std::string classNameCandidate = PyBytes_AsString (utf8Str);
41+ Py_DECREF (utf8Str);
42+
43+ // Check if the class is a subclass of Fmi3Slave
44+ PyObject* obj = PyDict_GetItem (dict, key);
45+ if (PyObject_HasAttrString (obj, " __bases__" )) {
46+ PyObject* bases = PyObject_GetAttrString (obj, " __bases__" );
47+ if (PyTuple_Check (bases)) {
48+ for (int j = 0 ; j < PyTuple_Size (bases); j++) {
49+ PyObject* base = PyTuple_GetItem (bases, j);
50+ PyObject* baseNameObj = PyObject_GetAttrString (base, " __name__" );
51+ if (baseNameObj && PyUnicode_Check (baseNameObj)) {
52+ PyObject* baseUtf8Str = PyUnicode_AsEncodedString (baseNameObj, " utf-8" , nullptr );
53+ if (baseUtf8Str != nullptr ) {
54+ std::string baseName = PyBytes_AsString (baseUtf8Str);
55+ Py_DECREF (baseUtf8Str);
56+ if (baseName == " Fmi3Slave" ) {
57+ className = classNameCandidate;
58+ Py_DECREF (baseNameObj);
59+ Py_DECREF (bases);
60+ break ;
61+ }
62+ }
63+ Py_DECREF (baseNameObj);
64+ }
65+ }
66+ }
67+ Py_DECREF (bases);
68+ }
69+
70+ if (!className.empty ()) {
71+ break ; // Break after finding the first subclass
72+ }
3773 }
3874 }
39- return " " ;
75+ return className ;
4076}
4177
4278inline void py_safe_run (const std::function<void (PyGILState_STATE gilState)>& f)
@@ -77,7 +113,7 @@ PySlaveInstance::PySlaveInstance(std::string instanceName, std::string resources
77113 handle_py_exception (" [ctor] PyImport_ImportModule" , gilState);
78114 }
79115
80- std::string className = findClassName (resources_ + " / " + moduleName + " .py " );
116+ std::string className = getClassName (pModule );
81117 if (className.empty ()) {
82118 cleanPyObject ();
83119 throw cppfmu::FatalError (" Unable to find class extending Fmi3Slave!" );
0 commit comments