[pypy-commit] pypy cppyy-packaging: clearer naming and __cppname__ property for classes

wlav pypy.commits at gmail.com
Sat Oct 7 09:08:58 EDT 2017


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: cppyy-packaging
Changeset: r92592:0a1c3153a7e5
Date: 2017-09-22 15:17 -0700
http://bitbucket.org/pypy/pypy/changeset/0a1c3153a7e5/

Log:	clearer naming and __cppname__ property for classes

diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
--- a/pypy/module/_cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -13,7 +13,7 @@
         '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_get_nullptr'           : 'interp_cppyy.get_nullptr',
-        'CPPInstanceBase'        : 'interp_cppyy.W_CPPInstance',
+        'CPPClassBase'           : 'interp_cppyy.W_CPPClass',
         'addressof'              : 'interp_cppyy.addressof',
         'bind_object'            : 'interp_cppyy.bind_object',
     }
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -594,7 +594,7 @@
     """Return a python string taking into account \0"""
 
     from pypy.module._cppyy import interp_cppyy
-    cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=False)
+    cppstr = space.interp_w(interp_cppyy.W_CPPClass, w_self, can_be_None=False)
     return space.newtext(c_stdstring2charp(space, cppstr._rawobject))
 
 # setup pythonizations for later use at run-time
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -22,8 +22,8 @@
 
 
 def get_rawobject(space, w_obj):
-    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    from pypy.module._cppyy.interp_cppyy import W_CPPClass
+    cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
     if cppinstance:
         rawobject = cppinstance.get_rawobject()
         assert lltype.typeOf(rawobject) == capi.C_OBJECT
@@ -31,15 +31,15 @@
     return capi.C_NULL_OBJECT
 
 def set_rawobject(space, w_obj, address):
-    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    from pypy.module._cppyy.interp_cppyy import W_CPPClass
+    cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
     if cppinstance:
         assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
         cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
 
 def get_rawobject_nonnull(space, w_obj):
-    from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    from pypy.module._cppyy.interp_cppyy import W_CPPClass
+    cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
     if cppinstance:
         cppinstance._nullcheck()
         rawobject = cppinstance.get_rawobject()
@@ -484,24 +484,24 @@
     typecode   = 'V'
 
 class InstanceRefConverter(TypeConverter):
-    _immutable_fields_ = ['typecode', 'cppclass']
+    _immutable_fields_ = ['typecode', 'clsdecl']
     typecode    = 'V'
 
-    def __init__(self, space, cppclass):
-        from pypy.module._cppyy.interp_cppyy import W_CPPClass
-        assert isinstance(cppclass, W_CPPClass)
-        self.cppclass = cppclass
+    def __init__(self, space, clsdecl):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
+        assert isinstance(clsdecl, W_CPPClassDecl)
+        self.clsdecl = clsdecl
 
     def _unwrap_object(self, space, w_obj):
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-        if isinstance(w_obj, W_CPPInstance):
-            if capi.c_is_subtype(space, w_obj.cppclass, self.cppclass):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClass
+        if isinstance(w_obj, W_CPPClass):
+            if capi.c_is_subtype(space, w_obj.cppclass, self.clsdecl):
                 rawobject = w_obj.get_rawobject()
-                offset = capi.c_base_offset(space, w_obj.cppclass, self.cppclass, rawobject, 1)
+                offset = capi.c_base_offset(space, w_obj.cppclass, self.clsdecl, rawobject, 1)
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise oefmt(space.w_TypeError,
-                    "cannot pass %T as %s", w_obj, self.cppclass.name)
+                    "cannot pass %T as %s", w_obj, self.clsdecl.name)
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
@@ -527,7 +527,7 @@
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.cppclass, do_cast=False)
+        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
@@ -548,7 +548,7 @@
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.cppclass, do_cast=False)
+        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
@@ -574,15 +574,15 @@
         raise FastCallNotPossible
 
     def finalize_call(self, space, w_obj, call_local):
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-        assert isinstance(w_obj, W_CPPInstance)
+        from pypy.module._cppyy.interp_cppyy import W_CPPClass
+        assert isinstance(w_obj, W_CPPClass)
         r = rffi.cast(rffi.VOIDPP, call_local)
         w_obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
 
     def from_memory(self, space, w_obj, w_pycppclass, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module._cppyy import interp_cppyy
-        return interp_cppyy.wrap_cppobject(space, address, self.cppclass,
+        return interp_cppyy.wrap_cppobject(space, address, self.clsdecl,
                                            do_cast=False, is_ref=True)
 
 class StdStringConverter(InstanceConverter):
@@ -593,8 +593,8 @@
         InstanceConverter.__init__(self, space, cppclass)
 
     def _unwrap_object(self, space, w_obj):
-        from pypy.module._cppyy.interp_cppyy import W_CPPInstance
-        if isinstance(w_obj, W_CPPInstance):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClass
+        if isinstance(w_obj, W_CPPClass):
             arg = InstanceConverter._unwrap_object(self, space, w_obj)
             return capi.c_stdstring2stdstring(space, arg)
         else:
@@ -603,15 +603,15 @@
     def to_memory(self, space, w_obj, w_value, offset):
         try:
             address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
-            assign = self.cppclass.get_overload("__assign__")
+            assign = self.clsdecl.get_overload("__assign__")
             from pypy.module._cppyy import interp_cppyy
             assign.call(
-                interp_cppyy.wrap_cppobject(space, address, self.cppclass, do_cast=False), [w_value])
+                interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False), [w_value])
         except Exception:
             InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
     def free_argument(self, space, arg, call_local):
