def make_pycppclass(scope, class_name, final_class_name, cppclass): # get a list of base classes for class creation bases = [get_pycppclass(base) for base in cppclass.get_base_names()] if not bases: bases = [CppyyClass,] else: # it's technically possible that the required class now has been built # if one of the base classes uses it in e.g. a function interface try: return scope.__dict__[final_class_name] except KeyError: pass # create a meta class to allow properties (for static data write access) metabases = [type(base) for base in bases] metacpp = type(CppyyClassMeta)(class_name+'_meta', _drop_cycles(metabases), {}) # create the python-side C++ class representation def dispatch(self, name, signature): cppol = cppclass.dispatch(name, signature) return types.MethodType(make_method(name, cppol), self, type(self)) d = {"_cpp_proxy" : cppclass, "__dispatch__" : dispatch, "__new__" : make_new(class_name, cppclass), } pycppclass = metacpp(class_name, _drop_cycles(bases), d) # cache result early so that the class methods can find the class itself setattr(scope, final_class_name, pycppclass) # insert (static) methods into the class dictionary for meth_name in cppclass.get_method_names(): cppol = cppclass.get_overload(meth_name) if cppol.is_static(): setattr(pycppclass, meth_name, make_static_function(meth_name, cppol)) else: setattr(pycppclass, meth_name, make_method(meth_name, cppol)) # add all data members to the dictionary of the class to be created, and # static ones also to the meta class (needed for property setters) for dm_name in cppclass.get_datamember_names(): cppdm = cppclass.get_datamember(dm_name) # here, setattr() can not be used, because a data member can shadow one in # its base class, resulting in the __set__() of its base class being called # by setattr(); so, store directly on the dictionary pycppclass.__dict__[dm_name] = cppdm import cppyy if cppyy._is_static(cppdm): # TODO: make this a method of cppdm metacpp.__dict__[dm_name] = cppdm # the call to register will add back-end specific pythonizations and thus # needs to run first, so that the generic pythonizations can use them import cppyy cppyy._register_class(pycppclass) _pythonize(pycppclass) return pycppclass
def make_pycppclass(scope, class_name, final_class_name, cppclass): # get a list of base classes for class creation bases = [get_pycppclass(base) for base in cppclass.get_base_names()] if not bases: bases = [CPPInstance,] else: # it's technically possible that the required class now has been built # if one of the base classes uses it in e.g. a function interface try: return scope.__dict__[final_class_name] except KeyError: pass # create a meta class to allow properties (for static data write access) metabases = [type(base) for base in bases] metacpp = type(CPPClass)(class_name+'_meta', _drop_cycles(metabases), {}) # create the python-side C++ class representation def dispatch(self, name, signature): cppol = cppclass.dispatch(name, signature) return types.MethodType(make_method(name, cppol), self, type(self)) d = {"_cpp_proxy" : cppclass, "__dispatch__" : dispatch, "__new__" : make_new(class_name), } pycppclass = metacpp(class_name, _drop_cycles(bases), d) # cache result early so that the class methods can find the class itself setattr(scope, final_class_name, pycppclass) # insert (static) methods into the class dictionary for meth_name in cppclass.get_method_names(): cppol = cppclass.get_overload(meth_name) if cppol.is_static(): setattr(pycppclass, meth_name, make_static_function(meth_name, cppol)) else: setattr(pycppclass, meth_name, make_method(meth_name, cppol)) # add all data members to the dictionary of the class to be created, and # static ones also to the meta class (needed for property setters) for dm_name in cppclass.get_datamember_names(): cppdm = cppclass.get_datamember(dm_name) # here, setattr() can not be used, because a data member can shadow one in # its base class, resulting in the __set__() of its base class being called # by setattr(); so, store directly on the dictionary pycppclass.__dict__[dm_name] = cppdm import cppyy if cppyy._is_static(cppdm): # TODO: make this a method of cppdm metacpp.__dict__[dm_name] = cppdm # the call to register will add back-end specific pythonizations and thus # needs to run first, so that the generic pythonizations can use them import cppyy cppyy._register_class(pycppclass) _pythonize(pycppclass) return pycppclass
def get_pycppitem(scope, name): import cppyy # resolve typedefs/aliases full_name = (scope == gbl) and name or (scope.__name__+'::'+name) true_name = cppyy._resolve_name(full_name) if true_name != full_name: return get_pycppclass(true_name) pycppitem = None # classes cppitem = cppyy._scope_byname(true_name) if cppitem: if cppitem.is_namespace(): pycppitem = make_cppnamespace(scope, true_name, cppitem) setattr(scope, name, pycppitem) else: pycppitem = make_pycppclass(scope, true_name, name, cppitem) # templates if not cppitem: cppitem = cppyy._template_byname(true_name) if cppitem: pycppitem = make_cpptemplatetype(scope, name) setattr(scope, name, pycppitem) # functions if not cppitem: try: cppitem = scope._cpp_proxy.get_overload(name) pycppitem = make_static_function(name, cppitem) setattr(scope.__class__, name, pycppitem) pycppitem = getattr(scope, name) # binds function as needed except AttributeError: pass # data if not cppitem: try: cppdm = scope._cpp_proxy.get_datamember(name) setattr(scope, name, cppdm) if cppyy._is_static(cppdm): # TODO: make this a method of cppdm setattr(scope.__class__, name, cppdm) pycppitem = getattr(scope, name) # gets actual property value except AttributeError: pass if pycppitem is not None: # pycppitem could be a bound C++ NULL, so check explicitly for Py_None return pycppitem raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))