]> granicus.if.org Git - python/commitdiff
PyCode_NewEmpty:
authorJeffrey Yasskin <jyasskin@gmail.com>
Fri, 8 May 2009 21:51:06 +0000 (21:51 +0000)
committerJeffrey Yasskin <jyasskin@gmail.com>
Fri, 8 May 2009 21:51:06 +0000 (21:51 +0000)
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.

Doc/c-api/code.rst [new file with mode: 0644]
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

diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst
new file mode 100644 (file)
index 0000000..c6ca8c5
--- /dev/null
@@ -0,0 +1,50 @@
+.. highlightlang:: c
+
+.. _codeobjects:
+
+Code Objects
+------------
+
+.. sectionauthor:: Jeffrey Yasskin <jyasskin@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.
index 6958646c18cd1c2ebac38fd2847c1e45e74b6fef..05957884fcf391e042af2376d06e79d0de47abbc 100644 (file)
@@ -105,3 +105,4 @@ Other Objects
    gen.rst
    datetime.rst
    set.rst
+   code.rst
index 8c00700a89bc74cfc82c05e89ee3b1d921bd739c..0167ad4a878d2dfa98a1bfb918cd35ec23574328 100644 (file)
@@ -70,6 +70,11 @@ PyAPI_FUNC(PyCodeObject *) PyCode_New(
        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 */
index b69223d190d75f6a3ea42d4be814a3373d4bb15e..4a88e60d1d91ee054470c674a18dbb2ded242738 100644 (file)
@@ -80,6 +80,9 @@ consts: ("'doc string'", 'None')
 
 """
 
+import unittest
+import _testcapi
+
 def consts(t):
     """Yield a doctest-safe sequence of object reprs."""
     for elt in t:
@@ -96,10 +99,21 @@ def dump(co):
         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__':
index e097b43c841d891def2d6426526e88a95e81d29f..ba721e729e4698ff0d6ec62c4c19e9b7457c2e01 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -927,6 +927,9 @@ Build
 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.
 
index 1720169431ab08607c7eab15e8ba2105f2caef6c..c7bfa21b832ca916dbea6f5898d3e581b3451e0c 100644 (file)
@@ -99,40 +99,13 @@ PrintError(char *msg, ...)
 /* 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 @@ void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
        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);
 }
index 0cccca3c2fdd52c1c9b8cb9b2b825f7f1b834177..fb5cf732e2bd2fff7936899a3c119f3bba4851fb 100644 (file)
@@ -988,6 +988,21 @@ traceback_print(PyObject *self, PyObject *args)
        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 @@ static PyMethodDef TestMethods[] = {
        {"_pending_threadfunc", pending_threadfunc,              METH_VARARGS},
 #endif
        {"traceback_print", traceback_print,             METH_VARARGS},
+       {"code_newempty", code_newempty,                 METH_VARARGS},
        {NULL, NULL} /* sentinel */
 };
 
index 01971b78ed91de65f4fb66dcaf613a721a9ad801..47ef186bc234bcca82f55289c78f3bbfc46929fd 100644 (file)
@@ -261,52 +261,11 @@ flag_error(xmlparseobject *self)
 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
index e94b4cc85b1f5feb0f1fa09a8bc34b32b0e0018d..55f3fb85154d14794c513399631a5a2f780ad1a3 100644 (file)
@@ -107,6 +107,52 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
        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)