-        capi.c_destruct(space, self.cppclass, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+        capi.c_destruct(space, self.clsdecl, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
 
 class StdStringRefConverter(InstancePtrConverter):
     _immutable_fields_ = ['cppclass', 'typecode']
@@ -710,19 +710,19 @@
 
     #   4) generalized cases (covers basically all user classes)
     from pypy.module._cppyy import interp_cppyy
-    cppclass = interp_cppyy.scope_byname(space, clean_name)
-    if cppclass:
+    scope_decl = interp_cppyy.scope_byname(space, clean_name)
+    if scope_decl:
         # type check for the benefit of the annotator
-        from pypy.module._cppyy.interp_cppyy import W_CPPClass
-        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
+        clsdecl = space.interp_w(W_CPPClassDecl, scope_decl, can_be_None=False)
         if compound == "*":
-            return InstancePtrConverter(space, cppclass)
+            return InstancePtrConverter(space, clsdecl)
         elif compound == "&":
-            return InstanceRefConverter(space, cppclass)
+            return InstanceRefConverter(space, clsdecl)
         elif compound == "**":
-            return InstancePtrPtrConverter(space, cppclass)
+            return InstancePtrPtrConverter(space, clsdecl)
         elif compound == "":
-            return InstanceConverter(space, cppclass)
+            return InstanceConverter(space, clsdecl)
     elif capi.c_is_enum(space, clean_name):
         return _converters['unsigned'](space, default)
 
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -281,8 +281,8 @@
     cppclass = interp_cppyy.scope_byname(space, clean_name)
     if cppclass:
         # type check for the benefit of the annotator
-        from pypy.module._cppyy.interp_cppyy import W_CPPClass
-        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
+        cppclass = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
         if compound == '':
             return InstanceExecutor(space, cppclass)
         elif compound == '*' or compound == '&':
diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -34,7 +34,7 @@
 class State(object):
     def __init__(self, space):
         self.cppscope_cache = {
-            "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+            "void" : W_CPPClassDecl(space, "void", capi.C_NULL_TYPE) }
         self.w_nullptr = None
         self.cpptemplate_cache = {}
         self.cppclass_registry = {}
@@ -77,11 +77,11 @@
     if opaque_handle:
         final_name = capi.c_final_name(space, opaque_handle)
         if capi.c_is_namespace(space, opaque_handle):
-            cppscope = W_CPPNamespace(space, final_name, opaque_handle)
+            cppscope = W_CPPNamespaceDecl(space, final_name, opaque_handle)
         elif capi.c_has_complex_hierarchy(space, opaque_handle):
-            cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
+            cppscope = W_CPPComplexClass(space, final_name, opaque_handle)
         else:
-            cppscope = W_CPPClass(space, final_name, opaque_handle)
+            cppscope = W_CPPClassDecl(space, final_name, opaque_handle)
         state.cppscope_cache[name] = cppscope
 
         cppscope._build_methods()
@@ -119,8 +119,8 @@
     state.w_fngen_callback = w_callback
 
 def register_class(space, w_pycppclass):
-    w_cppclass = space.findattr(w_pycppclass, space.newtext("_cpp_proxy"))
-    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
+    cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, can_be_None=False)
     # add back-end specific method pythonizations (doing this on the wrapped
     # class allows simple aliasing of methods)
     capi.pythonize(space, cppclass.name, w_pycppclass)
@@ -169,7 +169,7 @@
 
     @staticmethod
     def unpack_cppthis(space, w_cppinstance, declaring_scope):
-        cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+        cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False)
         cppinstance._nullcheck()
         return cppinstance.get_cppthis(declaring_scope)
 
@@ -593,7 +593,7 @@
     def call(self, w_cppinstance, args_w):
         w_result = W_CPPOverload.call(self, w_cppinstance, args_w)
         newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
-        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
         if cppinstance is not None:
             cppinstance._rawobject = newthis
             memory_regulator.register(cppinstance)
@@ -650,7 +650,7 @@
         return offset
 
     def get(self, w_cppinstance, w_pycppclass):
-        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
         if not cppinstance:
             raise oefmt(self.space.w_ReferenceError,
                         "attribute access requires an instance")
@@ -658,7 +658,7 @@
         return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
 
     def set(self, w_cppinstance, w_value):
-        cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+        cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
         if not cppinstance:
             raise oefmt(self.space.w_ReferenceError,
                         "attribute access requires an instance")
@@ -704,7 +704,7 @@
     except Exception:
         return space.w_False
 
-class W_CPPScope(W_Root):
+class W_CPPScopeDecl(W_Root):
     _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
     _immutable_fields_ = ['handle', 'name']
 
@@ -725,6 +725,7 @@
     def get_method_names(self):
         return self.space.newlist([self.space.newtext(name) for name in self.methods])
 
+    @unwrap_spec(name='text')
     def get_overload(self, name):
         try:
             return self.methods[name]
@@ -737,6 +738,7 @@
     def get_datamember_names(self):
         return self.space.newlist([self.space.newtext(name) for name in self.datamembers])
 
+    @unwrap_spec(name='text')
     def get_datamember(self, name):
         try:
             return self.datamembers[name]
@@ -746,7 +748,8 @@
         self.datamembers[name] = new_dm
         return new_dm
 
-    def dispatch(self, name, signature):
+    @unwrap_spec(name='text', signature='text')
+    def scope__dispatch__(self, name, signature):
         overload = self.get_overload(name)
         sig = '(%s)' % signature
         for f in overload.functions:
@@ -765,8 +768,7 @@
 # with info from multiple dictionaries and do not need to bother with meta
 # classes for inheritance. Both are python classes, though, and refactoring
 # may be in order at some point.
-class W_CPPNamespace(W_CPPScope):
-
+class W_CPPNamespaceDecl(W_CPPScopeDecl):
     def _make_cppfunction(self, pyname, index):
         num_args = capi.c_method_num_args(self.space, self, index)
         args_required = capi.c_method_req_args(self.space, self, index)
@@ -838,25 +840,24 @@
             "namespace '%s' has no attribute %s", self.name, name)
 
 
