| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 6f82818 commit 7b82b40
18 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,50 @@ | |||
| 1 | + .. highlightlang:: c | ||
| 2 | + | ||
| 3 | + .. _codeobjects: | ||
| 4 | + | ||
| 5 | + Code Objects | ||
| 6 | + ------------ | ||
| 7 | + | ||
| 8 | + .. sectionauthor:: Jeffrey Yasskin <jyasskin@gmail.com> | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + .. index:: | ||
| 12 | + object: code | ||
| 13 | + | ||
| 14 | + Code objects are a low-level detail of the CPython implementation. | ||
| 15 | + Each one represents a chunk of executable code that hasn't yet been | ||
| 16 | + bound into a function. | ||
| 17 | + | ||
| 18 | + .. ctype:: PyCodeObject | ||
| 19 | + | ||
| 20 | + The C structure of the objects used to describe code objects. The | ||
| 21 | + fields of this type are subject to change at any time. | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + .. cvar:: PyTypeObject PyCode_Type | ||
| 25 | + | ||
| 26 | + This is an instance of :ctype:`PyTypeObject` representing the Python | ||
| 27 | + :class:`code` type. | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + .. cfunction:: int PyCode_Check(PyObject *co) | ||
| 31 | + | ||
| 32 | + Return true if *co* is a :class:`code` object | ||
| 33 | + | ||
| 34 | + .. cfunction:: int PyCode_GetNumFree(PyObject *co) | ||
| 35 | + | ||
| 36 | + Return the number of free variables in *co*. | ||
| 37 | + | ||
| 38 | + .. 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) | ||
| 39 | + | ||
| 40 | + Return a new code object. If you need a dummy code object to | ||
| 41 | + create a frame, use :cfunc:`PyCode_NewEmpty` instead. Calling | ||
| 42 | + :cfunc:`PyCode_New` directly can bind you to a precise Python | ||
| 43 | + version since the definition of the bytecode changes often. | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + .. cfunction:: int PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) | ||
| 47 | + | ||
| 48 | + Return a new empty code object with the specified filename, | ||
| 49 | + function name, and first line number. It is illegal to | ||
| 50 | + :keyword:`exec` or :func:`eval` the resulting code object. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -105,3 +105,4 @@ Other Objects | |||
| 105 | 105 | cell.rst | |
| 106 | 106 | gen.rst | |
| 107 | 107 | datetime.rst | |
| 108 | + code.rst | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,6 +29,11 @@ Reflection | |||
| 29 | 29 | currently executing. | |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | + .. cfunction:: int PyFrame_GetLineNumber(PyFrameObject *frame) | ||
| 33 | + | ||
| 34 | + Return the line number that *frame* is currently executing. | ||
| 35 | + | ||
| 36 | + | ||
| 32 | 37 | .. cfunction:: int PyEval_GetRestricted() | |
| 33 | 38 | ||
| 34 | 39 | If there is a current frame and it is executing in restricted mode, return true, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -720,9 +720,11 @@ always available. | |||
| 720 | 720 | specifies the local trace function. | |
| 721 | 721 | ||
| 722 | 722 | ``'line'`` | |
| 723 | - The interpreter is about to execute a new line of code (sometimes multiple | ||
| 724 | - line events on one line exist). The local trace function is called; *arg* | ||
| 725 | - is ``None``; the return value specifies the new local trace function. | ||
| 723 | + The interpreter is about to execute a new line of code or re-execute the | ||
| 724 | + condition of a loop. The local trace function is called; *arg* is | ||
| 725 | + ``None``; the return value specifies the new local trace function. See | ||
| 726 | + :file:`Objects/lnotab_notes.txt` for a detailed explanation of how this | ||
| 727 | + works. | ||
| 726 | 728 | ||
| 727 | 729 | ``'return'`` | |
| 728 | 730 | A function (or other code block) is about to return. The local trace | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,7 +24,8 @@ typedef struct { | |||
| 24 | 24 | PyObject *co_filename; /* unicode (where it was loaded from) */ | |
| 25 | 25 | PyObject *co_name; /* unicode (name, for reference) */ | |
| 26 | 26 | int co_firstlineno; /* first source line number */ | |
| 27 | - PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ | ||
| 27 | + PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See | ||
| 28 | + Objects/lnotab_notes.txt for details. */ | ||
| 28 | 29 | void *co_zombieframe; /* for optimization only (see frameobject.c) */ | |
| 29 | 30 | } PyCodeObject; | |
| 30 | 31 | ||
@@ -72,6 +73,14 @@ PyAPI_FUNC(PyCodeObject *) PyCode_New( | |||
| 72 | 73 | PyObject *, PyObject *, PyObject *, PyObject *, | |
| 73 | 74 | PyObject *, PyObject *, int, PyObject *); | |
| 74 | 75 | /* same as struct above */ | |
| 76 | + | ||
| 77 | + /* Creates a new empty code object with the specified source location. */ | ||
| 78 | + PyAPI_FUNC(PyCodeObject *) | ||
| 79 | + PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno); | ||
| 80 | + | ||
| 81 | + /* Return the line number associated with the specified bytecode index | ||
| 82 | + in this code object. If you just need the line number of a frame, | ||
| 83 | + use PyFrame_GetLineNumber() instead. */ | ||
| 75 | 84 | PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); | |
| 76 | 85 | ||
| 77 | 86 | /* for internal use only */ | |
@@ -80,15 +89,11 @@ typedef struct _addr_pair { | |||
| 80 | 89 | int ap_upper; | |
| 81 | 90 | } PyAddrPair; | |
| 82 | 91 | ||
| 83 | - /* Check whether lasti (an instruction offset) falls outside bounds | ||
| 84 | - and whether it is a line number that should be traced. Returns | ||
| 85 | - a line number if it should be traced or -1 if the line should not. | ||
| 86 | - | ||
| 87 | - If lasti is not within bounds, updates bounds. | ||
| 92 | + /* Update *bounds to describe the first and one-past-the-last instructions in the | ||
| 93 | + same line as lasti. Return the number of that line. | ||
| 88 | 94 | */ | |
| 89 | - | ||
| 90 | - PyAPI_FUNC(int) PyCode_CheckLineNumber(PyCodeObject* co, | ||
| 91 | - int lasti, PyAddrPair *bounds); | ||
| 95 | + PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co, | ||
| 96 | + int lasti, PyAddrPair *bounds); | ||
| 92 | 97 | ||
| 93 | 98 | PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, | |
| 94 | 99 | PyObject *names, PyObject *lineno_obj); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -38,8 +38,11 @@ typedef struct _frame { | |||
| 38 | 38 | ||
| 39 | 39 | PyThreadState *f_tstate; | |
| 40 | 40 | int f_lasti; /* Last instruction if called */ | |
| 41 | - /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when | ||
| 42 | - f_trace is set) -- at other times use PyCode_Addr2Line instead. */ | ||
| 41 | + /* Call PyFrame_GetLineNumber() instead of reading this field | ||
| 42 | + directly. As of 2.3 f_lineno is only valid when tracing is | ||
| 43 | + active (i.e. when f_trace is set). At other times we use | ||
| 44 | + PyCode_Addr2Line to calculate the line from the current | ||
| 45 | + bytecode index. */ | ||
| 43 | 46 | int f_lineno; /* Current line number */ | |
| 44 | 47 | int f_iblock; /* index in f_blockstack */ | |
| 45 | 48 | PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ | |
@@ -75,6 +78,9 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); | |||
| 75 | 78 | ||
| 76 | 79 | PyAPI_FUNC(int) PyFrame_ClearFreeList(void); | |
| 77 | 80 | ||
| 81 | + /* Return the line of code the frame is currently executing. */ | ||
| 82 | + PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); | ||
| 83 | + | ||
| 78 | 84 | #ifdef __cplusplus | |
| 79 | 85 | } | |
| 80 | 86 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -102,6 +102,9 @@ | |||
| 102 | 102 | ||
| 103 | 103 | """ | |
| 104 | 104 | ||
| 105 | + import unittest | ||
| 106 | + import _testcapi | ||
| 107 | + | ||
| 105 | 108 | def consts(t): | |
| 106 | 109 | """Yield a doctest-safe sequence of object reprs.""" | |
| 107 | 110 | for elt in t: | |
@@ -118,10 +121,21 @@ def dump(co): | |||
| 118 | 121 | print("%s: %s" % (attr, getattr(co, "co_" + attr))) | |
| 119 | 122 | print("consts:", tuple(consts(co.co_consts))) | |
| 120 | 123 | ||
| 124 | + | ||
| 125 | + class CodeTest(unittest.TestCase): | ||
| 126 | + | ||
| 127 | + def test_newempty(self): | ||
| 128 | + co = _testcapi.code_newempty("filename", "funcname", 15) | ||
| 129 | + self.assertEquals(co.co_filename, "filename") | ||
| 130 | + self.assertEquals(co.co_name, "funcname") | ||
| 131 | + self.assertEquals(co.co_firstlineno, 15) | ||
| 132 | + | ||
| 133 | + | ||
| 121 | 134 | def test_main(verbose=None): | |
| 122 | - from test.support import run_doctest | ||
| 135 | + from test.support import run_doctest, run_unittest | ||
| 123 | 136 | from test import test_code | |
| 124 | 137 | run_doctest(test_code, verbose) | |
| 138 | + run_unittest(CodeTest) | ||
| 125 | 139 | ||
| 126 | 140 | ||
| 127 | 141 | if __name__ == '__main__': | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -40,6 +40,15 @@ C-API | |||
| 40 | 40 | ||
| 41 | 41 | - The code flags for old __future__ features are now available again. | |
| 42 | 42 | ||
| 43 | + - Issue #5954: Add a PyFrame_GetLineNumber() function to replace most uses of | ||
| 44 | + PyCode_Addr2Line(). | ||
| 45 | + | ||
| 46 | + - Issue #5959: Add a PyCode_NewEmpty() function to create a new empty code | ||
| 47 | + object at a specified file, function, and line number. | ||
| 48 | + | ||
| 49 | + - Issue #1419652: Change the first argument to PyImport_AppendInittab() to | ||
| 50 | + ``const char *`` as the string is stored beyond the call. | ||
| 51 | + | ||
| 43 | 52 | Library | |
| 44 | 53 | ------- | |
| 45 | 54 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -94,41 +94,13 @@ PrintError(char *msg, ...) | |||
| 94 | 94 | /* after code that pyrex generates */ | |
| 95 | 95 | void _ctypes_add_traceback(char *funcname, char *filename, int lineno) | |
| 96 | 96 | { | |
| 97 | - PyObject *py_srcfile = 0; | ||
| 98 | - PyObject *py_funcname = 0; | ||
| 99 | 97 | PyObject *py_globals = 0; | |
| 100 | - PyObject *empty_tuple = 0; | ||
| 101 | - PyObject *empty_string = 0; | ||
| 102 | 98 | PyCodeObject *py_code = 0; | |
| 103 | 99 | PyFrameObject *py_frame = 0; | |
| 104 | 100 | ||
| 105 | - py_srcfile = PyUnicode_DecodeFSDefault(filename); | ||
| 106 | - if (!py_srcfile) goto bad; | ||
| 107 | - py_funcname = PyUnicode_FromString(funcname); | ||
| 108 | - if (!py_funcname) goto bad; | ||
| 109 | 101 | py_globals = PyDict_New(); | |
| 110 | 102 | if (!py_globals) goto bad; | |
| 111 | - empty_tuple = PyTuple_New(0); | ||
| 112 | - if (!empty_tuple) goto bad; | ||
| 113 | - empty_string = PyBytes_FromString(""); | ||
| 114 | - if (!empty_string) goto bad; | ||
| 115 | - py_code = PyCode_New( | ||
| 116 | - 0, /*int argcount,*/ | ||
| 117 | - 0, /*int kwonlyargcount,*/ | ||
| 118 | - 0, /*int nlocals,*/ | ||
| 119 | - 0, /*int stacksize,*/ | ||
| 120 | - 0, /*int flags,*/ | ||
| 121 | - empty_string, /*PyObject *code,*/ | ||
| 122 | - empty_tuple, /*PyObject *consts,*/ | ||
| 123 | - empty_tuple, /*PyObject *names,*/ | ||
| 124 | - empty_tuple, /*PyObject *varnames,*/ | ||
| 125 | - empty_tuple, /*PyObject *freevars,*/ | ||
| 126 | - empty_tuple, /*PyObject *cellvars,*/ | ||
| 127 | - py_srcfile, /*PyObject *filename,*/ | ||
| 128 | - py_funcname, /*PyObject *name,*/ | ||
| 129 | - lineno, /*int firstlineno,*/ | ||
| 130 | - empty_string /*PyObject *lnotab*/ | ||
| 131 | - ); | ||
| 103 | + py_code = PyCode_NewEmpty(filename, funcname, lineno); | ||
| 132 | 104 | if (!py_code) goto bad; | |
| 133 | 105 | py_frame = PyFrame_New( | |
| 134 | 106 | PyThreadState_Get(), /*PyThreadState *tstate,*/ | |
@@ -141,10 +113,6 @@ void _ctypes_add_traceback(char *funcname, char *filename, int lineno) | |||
| 141 | 113 | PyTraceBack_Here(py_frame); | |
| 142 | 114 | bad: | |
| 143 | 115 | Py_XDECREF(py_globals); | |
| 144 | - Py_XDECREF(py_srcfile); | ||
| 145 | - Py_XDECREF(py_funcname); | ||
| 146 | - Py_XDECREF(empty_tuple); | ||
| 147 | - Py_XDECREF(empty_string); | ||
| 148 | 116 | Py_XDECREF(py_code); | |
| 149 | 117 | Py_XDECREF(py_frame); | |
| 150 | 118 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1446,6 +1446,21 @@ argparsing(PyObject *o, PyObject *args) | |||
| 1446 | 1446 | Py_RETURN_NONE; | |
| 1447 | 1447 | } | |
| 1448 | 1448 | ||
| 1449 | + /* To test that the result of PyCode_NewEmpty has the right members. */ | ||
| 1450 | + static PyObject * | ||
| 1451 | + code_newempty(PyObject *self, PyObject *args) | ||
| 1452 | + { | ||
| 1453 | + const char *filename; | ||
| 1454 | + const char *funcname; | ||
| 1455 | + int firstlineno; | ||
| 1456 | + | ||
| 1457 | + if (!PyArg_ParseTuple(args, "ssi:code_newempty", | ||
| 1458 | + &filename, &funcname, &firstlineno)) | ||
| 1459 | + return NULL; | ||
| 1460 | + | ||
| 1461 | + return (PyObject *)PyCode_NewEmpty(filename, funcname, firstlineno); | ||
| 1462 | + } | ||
| 1463 | + | ||
| 1449 | 1464 | static PyMethodDef TestMethods[] = { | |
| 1450 | 1465 | {"raise_exception", raise_exception, METH_VARARGS}, | |
| 1451 | 1466 | {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, | |
@@ -1498,6 +1513,7 @@ static PyMethodDef TestMethods[] = { | |||
| 1498 | 1513 | {"traceback_print", traceback_print, METH_VARARGS}, | |
| 1499 | 1514 | {"exception_print", exception_print, METH_VARARGS}, | |
| 1500 | 1515 | {"argparsing", argparsing, METH_VARARGS}, | |
| 1516 | + {"code_newempty", code_newempty, METH_VARARGS}, | ||
| 1501 | 1517 | {NULL, NULL} /* sentinel */ | |
| 1502 | 1518 | }; | |
| 1503 | 1519 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments