[pypy-svn] r73407 - in pypy/branch/cpython-extension/pypy/module/cpyext: . include src

fijal at codespeak.net fijal at codespeak.net
Mon Apr 5 05:34:16 CEST 2010


Author: fijal
Date: Mon Apr  5 05:34:14 2010
New Revision: 73407

Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/getargs.py
   pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
   pypy/branch/cpython-extension/pypy/module/cpyext/include/listobject.h
   pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.h
   pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
   pypy/branch/cpython-extension/pypy/module/cpyext/src/getargs.c
   pypy/branch/cpython-extension/pypy/module/cpyext/src/modsupport.c
Log:
Provide a bit more support for Py_BuildValue and a couple of simple changes.
WARNING: this is still a bit preliminary since we disable certain functions
out of Py_BuildValue (long long and complex to be precise)


Modified: pypy/branch/cpython-extension/pypy/module/cpyext/getargs.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/getargs.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/getargs.py	Mon Apr  5 05:34:14 2010
@@ -12,6 +12,10 @@
 def PyArg_ParseTuple():
     pass
 
+ at cpython_api_c()
+def PyArg_UnpackTuple():
+    pass
+
 @cpython_api([PyObject, rffi.CCHARP, VA_LIST_P, rffi.INT_real],
              rffi.INT_real, error=0)
 def pypy_vgetargs1(space, w_obj, fmt, va_list_p, flags):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/Python.h	Mon Apr  5 05:34:14 2010
@@ -13,6 +13,7 @@
 #define WITH_DOC_STRINGS
 #define HAVE_UNICODE
 #define INT_MAX (1 << (8 * sizeof(int) - 1))
+#define WITHOUT_COMPLEX
 
 /* Compat stuff */
 #ifndef _WIN32

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/listobject.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/listobject.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/listobject.h	Mon Apr  5 05:34:14 2010
@@ -1 +1,2 @@
 #define PyList_GET_ITEM PyList_GetItem
+#define PyList_SET_ITEM PyList_SetItem

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.h
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.h	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/include/modsupport.h	Mon Apr  5 05:34:14 2010
@@ -29,6 +29,12 @@
 
 int PyModule_AddObject(PyObject *m, const char *name, PyObject *o);
 
+PyObject * Py_BuildValue(const char *, ...);
+PyObject * _Py_BuildValue_SizeT(const char *, ...);
+int _PyArg_NoKeywords(const char *funcname, PyObject *kw);
+
+int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...);
+
 /*
  * This is from pyport.h.  Perhaps it belongs elsewhere.
  */

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/modsupport.py	Mon Apr  5 05:34:14 2010
@@ -11,6 +11,10 @@
 def PyModule_AddObject():
     pass
 
+ at cpython_api_c()
+def Py_BuildValue():
+    pass
+
 def PyImport_AddModule(space, name):
     w_name = space.wrap(name)
     w_mod = space.wrap(Module(space, w_name))

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/src/getargs.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/src/getargs.c	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/src/getargs.c	Mon Apr  5 05:34:14 2010
@@ -137,5 +137,63 @@
 	return pypy_vgetargs1(args, format, &lva, FLAG_SIZE_T);
 }
 
+int
+PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+{
+	Py_ssize_t i, l;
+	PyObject **o;
+	va_list vargs;
 
+#ifdef HAVE_STDARG_PROTOTYPES
+	va_start(vargs, max);
+#else
+	va_start(vargs);
+#endif
+
+	assert(min >= 0);
+	assert(min <= max);
+	if (!PyTuple_Check(args)) {
+		PyErr_SetString(PyExc_SystemError,
+		    "PyArg_UnpackTuple() argument list is not a tuple");
+		return 0;
+	}	
+	l = PyTuple_GET_SIZE(args);
+	if (l < min) {
+		if (name != NULL)
+			PyErr_Format(
+			    PyExc_TypeError,
+			    "%s expected %s%zd arguments, got %zd", 
+			    name, (min == max ? "" : "at least "), min, l);
+		else
+			PyErr_Format(
+			    PyExc_TypeError,
+			    "unpacked tuple should have %s%zd elements,"
+			    " but has %zd", 
+			    (min == max ? "" : "at least "), min, l);
+		va_end(vargs);
+		return 0;
+	}
+	if (l > max) {
+		if (name != NULL)
+			PyErr_Format(
+			    PyExc_TypeError,
+			    "%s expected %s%zd arguments, got %zd", 
+			    name, (min == max ? "" : "at most "), max, l);
+		else
+			PyErr_Format(
+			    PyExc_TypeError,
+			    "unpacked tuple should have %s%zd elements,"
+			    " but has %zd", 
+			    (min == max ? "" : "at most "), max, l);
+		va_end(vargs);
+		return 0;
+	}
+	for (i = 0; i < l; i++) {
+		o = va_arg(vargs, PyObject **);
+		*o = PyTuple_GET_ITEM(args, i);
+	}
+	va_end(vargs);
+	return 1;
+
+}
 // REST IS NOT COPIED FROM CPYTHON

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/src/modsupport.c
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/src/modsupport.c	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/src/modsupport.c	Mon Apr  5 05:34:14 2010
@@ -1,4 +1,522 @@
-#include <Python.h>
+
+/* Module support implementation */
+
+#include "Python.h"
+
+#define FLAG_SIZE_T 1
+typedef double va_double;
+
+static PyObject *va_build_value(const char *, va_list, int);
+
+/* Package context -- the full module name for package imports */
+char *_Py_PackageContext = NULL;
+
+/* Py_InitModule4() parameters:
+   - name is the module name
+   - methods is the list of top-level functions
+   - doc is the documentation string
+   - passthrough is passed as self to functions defined in the module
+   - api_version is the value of PYTHON_API_VERSION at the time the
+     module was compiled
+
+   Return value is a borrowed reference to the module object; or NULL
+   if an error occurred (in Python 1.4 and before, errors were fatal).
+   Errors may still leak memory.
+*/
+
+static char api_version_warning[] =
+"Python C API version mismatch for module %.100s:\
+ This Python has API version %d, module %.100s has version %d.";
+
+/* Helper for mkvalue() to scan the length of a format */
+
+static int
+countformat(const char *format, int endchar)
+{
+	int count = 0;
+	int level = 0;
+	while (level > 0 || *format != endchar) {
+		switch (*format) {
+		case '\0':
+			/* Premature end */
+			PyErr_SetString(PyExc_SystemError,
+					"unmatched paren in format");
+			return -1;
+		case '(':
+		case '[':
+		case '{':
+			if (level == 0)
+				count++;
+			level++;
+			break;
+		case ')':
+		case ']':
+		case '}':
+			level--;
+			break;
+		case '#':
+		case '&':
+		case ',':
+		case ':':
+		case ' ':
+		case '\t':
+			break;
+		default:
+			if (level == 0)
+				count++;
+		}
+		format++;
+	}
+	return count;
+}
+
+
+/* Generic function to create a value -- the inverse of getargs() */
+/* After an original idea and first implementation by Steven Miale */
+
+static PyObject *do_mktuple(const char**, va_list *, int, int, int);
+static PyObject *do_mklist(const char**, va_list *, int, int, int);
+static PyObject *do_mkdict(const char**, va_list *, int, int, int);
+static PyObject *do_mkvalue(const char**, va_list *, int);
+
+
+static PyObject *
+do_mkdict(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+	PyObject *d;
+	int i;
+	int itemfailed = 0;
+	if (n < 0)
+		return NULL;
+	if ((d = PyDict_New()) == NULL)
+		return NULL;
+	/* Note that we can't bail immediately on error as this will leak
+	   refcounts on any 'N' arguments. */
+	for (i = 0; i < n; i+= 2) {
+		PyObject *k, *v;
+		int err;
+		k = do_mkvalue(p_format, p_va, flags);
+		if (k == NULL) {
+			itemfailed = 1;
+			Py_INCREF(Py_None);
+			k = Py_None;
+		}
+		v = do_mkvalue(p_format, p_va, flags);
+		if (v == NULL) {
+			itemfailed = 1;
+			Py_INCREF(Py_None);
+			v = Py_None;
+		}
+		err = PyDict_SetItem(d, k, v);
+		Py_DECREF(k);
+		Py_DECREF(v);
+		if (err < 0 || itemfailed) {
+			Py_DECREF(d);
+			return NULL;
+		}
+	}
+	if (d != NULL && **p_format != endchar) {
+		Py_DECREF(d);
+		d = NULL;
+		PyErr_SetString(PyExc_SystemError,
+				"Unmatched paren in format");
+	}
+	else if (endchar)
+		++*p_format;
+	return d;
+}
+
+static PyObject *
+do_mklist(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+	PyObject *v;
+	int i;
+	int itemfailed = 0;
+	if (n < 0)
+		return NULL;
+	v = PyList_New(n);
+	if (v == NULL)
+		return NULL;
+	/* Note that we can't bail immediately on error as this will leak
+	   refcounts on any 'N' arguments. */
+	for (i = 0; i < n; i++) {
+		PyObject *w = do_mkvalue(p_format, p_va, flags);
+		if (w == NULL) {
+			itemfailed = 1;
+			Py_INCREF(Py_None);
+			w = Py_None;
+		}
+		PyList_SET_ITEM(v, i, w);
+	}
+
+	if (itemfailed) {
+		/* do_mkvalue() should have already set an error */
+		Py_DECREF(v);
+		return NULL;
+	}
+	if (**p_format != endchar) {
+		Py_DECREF(v);
+		PyErr_SetString(PyExc_SystemError,
+				"Unmatched paren in format");
+		return NULL;
+	}
+	if (endchar)
+		++*p_format;
+	return v;
+}
+
+#ifdef Py_USING_UNICODE
+static int
+_ustrlen(Py_UNICODE *u)
+{
+	int i = 0;
+	Py_UNICODE *v = u;
+	while (*v != 0) { i++; v++; } 
+	return i;
+}
+#endif
+
+static PyObject *
+do_mktuple(const char **p_format, va_list *p_va, int endchar, int n, int flags)
+{
+	PyObject *v;
+	int i;
+	int itemfailed = 0;
+	if (n < 0)
+		return NULL;
+	if ((v = PyTuple_New(n)) == NULL)
+		return NULL;
+	/* Note that we can't bail immediately on error as this will leak
+	   refcounts on any 'N' arguments. */
+	for (i = 0; i < n; i++) {
+		PyObject *w = do_mkvalue(p_format, p_va, flags);
+		if (w == NULL) {
+			itemfailed = 1;
+			Py_INCREF(Py_None);
+			w = Py_None;
+		}
+		PyTuple_SET_ITEM(v, i, w);
+	}
+	if (itemfailed) {
+		/* do_mkvalue() should have already set an error */
+		Py_DECREF(v);
+		return NULL;
+	}
+	if (**p_format != endchar) {
+		Py_DECREF(v);
+		PyErr_SetString(PyExc_SystemError,
+				"Unmatched paren in format");
+		return NULL;
+	}
+	if (endchar)
+		++*p_format;
+	return v;
+}
+
+static PyObject *
+do_mkvalue(const char **p_format, va_list *p_va, int flags)
+{
+	for (;;) {
+		switch (*(*p_format)++) {
+		case '(':
+			return do_mktuple(p_format, p_va, ')',
+					  countformat(*p_format, ')'), flags);
+
+		case '[':
+			return do_mklist(p_format, p_va, ']',
+					 countformat(*p_format, ']'), flags);
+
+		case '{':
+			return do_mkdict(p_format, p_va, '}',
+					 countformat(*p_format, '}'), flags);
+
+		case 'b':
+		case 'B':
+		case 'h':
+		case 'i':
+			return PyInt_FromLong((long)va_arg(*p_va, int));
+			
+		case 'H':
+			return PyInt_FromLong((long)va_arg(*p_va, unsigned int));
+
+		case 'I':
+		{
+      Py_FatalError("I unsupported so far");
+			//unsigned int n;
+			//n = va_arg(*p_va, unsigned int);
+			//if (n > (unsigned long)PyInt_GetMax())
+			//	return PyLong_FromUnsignedLong((unsigned long)n);
+			//else
+			//	return PyInt_FromLong(n);
+		}
+		
+		case 'n':
+#if SIZEOF_SIZE_T!=SIZEOF_LONG
+			return PyInt_FromSsize_t(va_arg(*p_va, Py_ssize_t));
+#endif
+			/* Fall through from 'n' to 'l' if Py_ssize_t is long */
+		case 'l':
+			return PyInt_FromLong(va_arg(*p_va, long));
+
+		case 'k':
+		{
+      Py_FatalError("Py_BuildValue k unsupported so far\n");
+			/* unsigned long n; */
+			/* n = va_arg(*p_va, unsigned long); */
+			/* if (n > (unsigned long)PyInt_GetMax()) */
+			/* 	return PyLong_FromUnsignedLong(n); */
+			/* else */
+			/* 	return PyInt_FromLong(n); */
+		}
+
+#ifdef HAVE_LONG_LONG
+		case 'L':
+      Py_FatalError("Py_BuildValue L unsupported for now\n");
+			//return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG));
+
+		case 'K':
+      Py_FatalError("Py_BuildValue K unsupported for now\n");
+			//return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG));
+#endif
+#ifdef Py_USING_UNICODE
+		case 'u':
+		{
+			PyObject *v;
+			Py_UNICODE *u = va_arg(*p_va, Py_UNICODE *);
+			Py_ssize_t n;	
+			if (**p_format == '#') {
+				++*p_format;
+				if (flags & FLAG_SIZE_T)
+					n = va_arg(*p_va, Py_ssize_t);
+				else
+					n = va_arg(*p_va, int);
+			}
+			else
+				n = -1;
+			if (u == NULL) {
+				v = Py_None;
+				Py_INCREF(v);
+			}
+			else {
+				if (n < 0)
+					n = _ustrlen(u);
+				v = PyUnicode_FromUnicode(u, n);
+			}
+			return v;
+		}
+#endif
+		case 'f':
+		case 'd':
+			return PyFloat_FromDouble(
+				(double)va_arg(*p_va, va_double));
+
+#ifndef WITHOUT_COMPLEX
+		case 'D':
+			return PyComplex_FromCComplex(
+				*((Py_complex *)va_arg(*p_va, Py_complex *)));
+#endif /* WITHOUT_COMPLEX */
+
+		case 'c':
+		{
+			char p[1];
+			p[0] = (char)va_arg(*p_va, int);
+			return PyString_FromStringAndSize(p, 1);
+		}
+
+		case 's':
+		case 'z':
+		{
+			PyObject *v;
+			char *str = va_arg(*p_va, char *);
+			Py_ssize_t n;
+			if (**p_format == '#') {
+				++*p_format;
+				if (flags & FLAG_SIZE_T)
+					n = va_arg(*p_va, Py_ssize_t);
+				else
+					n = va_arg(*p_va, int);
+			}
+			else
+				n = -1;
+			if (str == NULL) {
+				v = Py_None;
+				Py_INCREF(v);
+			}
+			else {
+				if (n < 0) {
+					size_t m = strlen(str);
+					if (m > PY_SSIZE_T_MAX) {
+						PyErr_SetString(PyExc_OverflowError,
+							"string too long for Python string");
+						return NULL;
+					}
+					n = (Py_ssize_t)m;
+				}
+				v = PyString_FromStringAndSize(str, n);
+			}
+			return v;
+		}
+
+		case 'N':
+		case 'S':
+		case 'O':
+		if (**p_format == '&') {
+			typedef PyObject *(*converter)(void *);
+			converter func = va_arg(*p_va, converter);
+			void *arg = va_arg(*p_va, void *);
+			++*p_format;
+			return (*func)(arg);
+		}
+		else {
+			PyObject *v;
+			v = va_arg(*p_va, PyObject *);
+			if (v != NULL) {
+				if (*(*p_format - 1) != 'N')
+					Py_INCREF(v);
+			}
+			else if (!PyErr_Occurred())
+				/* If a NULL was passed
+				 * because a call that should
+				 * have constructed a value
+				 * failed, that's OK, and we
+				 * pass the error on; but if
+				 * no error occurred it's not
+				 * clear that the caller knew
+				 * what she was doing. */
+				PyErr_SetString(PyExc_SystemError,
+					"NULL object passed to Py_BuildValue");
+			return v;
+		}
+
+		case ':':
+		case ',':
+		case ' ':
+		case '\t':
+			break;
+
+		default:
+			PyErr_SetString(PyExc_SystemError,
+				"bad format char passed to Py_BuildValue");
+			return NULL;
+
+		}
+	}
+}
+
+
+PyObject *
+Py_BuildValue(const char *format, ...)
+{
+	va_list va;
+	PyObject* retval;
+	va_start(va, format);
+	retval = va_build_value(format, va, 0);
+	va_end(va);
+	return retval;
+}
+
+PyObject *
+_Py_BuildValue_SizeT(const char *format, ...)
+{
+	va_list va;
+	PyObject* retval;
+	va_start(va, format);
+	retval = va_build_value(format, va, FLAG_SIZE_T);
+	va_end(va);
+	return retval;
+}
+
+PyObject *
+Py_VaBuildValue(const char *format, va_list va)
+{
+	return va_build_value(format, va, 0);
+}
+
+PyObject *
+_Py_VaBuildValue_SizeT(const char *format, va_list va)
+{
+	return va_build_value(format, va, FLAG_SIZE_T);
+}
+
+static PyObject *
+va_build_value(const char *format, va_list va, int flags)
+{
+	const char *f = format;
+	int n = countformat(f, '\0');
+	va_list lva;
+
+#ifdef VA_LIST_IS_ARRAY
+	memcpy(lva, va, sizeof(va_list));
+#else
+#ifdef __va_copy
+	__va_copy(lva, va);
+#else
+	lva = va;
+#endif
+#endif
+
+	if (n < 0)
+		return NULL;
+	if (n == 0) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+	if (n == 1)
+		return do_mkvalue(&f, &lva, flags);
+	return do_mktuple(&f, &lva, '\0', n, flags);
+}
+
+
+PyObject *
+PyEval_CallFunction(PyObject *obj, const char *format, ...)
+{
+	va_list vargs;
+	PyObject *args;
+	PyObject *res;
+
+	va_start(vargs, format);
+
+	args = Py_VaBuildValue(format, vargs);
+	va_end(vargs);
+
+	if (args == NULL)
+		return NULL;
+
+	res = PyEval_CallObject(obj, args);
+	Py_DECREF(args);
+
+	return res;
+}
+
+
+PyObject *
+PyEval_CallMethod(PyObject *obj, const char *methodname, const char *format, ...)
+{
+	va_list vargs;
+	PyObject *meth;
+	PyObject *args;
+	PyObject *res;
+
+	meth = PyObject_GetAttrString(obj, methodname);
+	if (meth == NULL)
+		return NULL;
+
+	va_start(vargs, format);
+
+	args = Py_VaBuildValue(format, vargs);
+	va_end(vargs);
+
+	if (args == NULL) {
+		Py_DECREF(meth);
+		return NULL;
+	}
+
+	res = PyEval_CallObject(meth, args);
+	Py_DECREF(meth);
+	Py_DECREF(args);
+
+	return res;
+}
 
 int
 PyModule_AddObject(PyObject *m, const char *name, PyObject *o)
@@ -29,3 +547,26 @@
 	return 0;
 }
 
+int 
+PyModule_AddIntConstant(PyObject *m, const char *name, long value)
+{
+	PyObject *o = PyInt_FromLong(value);
+	if (!o)
+		return -1;
+	if (PyModule_AddObject(m, name, o) == 0)
+		return 0;
+	Py_DECREF(o);
+	return -1;
+}
+
+int 
+PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
+{
+	PyObject *o = PyString_FromString(value);
+	if (!o)
+		return -1;
+	if (PyModule_AddObject(m, name, o) == 0)
+		return 0;
+	Py_DECREF(o);
+	return -1;
+}



More information about the Pypy-commit mailing list