Skip to content

Commit 629a5fd

Browse files
Copilotyouknowone
andcommitted
fix: restore def-line source range before entering function scope so co_firstlineno is correct
Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/94701403-2011-4525-88f1-6e06891da6a4 Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
1 parent 3930b2e commit 629a5fd

3 files changed

Lines changed: 48 additions & 2 deletions

File tree

Lib/test/test_inspect/test_inspect.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,6 @@ def test_range_traceback_toplevel_frame(self):
961961
class TestDecorators(GetSourceBase):
962962
fodderModule = mod2
963963

964-
@unittest.expectedFailure # TODO: RUSTPYTHON; pass
965964
def test_wrapped_decorator(self):
966965
self.assertSourceEqual(mod2.wrapped, 14, 17)
967966

@@ -1259,7 +1258,6 @@ def test_class(self):
12591258
class TestComplexDecorator(GetSourceBase):
12601259
fodderModule = mod2
12611260

1262-
@unittest.expectedFailure # TODO: RUSTPYTHON; return foo + bar()
12631261
def test_parens_in_decorator(self):
12641262
self.assertSourceEqual(self.fodderModule.complex_decorated, 273, 275)
12651263

crates/codegen/src/compile.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4246,11 +4246,19 @@ impl Compiler {
42464246
is_async: bool,
42474247
type_params: Option<&ast::TypeParams>,
42484248
) -> CompileResult<()> {
4249+
// Save the source range of the `def` line before compiling decorators/defaults,
4250+
// so that the function code object gets the correct co_firstlineno.
4251+
let def_source_range = self.current_source_range;
4252+
42494253
self.prepare_decorators(decorator_list)?;
42504254

42514255
// compile defaults and return funcflags
42524256
let funcflags = self.compile_default_arguments(parameters)?;
42534257

4258+
// Restore the `def` line range so that enter_function → push_output → get_source_line_number()
4259+
// records the `def` keyword's line as co_firstlineno, not the last default-argument line.
4260+
self.set_source_range(def_source_range);
4261+
42544262
let is_generic = type_params.is_some();
42554263
let mut num_typeparam_args = 0;
42564264

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Regression tests for inspect.getsource returning full source code."""
2+
import inspect
3+
4+
5+
def a(
6+
a=0,
7+
):
8+
pass
9+
10+
11+
source = inspect.getsource(a)
12+
assert "def" in source, f"Expected full source, got: {source!r}"
13+
14+
# Ensure the full definition including the `def` line is present
15+
assert source.startswith("def a("), f"Source should start with 'def a(', got: {source!r}"
16+
17+
18+
# Async function with multi-line parameters
19+
async def b(
20+
x=1,
21+
y=2,
22+
):
23+
pass
24+
25+
26+
source_b = inspect.getsource(b)
27+
assert "async def" in source_b, f"Expected 'async def' in source, got: {source_b!r}"
28+
29+
30+
# Function with keyword-only defaults
31+
def c(
32+
*,
33+
kw=42,
34+
):
35+
pass
36+
37+
38+
source_c = inspect.getsource(c)
39+
assert "def" in source_c, f"Expected full source for kw-only defaults, got: {source_c!r}"
40+
assert source_c.startswith("def c("), f"Source should start with 'def c(', got: {source_c!r}"

0 commit comments

Comments
 (0)