[pypy-commit] pypy default: Support PY_SSIZE_T_CLEAN, part 1

arigo noreply at buildbot.pypy.org
Mon Nov 11 10:46:27 CET 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r67948:b41903344f4c
Date: 2013-11-11 10:03 +0100
http://bitbucket.org/pypy/pypy/changeset/b41903344f4c/

Log:	Support PY_SSIZE_T_CLEAN, part 1

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -386,12 +386,14 @@
     'PyString_FromFormat', 'PyString_FromFormatV',
     'PyModule_AddObject', 'PyModule_AddIntConstant', 'PyModule_AddStringConstant',
     'Py_BuildValue', 'Py_VaBuildValue', 'PyTuple_Pack',
+    '_Py_BuildValue_SizeT', '_Py_VaBuildValue_SizeT',
 
     'PyErr_Format', 'PyErr_NewException', 'PyErr_NewExceptionWithDoc',
     'PySys_WriteStdout', 'PySys_WriteStderr',
 
     'PyEval_CallFunction', 'PyEval_CallMethod', 'PyObject_CallFunction',
     'PyObject_CallMethod', 'PyObject_CallFunctionObjArgs', 'PyObject_CallMethodObjArgs',
+    '_PyObject_CallFunction_SizeT', '_PyObject_CallMethod_SizeT',
 
     'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject',
     'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', 'init_bufferobject',
diff --git a/pypy/module/cpyext/include/eval.h b/pypy/module/cpyext/include/eval.h
--- a/pypy/module/cpyext/include/eval.h
+++ b/pypy/module/cpyext/include/eval.h
@@ -9,6 +9,11 @@
 
 #include "Python.h"
 
+#ifdef PY_SSIZE_T_CLEAN
+#define PyPyObject_CallFunction _PyPyObject_CallFunction_SizeT
+#define PyPyObject_CallMethod _PyPyObject_CallMethod_SizeT
+#endif
+
 #define PyEval_CallObject(func,arg) \
         PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL)
 
@@ -16,6 +21,8 @@
 PyObject * PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...);
 PyObject * PyObject_CallFunction(PyObject *obj, const char *format, ...);
 PyObject * PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...);
+PyObject * _PyObject_CallFunction_SizeT(PyObject *obj, const char *format, ...);
+PyObject * _PyObject_CallMethod_SizeT(PyObject *obj, const char *name, const char *format, ...);
 PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...);
 PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...);
 
diff --git a/pypy/module/cpyext/include/modsupport.h b/pypy/module/cpyext/include/modsupport.h
--- a/pypy/module/cpyext/include/modsupport.h
+++ b/pypy/module/cpyext/include/modsupport.h
@@ -7,6 +7,14 @@
 extern "C" {
 #endif
 
+/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier
+   to mean Py_ssize_t */
+#ifdef PY_SSIZE_T_CLEAN
+#define PyPy_BuildValue           _PyPy_BuildValue_SizeT
+#define PyPy_VaBuildValue         _PyPy_VaBuildValue_SizeT
+    /*XXX more*/
+#endif
+
 #define PYTHON_API_VERSION 1013
 #define PYTHON_API_STRING "1013"
 
diff --git a/pypy/module/cpyext/src/abstract.c b/pypy/module/cpyext/src/abstract.c
--- a/pypy/module/cpyext/src/abstract.c
+++ b/pypy/module/cpyext/src/abstract.c
@@ -150,6 +150,26 @@
 }
 
 PyObject *
+_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...)
+{
+    va_list va;
+    PyObject *args;
+
+    if (callable == NULL)
+        return null_error();
+
+    if (format && *format) {
+        va_start(va, format);
+        args = _Py_VaBuildValue_SizeT(format, va);
+        va_end(va);
+    }
+    else
+        args = PyTuple_New(0);
+
+    return call_function_tail(callable, args);
+}
+
+PyObject *
 PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...)
 {
     va_list va;
@@ -188,6 +208,45 @@
     return retval;
 }
 