-W_CPPNamespace.typedef = TypeDef(
-    'CPPNamespace',
-    get_method_names = interp2app(W_CPPNamespace.get_method_names),
-    get_overload = interp2app(W_CPPNamespace.get_overload, unwrap_spec=['self', 'text']),
-    get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
-    get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', 'text']),
-    is_namespace = interp2app(W_CPPNamespace.is_namespace),
-    __dir__ = interp2app(W_CPPNamespace.ns__dir__),
+W_CPPNamespaceDecl.typedef = TypeDef(
+    'CPPNamespaceDecl',
+    get_method_names = interp2app(W_CPPNamespaceDecl.get_method_names),
+    get_overload = interp2app(W_CPPNamespaceDecl.get_overload),
+    get_datamember_names = interp2app(W_CPPNamespaceDecl.get_datamember_names),
+    get_datamember = interp2app(W_CPPNamespaceDecl.get_datamember),
+    is_namespace = interp2app(W_CPPNamespaceDecl.is_namespace),
+    __cppname__ = interp_attrproperty('name', W_CPPNamespaceDecl, wrapfn="newtext"),
+    __dispatch__ = interp2app(W_CPPNamespaceDecl.scope__dispatch__),
+    __dir__ = interp2app(W_CPPNamespaceDecl.ns__dir__),
 )
-W_CPPNamespace.typedef.acceptable_as_base_class = False
+W_CPPNamespaceDecl.typedef.acceptable_as_base_class = False
 
 
-class W_CPPClass(W_CPPScope):
+class W_CPPClassDecl(W_CPPScopeDecl):
     _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
     _immutable_fields_ = ['handle', 'constructor', 'methods[*]', 'datamembers[*]']
 
-    def __init__(self, space, name, opaque_handle):
-        W_CPPScope.__init__(self, space, name, opaque_handle)
-
     def _build_methods(self):
         assert len(self.methods) == 0
         methods_temp = {}
@@ -956,22 +957,21 @@
             "class '%s' has no attribute %s", self.name, name)
 
 
-W_CPPClass.typedef = TypeDef(
-    'CPPClass',
-    type_name = interp_attrproperty('name', W_CPPClass, wrapfn="newtext"),
-    get_base_names = interp2app(W_CPPClass.get_base_names),
-    get_method_names = interp2app(W_CPPClass.get_method_names),
-    get_overload = interp2app(W_CPPClass.get_overload, unwrap_spec=['self', 'text']),
-    get_datamember_names = interp2app(W_CPPClass.get_datamember_names),
-    get_datamember = interp2app(W_CPPClass.get_datamember, unwrap_spec=['self', 'text']),
-    is_namespace = interp2app(W_CPPClass.is_namespace),
-    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', 'text', 'text'])
+W_CPPClassDecl.typedef = TypeDef(
+    'CPPClassDecl',
+    get_base_names = interp2app(W_CPPClassDecl.get_base_names),
+    get_method_names = interp2app(W_CPPClassDecl.get_method_names),
+    get_overload = interp2app(W_CPPClassDecl.get_overload),
+    get_datamember_names = interp2app(W_CPPClassDecl.get_datamember_names),
+    get_datamember = interp2app(W_CPPClassDecl.get_datamember),
+    is_namespace = interp2app(W_CPPClassDecl.is_namespace),
+    __cppname__ = interp_attrproperty('name', W_CPPClassDecl, wrapfn="newtext"),
+    __dispatch__ = interp2app(W_CPPClassDecl.scope__dispatch__)
 )
-W_CPPClass.typedef.acceptable_as_base_class = False
+W_CPPClassDecl.typedef.acceptable_as_base_class = False
 
 
-class W_ComplexCPPClass(W_CPPClass):
-
+class W_CPPComplexClassDecl(W_CPPClassDecl):
     def get_base_offset(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
         offset = capi.c_base_offset(self.space,
@@ -983,18 +983,18 @@
         offset = self.get_base_offset(cppinstance, calling_scope)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
 
-W_ComplexCPPClass.typedef = TypeDef(
-    'ComplexCPPClass',
-    type_name = interp_attrproperty('name', W_CPPClass, wrapfn="newtext"),
-    get_base_names = interp2app(W_ComplexCPPClass.get_base_names),
-    get_method_names = interp2app(W_ComplexCPPClass.get_method_names),
-    get_overload = interp2app(W_ComplexCPPClass.get_overload, unwrap_spec=['self', 'text']),
-    get_datamember_names = interp2app(W_ComplexCPPClass.get_datamember_names),
-    get_datamember = interp2app(W_ComplexCPPClass.get_datamember, unwrap_spec=['self', 'text']),
-    is_namespace = interp2app(W_ComplexCPPClass.is_namespace),
-    dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', 'text', 'text'])
+W_CPPComplexClassDecl.typedef = TypeDef(
+    'CPPComplexClassDecl',
+    get_base_names = interp2app(W_CPPComplexClassDecl.get_base_names),
+    get_method_names = interp2app(W_CPPComplexClassDecl.get_method_names),
+    get_overload = interp2app(W_CPPComplexClassDecl.get_overload),
+    get_datamember_names = interp2app(W_CPPComplexClassDecl.get_datamember_names),
+    get_datamember = interp2app(W_CPPComplexClassDecl.get_datamember),
+    is_namespace = interp2app(W_CPPComplexClassDecl.is_namespace),
+    __cppname__ = interp_attrproperty('name', W_CPPComplexClassDecl, wrapfn="newtext"),
+    __dispatch__ = interp2app(W_CPPComplexClassDecl.scope__dispatch__)
 )
-W_ComplexCPPClass.typedef.acceptable_as_base_class = False
+W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False
 
 
 class W_CPPTemplateType(W_Root):
@@ -1018,7 +1018,7 @@
 W_CPPTemplateType.typedef.acceptable_as_base_class = False
 
 
-class W_CPPInstance(W_Root):
+class W_CPPClass(W_Root):
     _attrs_ = ['space', 'cppclass', '_rawobject', 'isref', 'python_owns',
                'finalizer_registered']
     _immutable_fields_ = ["cppclass", "isref"]
@@ -1094,8 +1094,8 @@
         # find a global overload in gbl, in __gnu_cxx (for iterators), or in the
         # scopes of the argument classes (TODO: implement that last option)
         try:
-            # TODO: expecting w_other to be an W_CPPInstance is too limiting
-            other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+            # TODO: expecting w_other to be an W_CPPClass is too limiting
+            other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False)
             for name in ["", "__gnu_cxx", "__1"]:
                 nss = scope_byname(self.space, name)
                 meth_idx = capi.c_get_global_operator(
@@ -1117,7 +1117,7 @@
 
         # fallback 2: direct pointer comparison (the class comparison is needed since
         # the first data member in a struct and the struct have the same address)
-        other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)  # TODO: factor out
+        other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False)  # TODO: factor out
         iseq = (self._rawobject == other._rawobject) and (self.cppclass == other.cppclass)
         return self.space.newbool(iseq)
 
@@ -1160,20 +1160,20 @@
         if self.python_owns:
             self.destruct()
 
-W_CPPInstance.typedef = TypeDef(
-    'CPPInstance',
-    cppclass = interp_attrproperty_w('cppclass', cls=W_CPPInstance),
-    _python_owns = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
-    __init__ = interp2app(W_CPPInstance.instance__init__),
-    __eq__ = interp2app(W_CPPInstance.instance__eq__),
-    __ne__ = interp2app(W_CPPInstance.instance__ne__),
-    __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
-    __len__ = interp2app(W_CPPInstance.instance__len__),
-    __cmp__ = interp2app(W_CPPInstance.instance__cmp__),
-    __repr__ = interp2app(W_CPPInstance.instance__repr__),
-    __destruct__ = interp2app(W_CPPInstance.destruct),
+W_CPPClass.typedef = TypeDef(
+    'CPPClass',
+    cppclass = interp_attrproperty_w('cppclass', cls=W_CPPClass),
+    _python_owns = GetSetProperty(W_CPPClass.fget_python_owns, W_CPPClass.fset_python_owns),
+    __init__ = interp2app(W_CPPClass.instance__init__),
+    __eq__ = interp2app(W_CPPClass.instance__eq__),
+    __ne__ = interp2app(W_CPPClass.instance__ne__),
+    __nonzero__ = interp2app(W_CPPClass.instance__nonzero__),
+    __len__ = interp2app(W_CPPClass.instance__len__),
+    __cmp__ = interp2app(W_CPPClass.instance__cmp__),
+    __repr__ = interp2app(W_CPPClass.instance__repr__),
+    __destruct__ = interp2app(W_CPPClass.destruct),
 )
-W_CPPInstance.typedef.acceptable_as_base_class = True
+W_CPPClass.typedef.acceptable_as_base_class = True
 
 
 class MemoryRegulator:
@@ -1185,7 +1185,7 @@
     # Note that for now, the associated test carries an m_padding to make
     # a difference in the addresses.
     def __init__(self):
-        self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+        self.objects = rweakref.RWeakValueDictionary(int, W_CPPClass)
 
     def register(self, obj):
         if not obj._rawobject:
@@ -1233,8 +1233,8 @@
                 w_pycppclass = get_pythonized_cppclass(space, actual)
                 offset = capi.c_base_offset1(space, actual, cppclass, rawobject, -1)
                 rawobject = capi.direct_ptradd(rawobject, offset)
-                w_cppclass = space.findattr(w_pycppclass, space.newtext("_cpp_proxy"))
-                cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+                w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
+                cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, can_be_None=False)
             except Exception:
                 # failed to locate/build the derived class, so stick to the base (note
                 # that only get_pythonized_cppclass is expected to raise, so none of
@@ -1251,8 +1251,8 @@
             return obj
 
     # fresh creation
-    w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
-    cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+    w_cppinstance = space.allocate_instance(W_CPPClass, w_pycppclass)
+    cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False)
     cppinstance.__init__(space, cppclass, rawobject, is_ref, python_owns)
     memory_regulator.register(cppinstance)
     return w_cppinstance
@@ -1281,11 +1281,11 @@
     except Exception:
         # accept integer value as address
         rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
-    w_cppclass = space.findattr(w_pycppclass, space.newtext("_cpp_proxy"))
+    w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
     if not w_cppclass:
         w_cppclass = scope_byname(space, space.text_w(w_pycppclass))
         if not w_cppclass:
             raise oefmt(space.w_TypeError,
                         "no such class: %s", space.text_w(w_pycppclass))
-    cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+    cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, can_be_None=False)
     return wrap_cppobject(space, rawobject, cppclass, do_cast=cast, python_owns=owns)
diff --git a/pypy/module/_cppyy/pythonify.py b/pypy/module/_cppyy/pythonify.py
--- a/pypy/module/_cppyy/pythonify.py
+++ b/pypy/module/_cppyy/pythonify.py
@@ -4,11 +4,10 @@
 import sys
 
 
-# For now, keep namespaces and classes separate as namespaces are extensible
-# with info from multiple dictionaries and do not need to bother with meta
-# classes for inheritance. Both are python classes, though, and refactoring
-# may be in order at some point.
-class CPPScope(type):
+# Metaclasses are needed to store C++ static data members as properties. Since
+# the interp-level does not support metaclasses, they are created at app-level.
+# These are the metaclass base classes:
+class CPPMetaScope(type):
     def __getattr__(self, name):
         try:
             return get_pycppitem(self, name)  # will cache on self
@@ -16,14 +15,17 @@
             raise AttributeError("%s object has no attribute '%s' (details: %s)" %
                                  (self, name, str(e)))
 
-class CPPNamespace(CPPScope):
-    def __dir__(cls):
-        return cls._cpp_proxy.__dir__()
+class CPPMetaNamespace(CPPMetaScope):
+    def __dir__(self):
+        return self.__cppdecl__.__dir__()
 
-class CPPClass(CPPScope):
+class CPPMetaClass(CPPMetaScope):
     pass
 
-# class CPPInstance defined in _init_pythonify()
+# namespace base class (class base class defined in _init_pythonify)
+class CPPNamespace(object):
+    __metatype__ = CPPMetaNamespace
+
 
 class CPPTemplate(object):
     def __init__(self, name, scope=None):
@@ -88,24 +90,25 @@
     return method
 
 
-def make_cppnamespace(scope, namespace_name, cppns, build_in_full=False):
+def make_cppnamespace(scope, name, decl):
     # build up a representation of a C++ namespace (namespaces are classes)
 
-    # create a meta class to allow properties (for static data write access)
-    metans = type(CPPNamespace)(namespace_name+'_meta', (CPPNamespace,), {})
+    # create a metaclass to allow properties (for static data write access)
+    import _cppyy
+    ns_meta = type(name+'_meta', (CPPMetaNamespace,), {})
 
     # create the python-side C++ namespace representation, cache in scope if given
-    d = {"_cpp_proxy" : cppns}
-    pycppns = metans(namespace_name, (object,), d)
+    d = {"__cppdecl__" : decl, "__cppname__" : decl.__cppname__ }
+    pyns = ns_meta(name, (CPPNamespace,), d)
     if scope:
