Fix inspect.getsource returning truncated source for multi-line function definitions (#7519)

* Initial plan

* 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>

* fix: remove pre-existing expectedFailure decorators from test_gettext plural form tests

Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/ce27bf53-569f-45a0-ad5a-08e8f322c717

Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>

* remove extra_tests/snippets/inspect_getsource.py (covered by test_inspect)

Agent-Logs-Url: https://github.com/RustPython/RustPython/sessions/2b64da1b-8aab-4fec-8b28-3a21d46ac2f9

Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: youknowone <69878+youknowone@users.noreply.github.com>
This commit is contained in:
Copilotandyouknowone authored and GitHub committed 2026-03-29 00:52:34 +09:00
1 parent 4b99e3fd62
commit ae2ceab7ab
3 files changed
+8 -9

No files matched your search

-7
View File
@@ -385,7 +385,6 @@ class PluralFormsTests:
x = ngettext(singular, plural, None)
self.assertEqual(x, tplural)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_forms(self):
self._test_plural_forms(
self.ngettext, self.gettext,
@@ -396,7 +395,6 @@ class PluralFormsTests:
'%d file deleted', '%d files deleted',
'%d file deleted', '%d files deleted')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_context_forms(self):
ngettext = partial(self.npgettext, 'With context')
gettext = partial(self.pgettext, 'With context')
@@ -409,7 +407,6 @@ class PluralFormsTests:
'%d file deleted', '%d files deleted',
'%d file deleted', '%d files deleted')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_wrong_context_forms(self):
self._test_plural_forms(
partial(self.npgettext, 'Unknown context'),
@@ -442,7 +439,6 @@ class GNUTranslationsWithDomainPluralFormsTestCase(PluralFormsTests, GettextBase
self.pgettext = partial(gettext.dpgettext, 'gettext')
self.npgettext = partial(gettext.dnpgettext, 'gettext')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_forms_wrong_domain(self):
self._test_plural_forms(
partial(gettext.dngettext, 'unknown'),
@@ -451,7 +447,6 @@ class GNUTranslationsWithDomainPluralFormsTestCase(PluralFormsTests, GettextBase
'There is %s file', 'There are %s files',
numbers_only=False)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_context_forms_wrong_domain(self):
self._test_plural_forms(
partial(gettext.dnpgettext, 'unknown', 'With context'),
@@ -472,7 +467,6 @@ class GNUTranslationsClassPluralFormsTestCase(PluralFormsTests, GettextBaseTest)
self.pgettext = t.pgettext
self.npgettext = t.npgettext
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_forms_null_translations(self):
t = gettext.NullTranslations()
self._test_plural_forms(
@@ -481,7 +475,6 @@ class GNUTranslationsClassPluralFormsTestCase(PluralFormsTests, GettextBaseTest)
'There is %s file', 'There are %s files',
numbers_only=False)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_plural_context_forms_null_translations(self):
t = gettext.NullTranslations()
self._test_plural_forms(
-2
View File
@@ -961,7 +961,6 @@ class TestGettingSourceOfToplevelFrames(GetSourceBase):
class TestDecorators(GetSourceBase):
fodderModule = mod2
@unittest.expectedFailure # TODO: RUSTPYTHON; pass
def test_wrapped_decorator(self):
self.assertSourceEqual(mod2.wrapped, 14, 17)
@@ -1259,7 +1258,6 @@ class TestNoEOL(GetSourceBase):
class TestComplexDecorator(GetSourceBase):
fodderModule = mod2
@unittest.expectedFailure # TODO: RUSTPYTHON; return foo + bar()
def test_parens_in_decorator(self):
self.assertSourceEqual(self.fodderModule.complex_decorated, 273, 275)
+8
View File
@@ -4246,11 +4246,19 @@ impl Compiler {
is_async: bool,
type_params: Option<&ast::TypeParams>,
) -> CompileResult<()> {
// Save the source range of the `def` line before compiling decorators/defaults,
// so that the function code object gets the correct co_firstlineno.
let def_source_range = self.current_source_range;
self.prepare_decorators(decorator_list)?;
// compile defaults and return funcflags
let funcflags = self.compile_default_arguments(parameters)?;
// Restore the `def` line range so that enter_function → push_output → get_source_line_number()
// records the `def` keyword's line as co_firstlineno, not the last default-argument line.
self.set_source_range(def_source_range);
let is_generic = type_params.is_some();
let mut num_typeparam_args = 0;