Commits

wlav committed 7e43dd4

pull C++ bound methods into the app level to allow normal python mro to work

Comments (0)

Files changed (6)

pypy/module/cppyy/interp_cppyy.py

 
     @jit.purefunction
     def get_overload(self, name):
-        return self.methods[name]
+        try:
+            return self.methods[name]
+        except KeyError:
+            raise OperationError(
+                self.space.w_AttributeError,
+                self.space.wrap(str("class %s has no attribute %s" % (self.name, name))))
 
     def get_data_member_names(self):
         return self.space.newlist([self.space.wrap(name) for name in self.data_members])
 
     @jit.purefunction
     def get_data_member(self, name):
-        return self.data_members[name]
+        try:
+            return self.data_members[name]
+        except KeyError:
+            raise OperationError(
+                self.space.w_AttributeError,
+                self.space.wrap(str("class %s has no attribute %s" % (self.name, name))))
 
-    def invoke(self, name, args_w):
-        overload = self.get_overload(name)
+    def invoke(self, overload, args_w):
         return overload.call(NULL_VOIDP, args_w)
 
 W_CPPScope.typedef = TypeDef(
     get_overload = interp2app(W_CPPScope.get_overload, unwrap_spec=['self', str]),
     get_data_member_names = interp2app(W_CPPScope.get_data_member_names, unwrap_spec=['self']),
     get_data_member = interp2app(W_CPPScope.get_data_member, unwrap_spec=['self', str]),
-    invoke = interp2app(W_CPPScope.invoke, unwrap_spec=['self', str, 'args_w']),
+    invoke = interp2app(W_CPPScope.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']),
 )
 
 
     get_data_member_names = interp2app(W_CPPType.get_data_member_names, unwrap_spec=['self']),
     get_data_member = interp2app(W_CPPType.get_data_member, unwrap_spec=['self', str]),
     is_namespace = interp2app(W_CPPType.is_namespace, unwrap_spec=['self']),
-    invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', str, 'args_w']),
+    invoke = interp2app(W_CPPType.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']),
     construct = interp2app(W_CPPType.construct, unwrap_spec=['self', 'args_w']),
 )
 
         if not self.rawobject:
             raise OperationError(self.space.w_ReferenceError, self.space.wrap("trying to access a NULL pointer"))
 
-    def invoke(self, method_name, args_w):
+    def invoke(self, overload, args_w):
         self._nullcheck()
         cppclass = jit.hint(self.cppclass, promote=True)
-        overload = cppclass.get_overload(method_name)
         return overload.call(self.rawobject, args_w)
 
     def destruct(self):
 
 W_CPPInstance.typedef = TypeDef(
     'CPPInstance',
-    invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', str, 'args_w']),
+    invoke = interp2app(W_CPPInstance.invoke, unwrap_spec=['self', W_CPPOverload, 'args_w']),
     destruct = interp2app(W_CPPInstance.destruct, unwrap_spec=['self']),
 )

pypy/module/cppyy/pythonify.py

     bound_obj._cppinstance = cppobj
     return bound_obj
 
-def make_static_function(cpptype, name, rettype):
-    print rettype
+def make_static_function(cpptype, func_name, cppol):
+    rettype = cppol.get_returntype()
     if not rettype:                              # return builtin type
         def method(*args):
-            return cpptype.invoke(name, *args)
+            return cpptype.invoke(cppol, *args)
     else:                                        # return instance
         cppclass = get_cppclass(rettype)
         def method(*args):
-            return bind_object(cpptype.invoke(name, *args), cppclass)
-    method.__name__ = name
+            return bind_object(cpptype.invoke(cppol, *args), cppclass)
+    method.__name__ = func_name
     return staticmethod(method)
 
-def make_method(name, rettype):
+def make_method(meth_name, cppol):
+    rettype = cppol.get_returntype()
     if not rettype:                              # return builtin type
         def method(self, *args):
-            return self._cppinstance.invoke(name, *args)
+            return self._cppinstance.invoke(cppol, *args)
     else:                                        # return instance
         cppclass = get_cppclass(rettype)
         def method(self, *args):
-            return bind_object(self._cppinstance.invoke(name, *args), cppclass)
-    method.__name__ = name
+            return bind_object(self._cppinstance.invoke(cppol, *args), cppclass)
+    method.__name__ = meth_name
     return method
 
 
     d = {}
 
     # insert static methods into the "namespace" dictionary
-    for f in cppns.get_method_names():
+    for func_name in cppns.get_method_names():
         cppol = cppns.get_overload(f)
-        d[f] = make_static_function(cppns, f, cppol.get_returntype())
+        d[func_name] = make_static_function(cppns, func_name, cppol)
 
     # create a meta class to allow properties (for static data write access)
     metans = type(CppyyNamespace)(name+'_meta', (type(type),),
     _existing_cppitems[name] = pycppns
     return pycppns
 
-def make_cppclass(name, cpptype):
+def make_cppclass(class_name, cpptype):
     d = {"_cppyyclass" : cpptype}
 
     # insert (static) methods into the class dictionary
-    for f in cpptype.get_method_names():
-        cppol = cpptype.get_overload(f)
+    for meth_name in cpptype.get_method_names():
+        cppol = cpptype.get_overload(meth_name)
         if cppol.is_static():
-            d[f] = make_static_function(cpptype, f, cppol.get_returntype())
+            d[meth_name] = make_static_function(cpptype, meth_name, cppol)
         else:
-            d[f] = make_method(f, cppol.get_returntype())
+            d[meth_name] = make_method(meth_name, cppol)
 
     # get a list of base classes for class creation
     bases = tuple([get_cppclass(base) for base in cpptype.get_base_names()])
 
     # create a meta class to allow properties (for static data write access)
     metabases = tuple([type(base) for base in bases])
-    metacpp = type(CppyyClass)(name+'_meta', metabases,
+    metacpp = type(CppyyClass)(class_name+'_meta', metabases,
                                {"__getattr__" : __innercpp_getattr__})
 
     # add all data members to the dictionary of the class to be created, and
     # static ones also to the meta class (needed for property setters)
-    for dm in cpptype.get_data_member_names():
-        cppdm = cpptype.get_data_member(dm)
+    for dm_name in cpptype.get_data_member_names():
+        cppdm = cpptype.get_data_member(dm_name)
 
-        d[dm] = cppdm
+        d[dm_name] = cppdm
         if cppdm.is_static():
-            setattr(metacpp, dm, cppdm)
+            setattr(metacpp, dm_name, cppdm)
 
     # create the python-side C++ class representation
-    pycpptype = metacpp(name, bases, d)
+    pycpptype = metacpp(class_name, bases, d)
  
     # cache result and return
-    _existing_cppitems[name] = pycpptype
+    _existing_cppitems[class_name] = pycpptype
     return pycpptype
 
 

pypy/module/cppyy/test/advancedcpp.h

 //===========================================================================
 class base_class {                 // for simple inheritance testing
 public:
-   base_class() { m_a = 1; m_da = 1.1; }
+   base_class() { m_b = 1; m_db = 1.1; }
    virtual ~base_class() {}
-   virtual int get_value() = 0;
+   virtual int get_value() { return m_b; }
+   double get_base_value() { return m_db; }
 
 public:
-   int m_a;
-   double m_da;
+   int m_b;
+   double m_db;
 };
 
 class derived_class : public base_class {
 public:
-   derived_class() { m_b = 2; m_db = 2.2;}
-   virtual int get_value() { return m_b; }
+   derived_class() { m_d = 2; m_dd = 2.2;}
+   virtual int get_value() { return m_d; }
+   double get_derived_value() { return m_dd; }
 
 public:
-   int m_b;
-   double m_db;
+   int m_d;
+   double m_dd;
 };
 
 

pypy/module/cppyy/test/bench1.py

     for i in range(10000000):
         i
 
+addDataToInt = cls.get_overload("addDataToInt")
+
 def f():
     res = 0
     for i in range(10000000):
-        #inst.invoke("addDataToDouble", float(i))
-        inst.invoke("addDataToInt", i)
+        #inst.invoke(cls.get_overload("addDataToDouble"), float(i))
+        #inst.invoke(cls.get_overload("addDataToInt"), i)
+        inst.invoke(addDataToInt, i)
 
 g(); f();
 t1 = time.time()

pypy/module/cppyy/test/test_advancedcpp.py

         assert issubclass(derived_class, base_class)
         assert not issubclass(base_class, derived_class)
 
-        c = derived_class()
-        assert isinstance( c, derived_class )
-        assert isinstance( c, base_class )
+        b = base_class()
+        assert isinstance(b, base_class)
+        assert not isinstance(b, derived_class)
 
-        c.destruct()
+        assert b.get_value()      == 1
+        assert b.get_base_value() == 1.1
+
+        d = derived_class()
+        assert isinstance(d, derived_class)
+        assert isinstance(d, base_class)
+
+        assert d.get_value()         == 2
+        assert d.get_base_value()    == 1.1
+        assert d.get_derived_value() == 2.2
+
+        d.destruct()
 
     def test02_namespaces(self):
         """Test access to namespaces and inner classes"""

pypy/module/cppyy/test/test_cppyy.py

     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
-        res = t.invoke("staticAddOneToInt", 1)
+
+        res = t.invoke(t.get_overload("staticAddOneToInt"), 1)
         assert res == 2
-        res = t.invoke("staticAddOneToInt", 1L)
+        res = t.invoke(t.get_overload("staticAddOneToInt"), 1L)
         assert res == 2
-        res = t.invoke("staticAddOneToInt", 1, 2)
+        res = t.invoke(t.get_overload("staticAddOneToInt"), 1, 2)
         assert res == 4
-        res = t.invoke("staticAddOneToInt", -1)
+        res = t.invoke(t.get_overload("staticAddOneToInt"), -1)
         assert res == 0
-        res = t.invoke("staticAddOneToInt", sys.maxint-1)
+        res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint-1)
         assert res == sys.maxint
-        res = t.invoke("staticAddOneToInt", sys.maxint)
+        res = t.invoke(t.get_overload("staticAddOneToInt"), sys.maxint)
         assert res == -sys.maxint-1
 
-        raises(TypeError, 't.invoke("staticAddOneToInt", 1, [])')
-        raises(TypeError, 't.invoke("staticAddOneToInt", 1.)')
-        raises(OverflowError, 't.invoke("staticAddOneToInt", sys.maxint+1)')
+        raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1, [])')
+        raises(TypeError, 't.invoke(t.get_overload("staticAddOneToInt"), 1.)')
+        raises(OverflowError, 't.invoke(t.get_overload("staticAddOneToInt"), sys.maxint+1)')
 
 
     def test_example01static_double(self):
         """Test passing of a double and returning of a double on a static function."""
+
         t = self.example01
-        res = t.invoke("staticAddToDouble", 0.09)
+
+        res = t.invoke(t.get_overload("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
-        res = t.invoke("staticAtoi", "1")
+
+        res = t.invoke(t.get_overload("staticAtoi"), "1")
         assert res == 1
-
-        res = t.invoke("staticStrcpy", "aap")
+        res = t.invoke(t.get_overload("staticStrcpy"), "aap")
+        assert res == "aap"
+        res = t.invoke(t.get_overload("staticStrcpy"), u"aap")
         assert res == "aap"
 
-        res = t.invoke("staticStrcpy", u"aap")
-        assert res == "aap"
-
-        raises(TypeError, 't.invoke("staticStrcpy", 1.)')
+        raises(TypeError, 't.invoke(t.get_overload("staticStrcpy"), 1.)')
 
     def test_example01method_int(self):
         """Test passing of a int, returning of a int, and memory cleanup, on
             a method."""
+
         t = self.example01
-        assert t.invoke("getCount") == 0
-        instance = t.construct(7)
-        assert t.invoke("getCount") == 1
-        res = instance.invoke("addDataToInt", 4)
+
+        assert t.invoke(t.get_overload("getCount")) == 0
+
+        e1 = t.construct(7)
+        assert t.invoke(t.get_overload("getCount")) == 1
+        res = e1.invoke(t.get_overload("addDataToInt"), 4)
         assert res == 11
-        res = instance.invoke("addDataToInt", -4)
+        res = e1.invoke(t.get_overload("addDataToInt"), -4)
         assert res == 3
-        instance.destruct()
-        assert t.invoke("getCount") == 0
-        raises(ReferenceError, 'instance.invoke("addDataToInt", 4)')
+        e1.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
+        raises(ReferenceError, 'e1.invoke(t.get_overload("addDataToInt"), 4)')
 
-        instance = t.construct(7)
-        instance2 = t.construct(8)
-        assert t.invoke("getCount") == 2
-        instance.destruct()
-        assert t.invoke("getCount") == 1
-        instance2.destruct()
-        assert t.invoke("getCount") == 0
+        e1 = t.construct(7)
+        e2 = t.construct(8)
+        assert t.invoke(t.get_overload("getCount")) == 2
+        e1.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 1
+        e2.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
 
     def test_example01method_double(self):
         """Test passing of a double and returning of double on a method"""
+
         t = self.example01
-        instance = t.construct(13)
-        res = instance.invoke("addDataToDouble", 16)
+
+        e = t.construct(13)
+        res = e.invoke(t.get_overload("addDataToDouble"), 16)
         assert round(res-29, 8) == 0.
-        instance.destruct()
-        instance = t.construct(-13)
-        res = instance.invoke("addDataToDouble", 16)
+        e.destruct()
+
+        e = t.construct(-13)
+        res = e.invoke(t.get_overload("addDataToDouble"), 16)
         assert round(res-3, 8) == 0.
-        instance.destruct()
-        assert t.invoke("getCount") == 0
+        e.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
 
     def test_example01method_constcharp(self):
         """Test passing of a C string and returning of a C string on a
             method."""
 
         t = self.example01
-        instance = t.construct(42)
 
-        res = instance.invoke("addDataToAtoi", "13")
+        e = t.construct(42)
+        res = e.invoke(t.get_overload("addDataToAtoi"), "13")
         assert res == 55
-
-        res = instance.invoke("addToStringValue", "12")
+        res = e.invoke(t.get_overload("addToStringValue"), "12")
         assert res == "54"
-        res = instance.invoke("addToStringValue", "-12")
+        res = e.invoke(t.get_overload("addToStringValue"), "-12")
         assert res == "30"
-        instance.destruct()
-        assert t.invoke("getCount") == 0
+        e.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
 
     def testPassingOfAnObjectByPointer(self):
         """Test passing of an instance as an argument."""
 
-        t = self.example01
+        t1 = self.example01
+        t2 = self.payload
 
-        pl = self.payload.construct(3.14)
-        assert round(pl.invoke("getData")-3.14, 8) == 0
-        
-        t.invoke("staticSetPayload", pl, 41.)    # now pl is a CPPInstance
-        assert pl.invoke("getData") == 41.
+        pl = t2.construct(3.14)
+        assert round(pl.invoke(t2.get_overload("getData"))-3.14, 8) == 0
+        t1.invoke(t1.get_overload("staticSetPayload"), pl, 41.)  # now pl is a CPPInstance
+        assert pl.invoke(t2.get_overload("getData")) == 41.
 
-        e = t.construct(50)
-        e.invoke("setPayload", pl);
-        assert round(pl.invoke("getData")-50., 8) == 0
+        e = t1.construct(50)
+        e.invoke(t1.get_overload("setPayload"), pl);
+        assert round(pl.invoke(t2.get_overload("getData"))-50., 8) == 0
 
         e.destruct()
         pl.destruct() 
-        assert t.invoke("getCount") == 0
+        assert t1.invoke(t1.get_overload("getCount")) == 0
 
     def testReturningOfAnObjectByPointer(self):
         """Test returning of an instance as an argument."""
 
-        t = self.example01
-        
-        pl = self.payload.construct(3.14)
-        assert round(pl.invoke("getData")-3.14, 8) == 0
+        t1 = self.example01
+        t2 = self.payload
 
-        pl2 = t.invoke("staticCyclePayload", pl, 38.)
-        assert pl2.invoke("getData") == 38.
+        pl1 = t2.construct(3.14)
+        assert round(pl1.invoke(t2.get_overload("getData"))-3.14, 8) == 0
+        pl2 = t1.invoke(t1.get_overload("staticCyclePayload"), pl1, 38.)
+        assert pl2.invoke(t2.get_overload("getData")) == 38.
 
-        e = t.construct(50)
-
-        pl2 = e.invoke("cyclePayload", pl);
-        assert round(pl2.invoke("getData")-50., 8) == 0
+        e = t1.construct(50)
+        pl2 = e.invoke(t1.get_overload("cyclePayload"), pl1);
+        assert round(pl2.invoke(t2.get_overload("getData"))-50., 8) == 0
 
         e.destruct()
-        pl.destruct() 
-        assert t.invoke("getCount") == 0
-
+        pl1.destruct() 
+        assert t1.invoke(t1.get_overload("getCount")) == 0