test: assert line numbers of evaluated source (#6169)
* test: assert line numbers of evaluated source
#6089 dropped the coding cookie prepended to py::eval/py::exec source,
which had shifted reported SyntaxError and traceback line numbers by one,
and noted that no test asserted on them. Add one: errors on line 2 of the
evaluated source must report line 2. With pybind11's own test target the
new test reports (3, 3) against the parent of #6089 and (2, 2) with the fix.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* style: pre-commit fixes
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
diff --git a/tests/test_eval.cpp b/tests/test_eval.cpp
index cd2903f..6fdf7a8 100644
--- a/tests/test_eval.cpp
+++ b/tests/test_eval.cpp
@@ -87,6 +87,31 @@
return false;
});
+ // Line numbers reported from evaluated source must match the source as given;
+ // before #6089 a prepended coding cookie shifted them by one.
+ m.def("test_eval_line_numbers", []() {
+ int syntax_lineno = -1;
+ try {
+ py::exec("x = 1\nx = = 2\n");
+ throw std::runtime_error("py::exec did not raise SyntaxError");
+ } catch (py::error_already_set &e) {
+ syntax_lineno = e.value().attr("lineno").cast<int>();
+ }
+ int traceback_lineno = -1;
+ try {
+ py::exec("x = 1\nraise RuntimeError('line two')\n");
+ throw std::runtime_error("py::exec did not raise RuntimeError");
+ } catch (py::error_already_set &e) {
+ py::object tb = e.trace();
+ for (py::object next = tb.attr("tb_next"); !next.is_none();
+ next = tb.attr("tb_next")) {
+ tb = std::move(next);
+ }
+ traceback_lineno = tb.attr("tb_lineno").cast<int>();
+ }
+ return py::make_tuple(syntax_lineno, traceback_lineno);
+ });
+
// test_eval_empty_globals
m.def("eval_empty_globals", [](py::object global) {
if (global.is_none()) {
diff --git a/tests/test_eval.py b/tests/test_eval.py
index 8ac1907..db6cec8 100644
--- a/tests/test_eval.py
+++ b/tests/test_eval.py
@@ -27,6 +27,10 @@
assert m.test_eval_file_failure()
+def test_eval_line_numbers():
+ assert m.test_eval_line_numbers() == (2, 2)
+
+
def test_eval_empty_globals():
assert "__builtins__" in m.eval_empty_globals(None)