Author: Wim Lavrijsen <wlavrij...@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) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit