Skip to content

Commit

Permalink
pythongh-122981: Fix inspect.getsource() for generated classes with P…
Browse files Browse the repository at this point in the history
…ython base classes (pythonGH-123001)

Look up __firstlineno__ only in the class' dict, without searching in
base classes.
  • Loading branch information
serhiy-storchaka authored Aug 20, 2024
1 parent bb1d303 commit f88c14d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 4 deletions.
6 changes: 3 additions & 3 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -970,10 +970,10 @@ def findsource(object):

if isclass(object):
try:
firstlineno = object.__firstlineno__
except AttributeError:
firstlineno = vars(object)['__firstlineno__']
except (TypeError, KeyError):
raise OSError('source code not available')
return lines, object.__firstlineno__ - 1
return lines, firstlineno - 1

if ismethod(object):
object = object.__func__
Expand Down
42 changes: 42 additions & 0 deletions Lib/test/test_inspect/inspect_fodder2.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,45 @@ def g():
class ClassWithCodeObject:
import sys
code = sys._getframe(0).f_code

import enum

# line 321
class enum322(enum.Enum):
A = 'a'

# line 325
class enum326(enum.IntEnum):
A = 1

# line 329
class flag330(enum.Flag):
A = 1

# line 333
class flag334(enum.IntFlag):
A = 1

# line 337
simple_enum338 = enum.Enum('simple_enum338', 'A')
simple_enum339 = enum.IntEnum('simple_enum339', 'A')
simple_flag340 = enum.Flag('simple_flag340', 'A')
simple_flag341 = enum.IntFlag('simple_flag341', 'A')

import typing

# line 345
class nt346(typing.NamedTuple):
x: int
y: int

# line 350
nt351 = typing.NamedTuple('nt351', (('x', int), ('y', int)))

# line 353
class td354(typing.TypedDict):
x: int
y: int

# line 358
td359 = typing.TypedDict('td359', (('x', int), ('y', int)))
20 changes: 19 additions & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ def test_getsource_on_code_object(self):
self.assertSourceEqual(mod.eggs.__code__, 12, 18)

def test_getsource_on_generated_class(self):
A = type('A', (), {})
A = type('A', (unittest.TestCase,), {})
self.assertEqual(inspect.getsourcefile(A), __file__)
self.assertEqual(inspect.getfile(A), __file__)
self.assertIs(inspect.getmodule(A), sys.modules[__name__])
Expand Down Expand Up @@ -929,6 +929,24 @@ def test_anonymous(self):
# as argument to another function.
self.assertSourceEqual(mod2.anonymous, 55, 55)

def test_enum(self):
self.assertSourceEqual(mod2.enum322, 322, 323)
self.assertSourceEqual(mod2.enum326, 326, 327)
self.assertSourceEqual(mod2.flag330, 330, 331)
self.assertSourceEqual(mod2.flag334, 334, 335)
self.assertRaises(OSError, inspect.getsource, mod2.simple_enum338)
self.assertRaises(OSError, inspect.getsource, mod2.simple_enum339)
self.assertRaises(OSError, inspect.getsource, mod2.simple_flag340)
self.assertRaises(OSError, inspect.getsource, mod2.simple_flag341)

def test_namedtuple(self):
self.assertSourceEqual(mod2.nt346, 346, 348)
self.assertRaises(OSError, inspect.getsource, mod2.nt351)

def test_typeddict(self):
self.assertSourceEqual(mod2.td354, 354, 356)
self.assertRaises(OSError, inspect.getsource, mod2.td359)

class TestBlockComments(GetSourceBase):
fodderModule = mod

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :func:`inspect.getsource` for generated classes with Python base classes
(e.g. enums).

0 comments on commit f88c14d

Please sign in to comment.