-        setattr(scope, namespace_name, pycppns)
+        setattr(scope, name, pyns)
 
     # install as modules to allow importing from (note naming: cppyy)
     modname = 'cppyy.gbl'
     if scope:
-        modname = 'cppyy.gbl.'+pycppns.__name__.replace('::', '.')
-    sys.modules[modname] = pycppns
-    return pycppns
+        modname = 'cppyy.gbl.'+pyns.__cppname__.replace('::', '.')
+    sys.modules[modname] = pyns
+    return pyns
 
 def _drop_cycles(bases):
     # TODO: figure this out, as it seems to be a PyPy bug?!
@@ -126,12 +129,12 @@
         return instance
     return __new__
 
-def make_cppclass(scope, class_name, final_class_name, cppclass):
+def make_cppclass(scope, class_name, final_class_name, decl):
 
     # get a list of base classes for class creation
-    bases = [get_pycppclass(base) for base in cppclass.get_base_names()]
+    bases = [get_pycppclass(base) for base in decl.get_base_names()]
     if not bases:
-        bases = [CPPInstance,]
+        bases = [CPPClass,]
     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
@@ -140,50 +143,50 @@
         except KeyError:
             pass
 
-    # prepare dictionary for meta class
+    # prepare dictionary for metaclass
     d_meta = {}
 
     # prepare dictionary for python-side C++ class representation
     def dispatch(self, name, signature):
-        cppol = cppclass.dispatch(name, signature)
+        cppol = decl.dispatch(name, signature)
         return types.MethodType(make_method(name, cppol), self, type(self))
