mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
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
9 changed files with 139 additions and 76 deletions
50
Doc/c-api/code.rst
Normal file
50
Doc/c-api/code.rst
Normal 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.
|
|
@ -105,3 +105,4 @@ Other Objects
|
||||||
gen.rst
|
gen.rst
|
||||||
datetime.rst
|
datetime.rst
|
||||||
set.rst
|
set.rst
|
||||||
|
code.rst
|
||||||
|
|
|
@ -70,6 +70,11 @@ PyAPI_FUNC(PyCodeObject *) PyCode_New(
|
||||||
int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *,
|
int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *);
|
PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *);
|
||||||
/* same as struct above */
|
/* 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);
|
PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
|
||||||
|
|
||||||
/* for internal use only */
|
/* for internal use only */
|
||||||
|
|
|
@ -80,6 +80,9 @@ consts: ("'doc string'", 'None')
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import _testcapi
|
||||||
|
|
||||||
def consts(t):
|
def consts(t):
|
||||||
"""Yield a doctest-safe sequence of object reprs."""
|
"""Yield a doctest-safe sequence of object reprs."""
|
||||||
for elt in t:
|
for elt in t:
|
||||||
|
@ -96,10 +99,21 @@ def dump(co):
|
||||||
print "%s: %s" % (attr, getattr(co, "co_" + attr))
|
print "%s: %s" % (attr, getattr(co, "co_" + attr))
|
||||||
print "consts:", tuple(consts(co.co_consts))
|
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):
|
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
|
from test import test_code
|
||||||
run_doctest(test_code, verbose)
|
run_doctest(test_code, verbose)
|
||||||
|
run_unittest(CodeTest)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -927,6 +927,9 @@ Build
|
||||||
C-API
|
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
|
- Issue #1419652: Change the first argument to PyImport_AppendInittab() to
|
||||||
``const char *`` as the string is stored beyond the call.
|
``const char *`` as the string is stored beyond the call.
|
||||||
|
|
||||||
|
|
|
@ -99,40 +99,13 @@ PrintError(char *msg, ...)
|
||||||
/* after code that pyrex generates */
|
/* after code that pyrex generates */
|
||||||
void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
|
void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
|
||||||
{
|
{
|
||||||
PyObject *py_srcfile = 0;
|
|
||||||
PyObject *py_funcname = 0;
|
|
||||||
PyObject *py_globals = 0;
|
PyObject *py_globals = 0;
|
||||||
PyObject *empty_tuple = 0;
|
|
||||||
PyObject *empty_string = 0;
|
|
||||||
PyCodeObject *py_code = 0;
|
PyCodeObject *py_code = 0;
|
||||||
PyFrameObject *py_frame = 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();
|
py_globals = PyDict_New();
|
||||||
if (!py_globals) goto bad;
|
if (!py_globals) goto bad;
|
||||||
empty_tuple = PyTuple_New(0);
|
py_code = PyCode_NewEmpty(filename, funcname, lineno);
|
||||||
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*/
|
|
||||||
);
|
|
||||||
if (!py_code) goto bad;
|
if (!py_code) goto bad;
|
||||||
py_frame = PyFrame_New(
|
py_frame = PyFrame_New(
|
||||||
PyThreadState_Get(), /*PyThreadState *tstate,*/
|
PyThreadState_Get(), /*PyThreadState *tstate,*/
|
||||||
|
@ -145,10 +118,6 @@ void _ctypes_add_traceback(char *funcname, char *filename, int lineno)
|
||||||
PyTraceBack_Here(py_frame);
|
PyTraceBack_Here(py_frame);
|
||||||
bad:
|
bad:
|
||||||
Py_XDECREF(py_globals);
|
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_code);
|
||||||
Py_XDECREF(py_frame);
|
Py_XDECREF(py_frame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -988,6 +988,21 @@ traceback_print(PyObject *self, PyObject *args)
|
||||||
Py_RETURN_NONE;
|
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[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"raise_exception", raise_exception, METH_VARARGS},
|
{"raise_exception", raise_exception, METH_VARARGS},
|
||||||
{"test_config", (PyCFunction)test_config, METH_NOARGS},
|
{"test_config", (PyCFunction)test_config, METH_NOARGS},
|
||||||
|
@ -1033,6 +1048,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},
|
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},
|
||||||
#endif
|
#endif
|
||||||
{"traceback_print", traceback_print, METH_VARARGS},
|
{"traceback_print", traceback_print, METH_VARARGS},
|
||||||
|
{"code_newempty", code_newempty, METH_VARARGS},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -261,52 +261,11 @@ flag_error(xmlparseobject *self)
|
||||||
static PyCodeObject*
|
static PyCodeObject*
|
||||||
getcode(enum HandlerTypes slot, char* func_name, int lineno)
|
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) {
|
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 =
|
handler_info[slot].tb_code =
|
||||||
PyCode_New(0, /* argcount */
|
PyCode_NewEmpty(__FILE__, func_name, lineno);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
return handler_info[slot].tb_code;
|
return handler_info[slot].tb_code;
|
||||||
failed:
|
|
||||||
Py_XDECREF(code);
|
|
||||||
Py_XDECREF(name);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FIX_TRACE
|
#ifdef FIX_TRACE
|
||||||
|
|
|
@ -107,6 +107,52 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
|
||||||
return co;
|
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)
|
#define OFF(x) offsetof(PyCodeObject, x)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue