[Python-checkins] r72487 - in python/trunk: Doc/c-api/code.rst Doc/c-api/concrete.rst Include/code.h Lib/test/test_code.py Misc/NEWS Modules/_ctypes/callbacks.c Modules/_testcapimodule.c Modules/pyexpat.c Objects/codeobject.c

jeffrey.yasskin python-checkins at python.org
Fri May 8 23:51:07 CEST 2009


Author: jeffrey.yasskin
Date: Fri May  8 23:51:06 2009
New Revision: 72487

Log:
PyCode_NewEmpty:
Most uses of PyCode_New found by http://www.google.com/codesearch?q=PyCode_New
are trying to build an empty code object, usually to put it in a dummy frame
object. This patch adds a PyCode_NewEmpty wrapper which lets the user specify
just the filename, function name, and first line number, instead of also
requiring lots of code internals.


Added:
   python/trunk/Doc/c-api/code.rst
Modified:
   python/trunk/Doc/c-api/concrete.rst
   python/trunk/Include/code.h
   python/trunk/Lib/test/test_code.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/_ctypes/callbacks.c
   python/trunk/Modules/_testcapimodule.c
   python/trunk/Modules/pyexpat.c
   python/trunk/Objects/codeobject.c

Added: python/trunk/Doc/c-api/code.rst
==============================================================================
--- (empty file)
+++ python/trunk/Doc/c-api/code.rst	Fri May  8 23:51:06 2009
@@ -0,0 +1,50 @@
+.. highlightlang:: c
+
+.. _codeobjects:
+
+Code Objects
+------------
+
+.. sectionauthor:: Jeffrey Yasskin <jyasskin at gmail.com>
+
+
+.. index::
+   object: code
+
+Code objects are a low-level detail of the CPython implementation.
+Each one represents a chunk of executable code that hasn't yet been
+bound into a function.
+
+.. ctype:: PyCodeObject
+
+   The C structure of the objects used to describe code objects.  The
+   fields of this type are subject to change at any time.
+
+
+.. cvar:: PyTypeObject PyCode_Type
+
+   This is an instance of :ctype:`PyTypeObject` representing the Python
+   :class:`code` type.
+
+
+.. cfunction:: int PyCode_Check(PyObject *co)
+
+   Return true if *co* is a :class:`code` object
+
+.. cfunction:: int PyCode_GetNumFree(PyObject *co)
+
+   Return the number of free variables in *co*.
+
+.. cfunction:: PyCodeObject *PyCode_New(int argcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
+
+   Return a new code object.  If you need a dummy code object to
+   create a frame, use :cfunc:`PyCode_NewEmpty` instead.  Calling
+   :cfunc:`PyCode_New` directly can bind you to a precise Python
+   version since the definition of the bytecode changes often.
+
+
+.. cfunction:: int PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
+
+   Return a new empty code object with the specified filename,
+   function name, and first line number.  It is illegal to
+   :keyword:`exec` or :func:`eval` the resulting code object.

Modified: python/trunk/Doc/c-api/concrete.rst
==============================================================================
--- python/trunk/Doc/c-api/concrete.rst	(original)
+++ python/trunk/Doc/c-api/concrete.rst	Fri May  8 23:51:06 2009
@@ -105,3 +105,4 @@
    gen.rst
    datetime.rst
    set.rst
+   code.rst

Modified: python/trunk/Include/code.h
==============================================================================
--- python/trunk/Include/code.h	(original)
+++ python/trunk/Include/code.h	Fri May  8 23:51:06 2009
@@ -70,6 +70,11 @@
 	int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *,
 	PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *); 
         /* same as struct above */
+
+/* Creates a new empty code object with the specified source location. */
+PyAPI_FUNC(PyCodeObject *)
+PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno);
+
 PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
 
 /* for internal use only */

Modified: python/trunk/Lib/test/test_code.py
==============================================================================
--- python/trunk/Lib/test/test_code.py	(original)
+++ python/trunk/Lib/test/test_code.py	Fri May  8 23:51:06 2009
@@ -80,6 +80,9 @@
 
 """
 
+import unittest
+import _testcapi
+
 def consts(t):
     """Yield a doctest-safe sequence of object reprs."""
     for elt in t:
@@ -96,10 +99,21 @@
         print "%s: %s" % (attr, getattr(co, "co_" + attr))
     print "consts:", tuple(consts(co.co_consts))
 
+
+class CodeTest(unittest.TestCase):
+
+    def test_newempty(self):
+        co = _testcapi.code_newempty("filename", "funcname", 15)
+        self.assertEquals(co.co_filename, "filename")
+        self.assertEquals(co.co_name, "funcname")
+        self.assertEquals(co.co_firstlineno, 15)
+
+
 def test_main(verbose=None):
-    from test.test_support import run_doctest
+    from test.test_support import run_doctest, run_unittest
     from test import test_code
     run_doctest(test_code, verbose)
+    run_unittest(CodeTest)
 
 
 if __name__ == '__main__':

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Fri May  8 23:51:06 2009
@@ -927,6 +927,9 @@
 C-API
 -----
 
+- Issue #5959: Add a PyCode_NewEmpty() function to create a new empty code
+  object at a specified file, function, and line number.
+
 - Issue #1419652: Change the first argument to PyImport_AppendInittab() to
   ``const char *`` as the string is stored beyond the call.
 

Modified: python/trunk/Modules/_ctypes/callbacks.c
==============================================================================
--- python/trunk/Modules/_ctypes/callbacks.c	(original)
+++ python/trunk/Modules/_ctypes/callbacks.c	Fri May  8 23:51:06 2009
@@ -99,40 +99,13 @@
 /* after code that pyrex generates */
 void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
 {
-	PyObject *py_srcfile = 0;
-	PyObject *py_funcname = 0;
 	PyObject *py_globals = 0;
-	PyObject *empty_tuple = 0;
-	PyObject *empty_string = 0;
 	PyCodeObject *py_code = 0;
 	PyFrameObject *py_frame = 0;
-    
-	py_srcfile = PyString_FromString(filename);
-	if (!py_srcfile) goto bad;
-	py_funcname = PyString_FromString(funcname);
-	if (!py_funcname) goto bad;
+
 	py_globals = PyDict_New();
 	if (!py_globals) goto bad;
-	empty_tuple = PyTuple_New(0);
-	if (!empty_tuple) goto bad;
-	empty_string = PyString_FromString("");
-	if (!empty_string) goto bad;
-	py_code = PyCode_New(
-		0,            /*int argcount,*/
-		0,            /*int nlocals,*/
-		0,            /*int stacksize,*/
-		0,            /*int flags,*/
-		empty_string, /*PyObject *code,*/
-		empty_tuple,  /*PyObject *consts,*/
-		empty_tuple,  /*PyObject *names,*/
-		empty_tuple,  /*PyObject *varnames,*/
-		empty_tuple,  /*PyObject *freevars,*/
-		empty_tuple,  /*PyObject *cellvars,*/
-		py_srcfile,   /*PyObject *filename,*/
-		py_funcname,  /*PyObject *name,*/
-		lineno,   /*int firstlineno,*/
-		empty_string  /*PyObject *lnotab*/
-		);
+	py_code = PyCode_NewEmpty(filename, funcname, lineno);
 	if (!py_code) goto bad;
 	py_frame = PyFrame_New(
 		PyThreadState_Get(), /*PyThreadState *tstate,*/
@@ -145,10 +118,6 @@
 	PyTraceBack_Here(py_frame);
   bad:
 	Py_XDECREF(py_globals);
-	Py_XDECREF(py_srcfile);
-	Py_XDECREF(py_funcname);
-	Py_XDECREF(empty_tuple);
-	Py_XDECREF(empty_string);
 	Py_XDECREF(py_code);
 	Py_XDECREF(py_frame);
 }

Modified: python/trunk/Modules/_testcapimodule.c
==============================================================================
--- python/trunk/Modules/_testcapimodule.c	(original)
+++ python/trunk/Modules/_testcapimodule.c	Fri May  8 23:51:06 2009
@@ -988,6 +988,21 @@
 	Py_RETURN_NONE;
 }
 
+/* To test that the result of PyCode_NewEmpty has the right members. */
+static PyObject *
+code_newempty(PyObject *self, PyObject *args)
+{
+	const char *filename;
+	const char *funcname;
+        int firstlineno;
+
+	if (!PyArg_ParseTuple(args, "ssi:code_newempty",
+			      &filename, &funcname, &firstlineno))
+		return NULL;
+
+	return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno);
+}
+
 static PyMethodDef TestMethods[] = {
 	{"raise_exception",	raise_exception,		 METH_VARARGS},
 	{"test_config",		(PyCFunction)test_config,	 METH_NOARGS},
@@ -1033,6 +1048,7 @@
 	{"_pending_threadfunc",	pending_threadfunc,		 METH_VARARGS},
 #endif
 	{"traceback_print", traceback_print, 	         METH_VARARGS},
+	{"code_newempty", code_newempty, 	         METH_VARARGS},
 	{NULL, NULL} /* sentinel */
 };
 

Modified: python/trunk/Modules/pyexpat.c
==============================================================================
--- python/trunk/Modules/pyexpat.c	(original)
+++ python/trunk/Modules/pyexpat.c	Fri May  8 23:51:06 2009
@@ -261,52 +261,11 @@
 static PyCodeObject*
 getcode(enum HandlerTypes slot, char* func_name, int lineno)
 {
-    PyObject *code = NULL;
-    PyObject *name = NULL;
-    PyObject *nulltuple = NULL;
-    PyObject *filename = NULL;
-
     if (handler_info[slot].tb_code == NULL) {
-        code = PyString_FromString("");
-        if (code == NULL)
-            goto failed;
-        name = PyString_FromString(func_name);
-        if (name == NULL)
-            goto failed;
-        nulltuple = PyTuple_New(0);
-        if (nulltuple == NULL)
-            goto failed;
-        filename = PyString_FromString(__FILE__);
         handler_info[slot].tb_code =
-            PyCode_New(0,		/* argcount */
-                       0,		/* nlocals */
-                       0,		/* stacksize */
-                       0,		/* flags */
-                       code,		/* code */
-                       nulltuple,	/* consts */
-                       nulltuple,	/* names */
-                       nulltuple,	/* varnames */
-#if PYTHON_API_VERSION >= 1010
-                       nulltuple,	/* freevars */
-                       nulltuple,	/* cellvars */
-#endif
-                       filename,	/* filename */
-                       name,		/* name */
-                       lineno,		/* firstlineno */
-                       code		/* lnotab */
-                       );
-        if (handler_info[slot].tb_code == NULL)
-            goto failed;
-        Py_DECREF(code);
-        Py_DECREF(nulltuple);
-        Py_DECREF(filename);
-        Py_DECREF(name);
+            PyCode_NewEmpty(__FILE__, func_name, lineno);
     }
     return handler_info[slot].tb_code;
- failed:
-    Py_XDECREF(code);
-    Py_XDECREF(name);
-    return NULL;
 }
 
 #ifdef FIX_TRACE

Modified: python/trunk/Objects/codeobject.c
==============================================================================
--- python/trunk/Objects/codeobject.c	(original)
+++ python/trunk/Objects/codeobject.c	Fri May  8 23:51:06 2009
@@ -107,6 +107,52 @@
 	return co;
 }
 
+PyCodeObject *
+PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
+{
+	static PyObject *emptystring = NULL;
+	static PyObject *nulltuple = NULL;
+	PyObject *filename_ob = NULL;
+	PyObject *funcname_ob = NULL;
+	PyCodeObject *result = NULL;
+	if (emptystring == NULL) {
+		emptystring = PyString_FromString("");
+		if (emptystring == NULL)
+			goto failed;
+	}
+	if (nulltuple == NULL) {
+		nulltuple = PyTuple_New(0);
+		if (nulltuple == NULL)
+			goto failed;
+	}
+	funcname_ob = PyString_FromString(funcname);
+	if (funcname_ob == NULL)
+		goto failed;
+	filename_ob = PyString_FromString(filename);
+	if (filename_ob == NULL)
+		goto failed;
+
+	result = PyCode_New(0,			/* argcount */
+			    0,			/* nlocals */
+			    0,			/* stacksize */
+			    0,			/* flags */
+			    emptystring,	/* code */
+			    nulltuple,		/* consts */
+			    nulltuple,		/* names */
+			    nulltuple,		/* varnames */
+			    nulltuple,		/* freevars */
+			    nulltuple,		/* cellvars */
+			    filename_ob,	/* filename */
+			    funcname_ob,	/* name */
+			    firstlineno,	/* firstlineno */
+			    emptystring		/* lnotab */
+			    );
+
+failed:
+	Py_XDECREF(funcname_ob);
+	Py_XDECREF(filename_ob);
+	return result;
+}
 
 #define OFF(x) offsetof(PyCodeObject, x)
 


More information about the Python-checkins mailing list