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:
parent
083d1f9f9a
commit
1aa4700234
|
@ -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.
|
|
@ -105,3 +105,4 @@ Other Objects
|
|||
gen.rst
|
||||
datetime.rst
|
||||
set.rst
|
||||
code.rst
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue