[pypy-commit] pypy py3k: merge default (ea86924e88fb)

pjenvey noreply at buildbot.pypy.org
Fri Apr 25 01:59:38 CEST 2014


Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r70952:e0ce5503a026
Date: 2014-04-24 16:58 -0700
http://bitbucket.org/pypy/pypy/changeset/e0ce5503a026/

Log:	merge default (ea86924e88fb)

diff --git a/lib-python/2.7/test/test_itertools.py b/lib-python/2.7/test/test_itertools.py
--- a/lib-python/2.7/test/test_itertools.py
+++ b/lib-python/2.7/test/test_itertools.py
@@ -139,7 +139,6 @@
 
     @test_support.impl_detail("tuple reuse is specific to CPython")
     def test_combinations_tuple_reuse(self):
-        # Test implementation detail:  tuple re-use
         self.assertEqual(len(set(map(id, combinations('abcde', 3)))), 1)
         self.assertNotEqual(len(set(map(id, list(combinations('abcde', 3))))), 1)
 
@@ -211,7 +210,6 @@
 
     @test_support.impl_detail("tuple reuse is specific to CPython")
     def test_combinations_with_replacement_tuple_reuse(self):
-        # Test implementation detail:  tuple re-use
         cwr = combinations_with_replacement
         self.assertEqual(len(set(map(id, cwr('abcde', 3)))), 1)
         self.assertNotEqual(len(set(map(id, list(cwr('abcde', 3))))), 1)
@@ -278,7 +276,6 @@
 
     @test_support.impl_detail("tuple reuse is specific to CPython")
     def test_permutations_tuple_reuse(self):
-        # Test implementation detail:  tuple re-use
         self.assertEqual(len(set(map(id, permutations('abcde', 3)))), 1)
         self.assertNotEqual(len(set(map(id, list(permutations('abcde', 3))))), 1)
 
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -560,6 +560,12 @@
   Fixing these bootstrap problems is on the TODO list.
   The global namespace is ``cppyy.gbl``.
 
+* **NULL**: Is represented as ``cppyy.gbl.nullptr``.
+  In C++11, the keyword ``nullptr`` is used to represent ``NULL``.
+  For clarity of intent, it is recommended to use this instead of ``None``
+  (or the integer ``0``, which can serve in some cases), as ``None`` is better
+  understood as ``void`` in C++.
+
 * **operator conversions**: If defined in the C++ class and a python
   equivalent exists (i.e. all builtin integer and floating point types, as well
   as ``bool``), it will map onto that python conversion.
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -66,58 +66,26 @@
 Reflex
 ======
 
-This method is still experimental.  It adds the `cppyy`_ module.
-The method works by using the `Reflex package`_ to provide reflection
-information of the C++ code, which is then used to automatically generate
-bindings at runtime.
-From a python standpoint, there is no difference between generating bindings
-at runtime, or having them "statically" generated and available in scripts
-or compiled into extension modules: python classes and functions are always
-runtime structures, created when a script or module loads.
+The builtin `cppyy`_ module uses reflection information, provided by
+`Reflex`_ (which needs to be `installed separately`_), of C/C++ code to
+automatically generate bindings at runtime.
+In Python, classes and functions are always runtime structures, so when they
+are generated matters not for performance.
 However, if the backend itself is capable of dynamic behavior, it is a much
-better functional match to python, allowing tighter integration and more
-natural language mappings.
-Full details are `available here`_.
+better functional match, allowing tighter integration and more natural
+language mappings.
+
+The `cppyy`_ module is written in RPython, thus PyPy's JIT is able to remove
+most cross-language call overhead.
+
+`Full details`_ are `available here`_.
 
 .. _`cppyy`: cppyy.html
-.. _`reflex-support`: cppyy.html
-.. _`Reflex package`: http://root.cern.ch/drupal/content/reflex
+.. _`installed separately`: http://cern.ch/wlav/reflex-2013-08-14.tar.bz2
+.. _`Reflex`: http://root.cern.ch/drupal/content/reflex
+.. _`Full details`: cppyy.html
 .. _`available here`: cppyy.html
 
-Pros
-----
-
-The cppyy module is written in RPython, which makes it possible to keep the
-code execution visible to the JIT all the way to the actual point of call into
-C++, thus allowing for a very fast interface.
-Reflex is currently in use in large software environments in High Energy
-Physics (HEP), across many different projects and packages, and its use can be
-virtually completely automated in a production environment.
-One of its uses in HEP is in providing language bindings for CPython.
-Thus, it is possible to use Reflex to have bound code work on both CPython and
-on PyPy.
-In the medium-term, Reflex will be replaced by `cling`_, which is based on
-`llvm`_.
-This will affect the backend only; the python-side interface is expected to
-remain the same, except that cling adds a lot of dynamic behavior to C++,
-enabling further language integration.
-
-.. _`cling`: http://root.cern.ch/drupal/content/cling
-.. _`llvm`: http://llvm.org/
-
-Cons
-----
-
-C++ is a large language, and cppyy is not yet feature-complete.
-Still, the experience gained in developing the equivalent bindings for CPython
-means that adding missing features is a simple matter of engineering, not a
-question of research.
-The module is written so that currently missing features should do no harm if
-you don't use them, if you do need a particular feature, it may be necessary
-to work around it in python or with a C++ helper function.
-Although Reflex works on various platforms, the bindings with PyPy have only
-been tested on Linux.
-
 
 RPython Mixed Modules
 =====================
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
@@ -38,6 +38,24 @@
 typedef std::map<cppyy_scope_t, Cppyy_PseudoClassInfo> Scopes_t;
 static Scopes_t s_scopes;
 
+class PseudoExample01 {
+public:
+    PseudoExample01() : m_somedata(-99) {}
+    PseudoExample01(int a) : m_somedata(a) {}
+    PseudoExample01(const PseudoExample01& e) : m_somedata(e.m_somedata) {}
+    PseudoExample01& operator=(const PseudoExample01& e) {
+        if (this != &e) m_somedata = e.m_somedata;
+        return *this;
+    }
+   virtual ~PseudoExample01() {}
+
+public:
+    int m_somedata;
+};
+
+static int example01_last_static_method = 0;
+static int example01_last_constructor = 0;
+
 struct Cppyy_InitPseudoReflectionInfo {
     Cppyy_InitPseudoReflectionInfo() {
         // class example01 --
@@ -46,27 +64,62 @@
 
         std::vector<Cppyy_PseudoMethodInfo> methods;
 
-        // static double staticAddToDouble(double a);
+        // ( 0) static double staticAddToDouble(double a)
         std::vector<std::string> argtypes;
         argtypes.push_back("double");
         methods.push_back(Cppyy_PseudoMethodInfo("staticAddToDouble", argtypes, "double"));
 
-        // static int staticAddOneToInt(int a);
-        // static int staticAddOneToInt(int a, int b);
+        // ( 1) static int staticAddOneToInt(int a)
+        // ( 2) static int staticAddOneToInt(int a, int b)
         argtypes.clear();
         argtypes.push_back("int");
         methods.push_back(Cppyy_PseudoMethodInfo("staticAddOneToInt", argtypes, "int"));
         argtypes.push_back("int");
         methods.push_back(Cppyy_PseudoMethodInfo("staticAddOneToInt", argtypes, "int"));
 
-        // static int staticAtoi(const char* str);
+        // ( 3) static int staticAtoi(const char* str)
         argtypes.clear();
         argtypes.push_back("const char*");
         methods.push_back(Cppyy_PseudoMethodInfo("staticAtoi", argtypes, "int"));
 
-        // static char* staticStrcpy(const char* strin);
+        // ( 4) static char* staticStrcpy(const char* strin)
         methods.push_back(Cppyy_PseudoMethodInfo("staticStrcpy", argtypes, "char*"));
 
+        // ( 5) static void staticSetPayload(payload* p, double d)
+        // ( 6) static payload* staticCyclePayload(payload* p, double d)
+        // ( 7) static payload staticCopyCyclePayload(payload* p, double d)
+        argtypes.clear();
+        argtypes.push_back("payload*");
+        argtypes.push_back("double");
+        methods.push_back(Cppyy_PseudoMethodInfo("staticSetPayload", argtypes, "void"));
+        methods.push_back(Cppyy_PseudoMethodInfo("staticCyclePayload", argtypes, "payload*"));
+        methods.push_back(Cppyy_PseudoMethodInfo("staticCopyCyclePayload", argtypes, "payload"));
+
+        // ( 8) static int getCount()
+        // ( 9) static void setCount(int)
+        argtypes.clear();
+        methods.push_back(Cppyy_PseudoMethodInfo("getCount", argtypes, "int"));
+        argtypes.push_back("int");
+        methods.push_back(Cppyy_PseudoMethodInfo("setCount", argtypes, "void"));
+
+        // cut-off is used in cppyy_is_static
+        example01_last_static_method = methods.size();
+
+        // (10) example01()
+        // (11) example01(int a)
+        argtypes.clear();
+        methods.push_back(Cppyy_PseudoMethodInfo("example01", argtypes, "constructor"));
+        argtypes.push_back("int");
+        methods.push_back(Cppyy_PseudoMethodInfo("example01", argtypes, "constructor"));
+
+        // cut-off is used in cppyy_is_constructor
+        example01_last_constructor = methods.size();
+
+        // (12) double addDataToDouble(double a)
+        argtypes.clear();
+        argtypes.push_back("double");
+        methods.push_back(Cppyy_PseudoMethodInfo("addDataToDouble", argtypes, "double"));
+
         Cppyy_PseudoClassInfo info(methods);
         s_scopes[(cppyy_scope_t)s_scope_id] = info;
         // -- class example01
@@ -98,47 +151,69 @@
 }
 
 
+/* memory management ------------------------------------------------------ */
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+    if (handle == s_handles["example01"])
+       delete (PseudoExample01*)self;
+}
+
+
 /* method/function dispatching -------------------------------------------- */
-template<typename T>
-static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    T result = T();
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    int result = 0;
     switch ((long)method) {
-    case 0:             // double staticAddToDouble(double)
-        assert(!self && nargs == 1);
-        result = ((CPPYY_G__value*)args)[0].obj.d + 0.01;
-        break;
-    case 1:             // int staticAddOneToInt(int)
+    case 1:             // static int staticAddOneToInt(int)
         assert(!self && nargs == 1);
         result = ((CPPYY_G__value*)args)[0].obj.in + 1;
         break;
-    case 2:             // int staticAddOneToInt(int, int)
+    case 2:             // static int staticAddOneToInt(int, int)
         assert(!self && nargs == 2);
         result = ((CPPYY_G__value*)args)[0].obj.in + ((CPPYY_G__value*)args)[1].obj.in + 1;
         break;
-    case 3:             // int staticAtoi(const char* str)
+    case 3:             // static int staticAtoi(const char* str)
         assert(!self && nargs == 1);
         result = ::atoi((const char*)(*(long*)&((CPPYY_G__value*)args)[0]));
         break;
+    case 8:             // static int getCount()
+       assert(!self && nargs == 0);
+       // can't actually call this method (would need to resolve example01::count), but
+       // other than the memory tests, most tests just check for 0 at the end
+       result = 0;
+       break;
     default:
+        assert(!"method unknown in cppyy_call_i");
         break;
     }
     return result;
 }
 
-int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    return cppyy_call_T<int>(method, self, nargs, args);
-}
-
 long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    // char* staticStrcpy(const char* strin)
-    const char* strin = (const char*)(*(long*)&((CPPYY_G__value*)args)[0]);
-    char* strout = (char*)malloc(::strlen(strin)+1);
-    ::strcpy(strout, strin);
-    return (long)strout;
+    if ((long)method == 4) {  // static char* staticStrcpy(const char* strin)
+       const char* strin = (const char*)(*(long*)&((CPPYY_G__value*)args)[0]);
+       char* strout = (char*)malloc(::strlen(strin)+1);
+       ::strcpy(strout, strin);
+       return (long)strout;
+    }
+    assert(!"method unknown in cppyy_call_l");
+    return 0;
 }
 
 double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    return cppyy_call_T<double>(method, self, nargs, args);
+    double result = 0.;
+    switch ((long)method) {
+    case 0:             // static double staticAddToDouble(double)
+        assert(!self && nargs == 1);
+        result = ((CPPYY_G__value*)args)[0].obj.d + 0.01;
+        break;
+    case 12:            // double addDataToDouble(double a)
+        assert(self && nargs == 1);
+        result = ((PseudoExample01*)self)->m_somedata + ((CPPYY_G__value*)args)[0].obj.d;
+        break;
+    default:
+        assert(!"method unknown in cppyy_call_d");
+        break;
+    }
+    return result;
 }
 
 char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
@@ -149,10 +224,31 @@
     return strout;
 }
 
+cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) {
+    void* result = 0;
+    if (handle == s_handles["example01"]) {
+        switch ((long)method) {
+        case 10:
+            assert(nargs == 0);
+            result = new PseudoExample01;
+            break;
+        case 11:
+            assert(nargs == 1);
+            result = new PseudoExample01(((CPPYY_G__value*)args)[0].obj.in);
+            break;
+        default:
+            assert(!"method unknown in cppyy_constructor");
+            break;
+        }
+    }
+    return (cppyy_object_t)result;
+}
+
 cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
     return (cppyy_methptrgetter_t)0;
 }
 
+
 /* handling of function argument buffer ----------------------------------- */
 void* cppyy_allocate_function_args(size_t nargs) {
     CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
@@ -200,7 +296,11 @@
 }   
 
 int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) {
-    return 1;
+    return 0;
+}
+
+int cppyy_num_bases(cppyy_type_t /*handle*/) {
+   return 0;
 }
 
 
@@ -252,11 +352,16 @@
 
 
 /* method properties -----------------------------------------------------  */
-int cppyy_is_constructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) {
+    if (handle == s_handles["example01"])
+       return example01_last_static_method <= method_index
+           && method_index < example01_last_constructor;
     return 0;
 }
 
-int cppyy_is_staticmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) {
+    if (handle == s_handles["example01"])
+        return method_index < example01_last_static_method ? 1 : 0;
     return 1;
 }
 
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
--- a/pypy/module/cppyy/test/conftest.py
+++ b/pypy/module/cppyy/test/conftest.py
@@ -7,11 +7,12 @@
         if 'dummy' in lcapi.reflection_library:
             # run only tests that are covered by the dummy backend and tests
             # that do not rely on reflex
-            if not item.location[0] in ['test_helper.py', 'test_cppyy.py']:
+            if not ('test_helper.py' in item.location[0] or \
+                    'test_cppyy.py' in item.location[0]):
                 py.test.skip("genreflex is not installed")
             import re
-            if item.location[0] == 'test_cppyy.py' and \
-                not re.search("test0[1-3]", item.location[2]):
+            if 'test_cppyy.py' in item.location[0] and \
+                not re.search("test0[1-36]", item.location[2]):
                 py.test.skip("genreflex is not installed")
 
 def pytest_configure(config):
diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py
--- a/pypy/module/marshal/interp_marshal.py
+++ b/pypy/module/marshal/interp_marshal.py
@@ -330,21 +330,8 @@
 
 
 def invalid_typecode(space, u, tc):
-    # %r not supported in rpython
-    #u.raise_exc('invalid typecode in unmarshal: %r' % tc)
-    c = ord(tc)
-    if c < 16:
-        s = '\\x0%x' % c
-    elif c < 32 or c > 126:
-        s = '\\x%x' % c
-    elif tc == '\\':
-        s = r'\\'
-    else:
-        s = tc
-    q = "'"
-    if s[0] == "'":
-        q = '"'
-    u.raise_exc('invalid typecode in unmarshal: ' + q + s + q)
+    u.raise_exc("bad marshal data (unknown type code)")
+
 
 def register(codes, func):
     """NOT_RPYTHON"""
diff --git a/pypy/module/marshal/test/test_marshal.py b/pypy/module/marshal/test/test_marshal.py
--- a/pypy/module/marshal/test/test_marshal.py
+++ b/pypy/module/marshal/test/test_marshal.py
@@ -15,11 +15,14 @@
         print(repr(s))
         x = marshal.loads(s)
         assert x == case and type(x) is type(case)
-        f = BytesIO()
-        marshal.dump(case, f)
-        f.seek(0)
-        x = marshal.load(f)
-        assert x == case and type(x) is type(case)
+
+        import sys
+        if '__pypy__' in sys.builtin_module_names:
+            f = StringIO.StringIO()
+            marshal.dump(case, f)
+            f.seek(0)
+            x = marshal.load(f)
+            assert x == case and type(x) is type(case)
         return x
 
     def test_None(self):
@@ -190,8 +193,8 @@
 
     def test_bad_typecode(self):
         import marshal
-        exc = raises(ValueError, marshal.loads, b'\x01')
-        assert r"'\x01'" in str(exc.value)
+        exc = raises(ValueError, marshal.loads, chr(1))
+        assert str(exc.value) == "bad marshal data (unknown type code)"
 
     def test_bad_data(self):
         import marshal


More information about the pypy-commit mailing list