-    d_class = {"_cpp_proxy"   : cppclass,
-         "__dispatch__" : dispatch,
+    d_class = {"__cppdecl__"   : decl,
+         "__cppname__"  : decl.__cppname__,
          "__new__"      : make_new(class_name),
          }
 
     # insert (static) methods into the class dictionary
-    for name in cppclass.get_method_names():
-        cppol = cppclass.get_overload(name)
+    for name in decl.get_method_names():
+        cppol = decl.get_overload(name)
         if cppol.is_static():
             d_class[name] = make_static_function(name, cppol)
         else:
             d_class[name] = make_method(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 name in cppclass.get_datamember_names():
-        cppdm = cppclass.get_datamember(name)
+    # static ones also to the metaclass (needed for property setters)
+    for name in decl.get_datamember_names():
+        cppdm = decl.get_datamember(name)
         d_class[name] = cppdm
         if cppdm.is_static():
             d_meta[name] = cppdm
 
-    # create a meta class to allow properties (for static data write access)
+    # create a metaclass to allow properties (for static data write access)
     metabases = [type(base) for base in bases]
-    metacpp = type(CPPClass)(class_name+'_meta', _drop_cycles(metabases), d_meta)
+    metacpp = type(CPPMetaScope)(class_name+'_meta', _drop_cycles(metabases), d_meta)
 
     # create the python-side C++ class
-    pycppclass = metacpp(class_name, _drop_cycles(bases), d_class)
+    pycls = metacpp(class_name, _drop_cycles(bases), d_class)
 
     # store the class on its outer scope
-    setattr(scope, final_class_name, pycppclass)
+    setattr(scope, final_class_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(pycppclass)
-    _pythonize(pycppclass)
-    return pycppclass
+    _cppyy._register_class(pycls)
+    _pythonize(pycls)
+    return pycls
 
 def make_cpptemplatetype(scope, template_name):
     return CPPTemplate(template_name, scope)
@@ -203,11 +206,14 @@
     # classes
     cppitem = _cppyy._scope_byname(true_name)
     if cppitem:
+        name = true_name
+        if scope != gbl:
+            name = true_name[len(scope.__cppname__)+2:]
         if cppitem.is_namespace():
-            pycppitem = make_cppnamespace(scope, true_name, cppitem)
+            pycppitem = make_cppnamespace(scope, name, cppitem)
             setattr(scope, name, pycppitem)
         else:
-            pycppitem = make_cppclass(scope, true_name, name, cppitem)
+            pycppitem = make_cppclass(scope, name, true_name, cppitem)
 
     # templates
     if not cppitem:
@@ -219,7 +225,7 @@
     # functions
     if not cppitem:
         try:
-            cppitem = scope._cpp_proxy.get_overload(name)
+            cppitem = scope.__cppdecl__.get_overload(name)
             pycppitem = make_static_function(name, cppitem)
             setattr(scope.__class__, name, pycppitem)
             pycppitem = getattr(scope, name)      # binds function as needed
@@ -229,7 +235,7 @@
     # data
     if not cppitem:
         try:
-            cppdm = scope._cpp_proxy.get_datamember(name)
+            cppdm = scope.__cppdecl__.get_datamember(name)
             setattr(scope, name, cppdm)
             if cppdm.is_static():
                 setattr(scope.__class__, name, cppdm)
@@ -388,11 +394,11 @@
     # at pypy-c startup, rather than on the "import _cppyy" statement
     import _cppyy
 
-    # root of all proxy classes: CPPInstance in pythonify exists to combine the
-    # CPPClass meta class with the interp-level CPPInstanceBase
-    global CPPInstance
-    class CPPInstance(_cppyy.CPPInstanceBase):
-        __metaclass__ = CPPClass
+    # root of all proxy classes: CPPClass in pythonify exists to combine the
+    # CPPMetaScope metaclass with the interp-level CPPClassBase
+    global CPPClass
+    class CPPClass(_cppyy.CPPClassBase):
+        __metaclass__ = CPPMetaScope
         pass
 
     # class generator callback
@@ -403,8 +409,9 @@
 
     # user interface objects
     global gbl
-    gbl = make_cppnamespace(None, '::', _cppyy._scope_byname(''))
-    gbl.__doc__ = "Global C++ namespace."
+    gbl = make_cppnamespace(None, 'gbl', _cppyy._scope_byname(''))
+    gbl.__module__  = 'cppyy'
+    gbl.__doc__     = 'Global C++ namespace.'
 
     # pre-create std to allow direct importing
     gbl.std = make_cppnamespace(gbl, 'std', _cppyy._scope_byname('std'))
diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx b/pypy/module/_cppyy/src/dummy_backend.cxx
--- a/pypy/module/_cppyy/src/dummy_backend.cxx
+++ b/pypy/module/_cppyy/src/dummy_backend.cxx
@@ -164,6 +164,14 @@
         static long s_scope_id  = 0;
         static long s_method_id = 0;
 
+        { // namespace ''
+        s_handles[""] = (cppyy_scope_t)++s_scope_id;
+        }
+
+        { // namespace std
+        s_handles["std"] = (cppyy_scope_t)++s_scope_id;
+        }
+
         { // class example01 --
         s_handles["example01"] = (cppyy_scope_t)++s_scope_id;
 
diff --git a/pypy/module/_cppyy/test/test_cppyy.py b/pypy/module/_cppyy/test/test_cppyy.py
--- a/pypy/module/_cppyy/test/test_cppyy.py
+++ b/pypy/module/_cppyy/test/test_cppyy.py
@@ -95,7 +95,7 @@
 
         assert t.get_overload("getCount").call(None) == 0
 
-        e1 = t.get_overload(t.type_name).call(None, 7)
+        e1 = t.get_overload(t.__cppname__).call(None, 7)
         assert t.get_overload("getCount").call(None) == 1
         res = t.get_overload("addDataToInt").call(e1, 4)
         assert res == 11
@@ -105,8 +105,8 @@
         assert t.get_overload("getCount").call(None) == 0
         raises(ReferenceError, 't.get_overload("addDataToInt").call(e1, 4)')
 
-        e1 = t.get_overload(t.type_name).call(None, 7)
-        e2 = t.get_overload(t.type_name).call(None, 8)
+        e1 = t.get_overload(t.__cppname__).call(None, 7)
+        e2 = t.get_overload(t.__cppname__).call(None, 8)
         assert t.get_overload("getCount").call(None) == 2
         e1.__destruct__()
         assert t.get_overload("getCount").call(None) == 1
@@ -128,7 +128,7 @@
 
         assert t.get_overload("getCount").call(None) == 0
 
-        e1 = t.get_overload(t.type_name).call(None, 7)
+        e1 = t.get_overload(t.__cppname__).call(None, 7)
         assert t.get_overload("getCount").call(None) == 1
         res = t.get_overload("addDataToInt").call(e1, 4)
         assert res == 11
@@ -138,8 +138,8 @@
         gc.collect()
         assert t.get_overload("getCount").call(None) == 0
 
-        e1 = t.get_overload(t.type_name).call(None, 7)
-        e2 = t.get_overload(t.type_name).call(None, 8)
+        e1 = t.get_overload(t.__cppname__).call(None, 7)
+        e2 = t.get_overload(t.__cppname__).call(None, 8)
         assert t.get_overload("getCount").call(None) == 2
         e1 = None
         gc.collect()
@@ -159,7 +159,7 @@
 
         assert t.get_overload("getCount").call(None) == 0
 
-        e1 = t.get_overload(t.type_name).call(None, 7)
+        e1 = t.get_overload(t.__cppname__).call(None, 7)
         assert t.get_overload("getCount").call(None) == 1
         assert e1._python_owns == True
         e1._python_owns = False
@@ -178,12 +178,12 @@
 
         t = self.example01
 
-        e = t.get_overload(t.type_name).call(None, 13)
+        e = t.get_overload(t.__cppname__).call(None, 13)
         res = t.get_overload("addDataToDouble").call(e, 16)
         assert round(res-29, 8) == 0.
         e.__destruct__()
 
-        e = t.get_overload(t.type_name).call(None, -13)
+        e = t.get_overload(t.__cppname__).call(None, -13)
         res = t.get_overload("addDataToDouble").call(e, 16)
         assert round(res-3, 8) == 0.
         e.__destruct__()
@@ -196,7 +196,7 @@
 
         t = self.example01
 
-        e = t.get_overload(t.type_name).call(None, 42)
+        e = t.get_overload(t.__cppname__).call(None, 42)
         res = t.get_overload("addDataToAtoi").call(e, "13")
         assert res == 55
         res = t.get_overload("addToStringValue").call(e, "12")       # TODO: this leaks
@@ -213,12 +213,12 @@
         t1 = self.example01
         t2 = self.payload
 
-        pl = t2.get_overload(t2.type_name).call(None, 3.14)
+        pl = t2.get_overload(t2.__cppname__).call(None, 3.14)
         assert round(t2.get_overload("getData").call(pl)-3.14, 8) == 0
-        t1.get_overload("staticSetPayload").call(None, pl, 41.)      # now pl is a CPPInstance
+        t1.get_overload("staticSetPayload").call(None, pl, 41.)
         assert t2.get_overload("getData").call(pl) == 41.
 
-        e = t1.get_overload(t1.type_name).call(None, 50)
+        e = t1.get_overload(t1.__cppname__).call(None, 50)
         t1.get_overload("setPayload").call(e, pl);
         assert round(t2.get_overload("getData").call(pl)-50., 8) == 0
 
@@ -233,12 +233,12 @@
         t1 = self.example01
         t2 = self.payload
 
-        pl1 = t2.get_overload(t2.type_name).call(None, 3.14)
+        pl1 = t2.get_overload(t2.__cppname__).call(None, 3.14)
         assert round(t2.get_overload("getData").call(pl1)-3.14, 8) == 0
         pl2 = t1.get_overload("staticCyclePayload").call(None, pl1, 38.)
         assert t2.get_overload("getData").call(pl2) == 38.
 
-        e = t1.get_overload(t1.type_name).call(None, 50)
+        e = t1.get_overload(t1.__cppname__).call(None, 50)
         pl2 = t1.get_overload("cyclePayload").call(e, pl1);
         assert round(t2.get_overload("getData").call(pl2)-50., 8) == 0
 
diff --git a/pypy/module/_cppyy/test/test_fragile.py b/pypy/module/_cppyy/test/test_fragile.py
--- a/pypy/module/_cppyy/test/test_fragile.py
+++ b/pypy/module/_cppyy/test/test_fragile.py
@@ -34,7 +34,7 @@
 
         assert fragile.B == fragile.B
         assert fragile.B().check() == ord('B')
-        raises(AttributeError, getattr, fragile.B().gime_no_such(), "_cpp_proxy")
+        raises(AttributeError, getattr, fragile.B().gime_no_such(), "__cppdecl__")
 
         assert fragile.C == fragile.C
         assert fragile.C().check() == ord('C')
@@ -237,17 +237,35 @@
 
         from cppyy.gbl.fragile import nested1
         assert _cppyy.gbl.fragile.nested1 is nested1
+        assert nested1.__name__ == 'nested1'
+        assert nested1.__module__ == 'cppyy.gbl.fragile'
+        assert nested1.__cppname__ == 'nested1'
 
         from cppyy.gbl.fragile.nested1 import A, nested2
         assert _cppyy.gbl.fragile.nested1.A is A
+        assert A.__name__ == 'A'
+        assert A.__module__ == 'cppyy.gbl.fragile.nested1'
+        assert A.__cppname__ == 'fragile::nested1::A'
         assert _cppyy.gbl.fragile.nested1.nested2 is nested2
+        assert A.__name__ == 'A'
+        assert A.__module__ == 'cppyy.gbl.fragile.nested1'
+        assert nested2.__cppname__ == 'fragile::nested1::nested2'
 
         from cppyy.gbl.fragile.nested1.nested2 import A, nested3
         assert _cppyy.gbl.fragile.nested1.nested2.A is A
+        assert A.__name__ == 'A'
+        assert A.__module__ == 'cppyy.gbl.fragile.nested1'
+        assert A.__cppname__ == 'fragile::nested1::nested2::A'
         assert _cppyy.gbl.fragile.nested1.nested2.nested3 is nested3
+        assert A.__name__ == 'A'
+        assert A.__module__ == 'cppyy.gbl.fragile.nested1'
+        assert nested3.__cppname__ == 'fragile::nested1::nested2::nested3'
 
         from cppyy.gbl.fragile.nested1.nested2.nested3 import A
         assert _cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A
+        assert A.__name__ == 'A'
+        assert A.__module__ == 'cppyy.gbl.fragile.nested1'
+        assert A.__cppname__ == 'fragile::nested1::nested2::nested3::A'
 
     def test12_missing_casts(self):
         """Test proper handling when a hierarchy is not fully available"""
diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -281,7 +281,7 @@
             cls  = interp_cppyy.scope_byname(space, "example01")
             inst = cls.get_overload("example01").call(None, [FakeInt(0)])
             cppmethod = cls.get_overload(method_name)
-            assert isinstance(inst, interp_cppyy.W_CPPInstance)
+            assert isinstance(inst, interp_cppyy.W_CPPClass)
             i = 10
             while i > 0:
                 drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)


More information about the pypy-commit mailing list