Skip to content

Commit 182c512

Browse files
committed
Add test for co_branches
1 parent 76b9b3e commit 182c512

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

Lib/test/test_code.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@
215215
from test.support import threading_helper, import_helper
216216
from test.support.bytecode_helper import instructions_with_positions
217217
from opcode import opmap, opname
218+
from _testcapi import code_offset_to_line
219+
218220
COPY_FREE_VARS = opmap['COPY_FREE_VARS']
219221

220222

@@ -896,6 +898,44 @@ async def async_func():
896898

897899
rc, out, err = assert_python_ok('-OO', '-c', code)
898900

901+
def test_co_branches(self):
902+
903+
def get_line_branches(func):
904+
code = func.__code__
905+
base = code.co_firstlineno
906+
return [
907+
(
908+
code_offset_to_line(code, src)-base,
909+
code_offset_to_line(code, left)-base,
910+
code_offset_to_line(code, right)-base
911+
) for (src, left, right) in
912+
code.co_branches()
913+
]
914+
915+
def simple(x):
916+
if x:
917+
A
918+
else:
919+
B
920+
921+
self.assertEqual(
922+
get_line_branches(simple),
923+
[(1,2,4)])
924+
925+
def with_extended_args(x):
926+
if x:
927+
A.x; A.x; A.x; A.x; A.x; A.x;
928+
A.x; A.x; A.x; A.x; A.x; A.x;
929+
A.x; A.x; A.x; A.x; A.x; A.x;
930+
A.x; A.x; A.x; A.x; A.x; A.x;
931+
A.x; A.x; A.x; A.x; A.x; A.x;
932+
else:
933+
B
934+
935+
self.assertEqual(
936+
get_line_branches(with_extended_args),
937+
[(1,2,8)])
938+
899939
if check_impl_detail(cpython=True) and ctypes is not None:
900940
py = ctypes.pythonapi
901941
freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)

Modules/_testcapimodule.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3415,6 +3415,26 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
34153415
Py_RETURN_NONE;
34163416
}
34173417

3418+
static PyObject*
3419+
code_offset_to_line(PyObject* self, PyObject* const* args, Py_ssize_t nargsf)
3420+
{
3421+
Py_ssize_t nargs = _PyVectorcall_NARGS(nargsf);
3422+
if (nargs != 2) {
3423+
PyErr_SetString(PyExc_TypeError, "code_offset_to_line takes 2 arguments");
3424+
return NULL;
3425+
}
3426+
int offset;
3427+
if (PyLong_AsInt32(args[1], &offset) < 0) {
3428+
return NULL;
3429+
}
3430+
PyCodeObject *code = (PyCodeObject *)args[0];
3431+
if (!PyCode_Check(code)) {
3432+
PyErr_SetString(PyExc_TypeError, "first arg must be a code object");
3433+
return NULL;
3434+
}
3435+
return PyLong_FromInt32(PyCode_Addr2Line(code, offset));
3436+
}
3437+
34183438
static PyMethodDef TestMethods[] = {
34193439
{"set_errno", set_errno, METH_VARARGS},
34203440
{"test_config", test_config, METH_NOARGS},
@@ -3557,6 +3577,7 @@ static PyMethodDef TestMethods[] = {
35573577
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
35583578
{"type_freeze", type_freeze, METH_VARARGS},
35593579
{"test_atexit", test_atexit, METH_NOARGS},
3580+
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
35603581
{NULL, NULL} /* sentinel */
35613582
};
35623583

0 commit comments

Comments
 (0)