[pypy-svn] r76017 - in pypy/branch/reflex-support/pypy/module/cppyy: . test

wlav at codespeak.net wlav at codespeak.net
Thu Jul 8 12:38:19 CEST 2010


Author: wlav
Date: Thu Jul  8 12:38:17 2010
New Revision: 76017

Modified:
   pypy/branch/reflex-support/pypy/module/cppyy/__init__.py
   pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py
   pypy/branch/reflex-support/pypy/module/cppyy/pythonify.py
   pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py
   pypy/branch/reflex-support/pypy/module/cppyy/test/test_pythonify.py
Log:
(wlav, cfbolz): start exposing c++ classes and support static methods on them.


Modified: pypy/branch/reflex-support/pypy/module/cppyy/__init__.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/__init__.py	(original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/__init__.py	Thu Jul  8 12:38:17 2010
@@ -4,7 +4,8 @@
     """    """
 
     interpleveldefs = {
-        '_load_lib': 'interp_cppyy.load_lib',
+        '_load_lib'              : 'interp_cppyy.load_lib',
+        '_type_byname'           : 'interp_cppyy.type_byname',
     }
 
     appleveldefs = {

Modified: pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py	(original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/interp_cppyy.py	Thu Jul  8 12:38:17 2010
@@ -20,19 +20,22 @@
     return W_CPPLibrary(space, cdll)
 load_lib.unwrap_spec = [ObjSpace, str]
 
+def type_byname(space, name):
+    handle = capi.c_cppyy_get_typehandle(name)
+    if handle:
+        return W_CPPType(space, name, handle)
+    raise OperationError(space.w_TypeError, space.wrap("no such C++ class %s" % name))
+type_byname.unwrap_spec = [ObjSpace, str]
+
+
 class W_CPPLibrary(Wrappable):
     _immutable_ = True
     def __init__(self, space, cdll):
         self.cdll = cdll
         self.space = space
 
-    def type_byname(self, name):
-        handle = capi.c_cppyy_get_typehandle(name)
-        return W_CPPType(self, name, handle)
-
 W_CPPLibrary.typedef = TypeDef(
     'CPPLibrary',
-    type_byname = interp2app(W_CPPLibrary.type_byname, unwrap_spec=['self', str]),
 )
 
 class CPPMethod(object):
@@ -118,7 +121,7 @@
         return W_CPPObject(self.cpptype, result)
 
 
-class CPPOverload(object):
+class W_CPPOverload(Wrappable):
     _immutable_ = True
     _immutable_fields_ = ["functions[*]"]
     def __init__(self, space, func_name, functions):
@@ -126,6 +129,9 @@
         self.func_name = func_name
         self.functions = debug.make_sure_not_resized(functions)
 
+    def is_static(self):
+        return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+
     @jit.unroll_safe
     def call(self, cppthis, args_w):
         space = self.space
@@ -142,15 +148,19 @@
         raise OperationError(space.w_TypeError, space.wrap("none of the overloads matched"))
 
     def __repr__(self):
-        return "CPPOverload(%s, %s)" % (self.func_name, self.functions)
+        return "W_CPPOverload(%s, %s)" % (self.func_name, self.functions)
+
+W_CPPOverload.typedef = TypeDef(
+    'CPPOverload',
+    is_static = interp2app(W_CPPOverload.is_static, unwrap_spec=['self']),
+)
 
 
 class W_CPPType(Wrappable):
-    _immutable_fields_ = ["cpplib", "name","handle"]
+    _immutable_fields_ = ["name","handle"]
 
-    def __init__(self, cpplib, name, handle):
-        self.space = cpplib.space
-        self.cpplib = cpplib
+    def __init__(self, space, name, handle):
+        self.space = space
         self.name = name
         self.handle = handle
         self.function_members = {}
@@ -165,7 +175,7 @@
             overload = args_temp.setdefault(func_member_name, [])
             overload.append(cppfunction)
         for name, functions in args_temp.iteritems():
-            overload = CPPOverload(self.space, name, functions[:])
+            overload = W_CPPOverload(self.space, name, functions[:])
             self.function_members[name] = overload
 
     def _make_cppfunction(self, method_index):
@@ -183,6 +193,9 @@
             cls = CPPMethod
         return cls(self, method_index, result_type, argtypes)
 
+    def get_function_members(self):
+        return self.space.newlist([self.space.wrap(name) for name in self.function_members])
+
     @jit.purefunction
     def get_overload(self, name):
         return self.function_members[name]
@@ -197,6 +210,8 @@
 
 W_CPPType.typedef = TypeDef(
     'CPPType',
+    get_function_members = interp2app(W_CPPType.get_function_members, unwrap_spec=['self']),
+    get_overload = interp2app(W_CPPType.get_overload, unwrap_spec=['self', str]),
     invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', str, 'args_w']),
     construct = interp2app(W_CPPType.construct, unwrap_spec=['self', 'args_w']),
 )

Modified: pypy/branch/reflex-support/pypy/module/cppyy/pythonify.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/pythonify.py	(original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/pythonify.py	Thu Jul  8 12:38:17 2010
@@ -1,25 +1,52 @@
 # NOT_RPYTHON
 import cppyy
 
-class _gbl(object):
-    """Global C++ namespace, i.e. ::."""
-
-    def __getattr__(self, attr):
-        raise AttributeError
 
-class CppyyClass(object):
-    def __init__(self, cppclass):
-        # fill dictionary
-       pass
+class CppyyClass(type):
+     pass
 
+def make_static_function(cpptype, name):
+    def method(*args):
+        return cpptype.invoke(name,*args)
+    method.__name__ = name
+    return staticmethod(method)
 
+_existing_classes = {}
 def get_cppclass(name):
     # lookup class
+    try:
+        return _existing_classes[name]
+    except KeyError:
+        pass
 
     # if failed, create
+    # TODO: handle base classes
+    cpptype = cppyy._type_byname(name)
+    d = {"_cppyyclass" : cpptype}
+    for f in cpptype.get_function_members():
+        cppol = cpptype.get_overload(f)
+        if cppol.is_static():
+            d[f] = make_static_function(cpptype, f)
+        else:
+            pass
+
+    pycpptype = CppyyClass(name, (object,), d)
 
-    # create base classes
-    pass
+    return pycpptype
+
+#    raise TypeError("no such C++ class %s" % name)
+
+
+class _gbl(object):
+    """Global C++ namespace, i.e. ::."""
+
+    def __getattr__(self, attr):
+        try:
+            cppclass = get_cppclass(attr)
+            self.__dict__[attr] = cppclass
+            return cppclass
+        except TypeError:
+            raise AttributeError("'gbl' object has no attribute '%s'" % attr)
 
 
 _loaded_shared_libs = {}

Modified: pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py	(original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/test/test_cppyy.py	Thu Jul  8 12:38:17 2010
@@ -14,7 +14,7 @@
 class TestCPPYYImplementation:
     def test_class_query(self):
         lib = interp_cppyy.load_lib(space, shared_lib)
-        w_cppyyclass = lib.type_byname("example01")
+        w_cppyyclass = interp_cppyy.type_byname(space, "example01")
         adddouble = w_cppyyclass.function_members["staticAddToDouble"]
         func, = adddouble.functions
         assert isinstance(func.executor, executor.DoubleExecutor)
@@ -27,13 +27,14 @@
         env = os.environ
         cls.w_example01 = cls.space.appexec([], """():
             import cppyy
-            return cppyy.load_lib(%r)""" % (shared_lib, ))
+            cppyy.load_lib(%r)
+            return cppyy._type_byname('example01')""" % (shared_lib, ))
 
     def test_example01static_int(self):
         """Test passing of an int, returning of an int, and overloading on a
             differening number of arguments."""
         import sys
-        t = self.example01.type_byname("example01")
+        t = self.example01
         res = t.invoke("staticAddOneToInt", 1)
         assert res == 2
         res = t.invoke("staticAddOneToInt", 1L)
@@ -54,14 +55,14 @@
 
     def test_example01static_double(self):
         """Test passing of a double and returning of a double on a static function."""
-        t = self.example01.type_byname("example01")
+        t = self.example01
         res = t.invoke("staticAddToDouble", 0.09)
         assert res == 0.09 + 0.01
 
     def test_example01static_constcharp(self):
         """Test passing of a C string and returning of a C string on a static
             function."""
-        t = self.example01.type_byname("example01")
+        t = self.example01
         res = t.invoke("staticAtoi", "1")
         assert res == 1
 
@@ -76,7 +77,7 @@
     def test_example01method_int(self):
         """Test passing of a int, returning of a int, and memory cleanup, on
             a method."""
-        t = self.example01.type_byname("example01")
+        t = self.example01
         assert t.invoke("getCount") == 0
         instance = t.construct(7)
         assert t.invoke("getCount") == 1
@@ -98,7 +99,7 @@
 
     def test_example01method_double(self):
         """Test passing of a double and returning of double on a method"""
-        t = self.example01.type_byname("example01")
+        t = self.example01
         instance = t.construct(13)
         res = instance.invoke("addDataToDouble", 16)
         assert round(res-29, 8) == 0.
@@ -110,7 +111,7 @@
         """Test passing of a C string and returning of a C string on a
             method."""
 
-        t = self.example01.type_byname("example01")
+        t = self.example01
         instance = t.construct(42)
 
         res = instance.invoke("addDataToAtoi", "13")

Modified: pypy/branch/reflex-support/pypy/module/cppyy/test/test_pythonify.py
==============================================================================
--- pypy/branch/reflex-support/pypy/module/cppyy/test/test_pythonify.py	(original)
+++ pypy/branch/reflex-support/pypy/module/cppyy/test/test_pythonify.py	Thu Jul  8 12:38:17 2010
@@ -25,3 +25,35 @@
         import cppyy
         lib2 = cppyy.load_lib(self.shared_lib)
         assert self.example01 is lib2
+
+    def testFindingAClass(self):
+        """Test the lookup of a class, and its caching."""
+        import cppyy
+        example01_class = cppyy.gbl.example01
+        cl2 = cppyy.gbl.example01
+        assert example01_class is cl2
+
+        raises(AttributeError, "cppyy.gbl.nonexistingclass")
+
+    def testCallingAStaticFunction(self):
+        """Test calling of static methods."""
+        import cppyy, sys
+        example01_class = cppyy.gbl.example01
+        res = example01_class.staticAddOneToInt(1)
+        assert res == 2
+
+        res = example01_class.staticAddOneToInt(1L)
+        assert res == 2
+        res = example01_class.staticAddOneToInt(1, 2)
+        assert res == 4
+        res = example01_class.staticAddOneToInt(-1)
+        assert res == 0
+        res = example01_class.staticAddOneToInt(sys.maxint-1)
+        assert res == sys.maxint
+        res = example01_class.staticAddOneToInt(sys.maxint)
+        assert res == -sys.maxint-1
+
+        raises(TypeError, 'example01_class.staticAddOneToInt(1, [])')
+        raises(TypeError, 'example01_class.staticAddOneToInt(1.)')
+        raises(OverflowError, 'example01_class.staticAddOneToInt(sys.maxint+1)')
+



More information about the Pypy-commit mailing list