+PyObject *
+_PyObject_CallMethod_SizeT(PyObject *o, const char *name, const char *format, ...)
+{
+    va_list va;
+    PyObject *args;
+    PyObject *func = NULL;
+    PyObject *retval = NULL;
+
+    if (o == NULL || name == NULL)
+        return null_error();
+
+    func = PyObject_GetAttrString(o, name);
+    if (func == NULL) {
+        PyErr_SetString(PyExc_AttributeError, name);
+        return 0;
+    }
+
+    if (!PyCallable_Check(func)) {
+        type_error("attribute of type '%.200s' is not callable", func);
+        goto exit;
+    }
+
+    if (format && *format) {
+        va_start(va, format);
+        args = _Py_VaBuildValue_SizeT(format, va);
+        va_end(va);
+    }
+    else
+        args = PyTuple_New(0);
+
+    retval = call_function_tail(func, args);
+
+  exit:
+    /* args gets consumed in call_function_tail */
+    Py_XDECREF(func);
+
+    return retval;
+}
+
 static PyObject *
 objargs_mktuple(va_list va)
 {
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -229,9 +229,11 @@
             return space.wrap(pydname)
 
         @unwrap_spec(name=str, init='str_or_None', body=str,
-                     load_it=bool, filename='str_or_None')
+                     load_it=bool, filename='str_or_None',
+                     PY_SSIZE_T_CLEAN=bool)
         def import_module(space, name, init=None, body='',
-                          load_it=True, filename=None):
+                          load_it=True, filename=None,
+                          PY_SSIZE_T_CLEAN=False):
             """
             init specifies the overall template of the module.
 
@@ -243,15 +245,19 @@
             """
             if init is not None:
                 code = """
+                %(PY_SSIZE_T_CLEAN)s
                 #include <Python.h>
                 %(body)s
 
                 void init%(name)s(void) {
                 %(init)s
                 }
-                """ % dict(name=name, init=init, body=body)
+                """ % dict(name=name, init=init, body=body,
+                           PY_SSIZE_T_CLEAN='#define PY_SSIZE_T_CLEAN'
+                                            if PY_SSIZE_T_CLEAN else '')
                 kwds = dict(separate_module_sources=[code])
             else:
+                assert not PY_SSIZE_T_CLEAN
                 if filename is None:
                     filename = name
                 filename = py.path.local(pypydir) / 'module' \
@@ -276,8 +282,9 @@
                 space.sys.get('modules'),
                 space.wrap(name))
 
-        @unwrap_spec(modname=str, prologue=str)
-        def import_extension(space, modname, w_functions, prologue=""):
+        @unwrap_spec(modname=str, prologue=str, PY_SSIZE_T_CLEAN=bool)
+        def import_extension(space, modname, w_functions, prologue="",
+                             PY_SSIZE_T_CLEAN=False):
             functions = space.unwrap(w_functions)
             methods_table = []
             codes = []
@@ -300,7 +307,8 @@
             };
             """ % ('\n'.join(methods_table),)
             init = """Py_InitModule("%s", methods);""" % (modname,)
-            return import_module(space, name=modname, init=init, body=body)
+            return import_module(space, name=modname, init=init, body=body,
+                                 PY_SSIZE_T_CLEAN=PY_SSIZE_T_CLEAN)
 
         @unwrap_spec(name=str)
         def record_imported_module(name):
diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py
--- a/pypy/module/cpyext/test/test_eval.py
+++ b/pypy/module/cpyext/test/test_eval.py
@@ -212,7 +212,7 @@
             ("call_func", "METH_VARARGS",
              """
                 return PyObject_CallFunction(PyTuple_GetItem(args, 0),
-                   "siO", "text", 42, Py_None);
+                   "siiiiO", "text", 42, -41, 40, -39, Py_None);
              """),
             ("call_method", "METH_VARARGS",
              """
@@ -222,9 +222,28 @@
             ])
         def f(*args):
             return args
-        assert module.call_func(f) == ("text", 42, None)
+        assert module.call_func(f) == ("text", 42, -41, 40, -39, None)
         assert module.call_method("text") == 2
 
+    def test_CallFunction_PY_SSIZE_T_CLEAN(self):
+        module = self.import_extension('foo', [
+            ("call_func", "METH_VARARGS",
+             """
+                return PyObject_CallFunction(PyTuple_GetItem(args, 0),
+                   "s#s#", "text", (Py_ssize_t)3, "othertext", (Py_ssize_t)6);
+             """),
+            ("call_method", "METH_VARARGS",
+             """
+                return PyObject_CallMethod(PyTuple_GetItem(args, 0),
+                   "find", "s#", "substring", (Py_ssize_t)6);
+             """),
+            ], PY_SSIZE_T_CLEAN=True)
+        def f(*args):
+            return args
+        assert module.call_func(f) == ("tex", "othert")
+        assert module.call_method("<<subst>>") == -1
+        assert module.call_method("<<substr>>") == 2
+
     def test_CallFunctionObjArgs(self):
         module = self.import_extension('foo', [
             ("call_func", "METH_VARARGS",


More information about the pypy-commit mailing list