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.
This commit is contained in:
Jeffrey Yasskin 2009-05-08 21:51:06 +00:00
parent 083d1f9f9a
commit 1aa4700234
9 changed files with 139 additions and 76 deletions

50
Doc/c-api/code.rst Normal file
View File

@ -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.

View File

@ -105,3 +105,4 @@ Other Objects
gen.rst
datetime.rst
set.rst
code.rst

View 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 */

View 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__':

View File

@ -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.

View 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);
}

View 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 */
};

View 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

View 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)