def make_cppclass(scope, cl_name, decl): import _cppyy # get a list of base classes for class creation bases = [get_pycppclass(base) for base in decl.get_base_names()] if not bases: bases = [CPPClass,] else: # it's 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__[cl_name] except KeyError: pass # prepare dictionary for metaclass d_meta = {} # prepare dictionary for python-side C++ class representation def dispatch(self, m_name, signature): cppol = decl.__dispatch__(m_name, signature) return MethodType(cppol, self, type(self)) d_class = {"__cppdecl__" : decl, "__new__" : make_new(decl), "__module__" : make_module_name(scope), "__cppname__" : decl.__cppname__, "__dispatch__" : dispatch, } # insert (static) methods into the class dictionary for m_name in decl.get_method_names(): cppol = decl.get_overload(m_name) d_class[m_name] = cppol # add all data members to the dictionary of the class to be created, and # static ones also to the metaclass (needed for property setters) for d_name in decl.get_datamember_names(): cppdm = decl.get_datamember(d_name) d_class[d_name] = cppdm if _cppyy._is_static_data(cppdm): d_meta[d_name] = cppdm # create a metaclass to allow properties (for static data write access) metabases = [type(base) for base in bases] cl_meta = type(CPPClassMeta)(cl_name+'_meta', _drop_cycles(metabases), d_meta) # create the python-side C++ class pycls = cl_meta(cl_name, _drop_cycles(bases), d_class) # store the class on its outer scope setattr(scope, cl_name, pycls) # 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(pycls) _pythonize(pycls, pycls.__cppname__) return pycls
def get_scoped_pycppitem(scope, name, type_only=False): import _cppyy # resolve typedefs/aliases: these may cross namespaces, in which case # the lookup must trigger the creation of all necessary scopes scoped_name = (scope == gbl) and name or (scope.__cppname__ + '::' + name) final_scoped_name = _cppyy._resolve_name(scoped_name) if final_scoped_name != scoped_name: pycppitem = get_pycppitem(final_scoped_name) # also store on the requested scope (effectively a typedef or pointer copy) setattr(scope, name, pycppitem) return pycppitem pycppitem = None # scopes (classes and namespaces) cppitem = _cppyy._scope_byname(final_scoped_name) if cppitem: if cppitem.is_namespace(): pycppitem = make_cppnamespace(scope, name, cppitem) else: pycppitem = make_cppclass(scope, name, cppitem) if type_only: return pycppitem # templates if not cppitem: cppitem = _cppyy._is_template(final_scoped_name) if cppitem: pycppitem = make_cpptemplatetype(scope, name) setattr(scope, name, pycppitem) # functions if not cppitem: try: cppitem = scope.__cppdecl__.get_overload(name) setattr(scope.__class__, name, cppitem) pycppitem = getattr(scope, name) # binds function as needed except AttributeError: pass # data if not cppitem: try: cppdm = scope.__cppdecl__.get_datamember(name) setattr(scope, name, cppdm) if _cppyy._is_static_data(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))