https://github.com/python/cpython/commit/2b4c31d87d6fe9ec7cdc88eb6139ce9370666739
commit: 2b4c31d87d6fe9ec7cdc88eb6139ce9370666739
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Yhg1s <[email protected]>
date: 2024-09-02T13:07:08+02:00
summary:

[3.13] gh-122981: Fix inspect.getsource() for generated classes with Python 
base classes (GH-123001) (#123182)

gh-122981: Fix inspect.getsource() for generated classes with Python base 
classes (GH-123001)

Look up __firstlineno__ only in the class' dict, without searching in
base classes.
(cherry picked from commit f88c14d412522587085ae039ebe70b91d5b4e226)

Co-authored-by: Serhiy Storchaka <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst
M Lib/inspect.py
M Lib/test/test_inspect/inspect_fodder2.py
M Lib/test/test_inspect/test_inspect.py

diff --git a/Lib/inspect.py b/Lib/inspect.py
index 845d55f41751a0..9499dc5c6dc81c 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1082,10 +1082,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__
diff --git a/Lib/test/test_inspect/inspect_fodder2.py 
b/Lib/test/test_inspect/inspect_fodder2.py
index bb9d3e88cfbee1..43e9f852022934 100644
--- a/Lib/test/test_inspect/inspect_fodder2.py
+++ b/Lib/test/test_inspect/inspect_fodder2.py
@@ -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)))
diff --git a/Lib/test/test_inspect/test_inspect.py 
b/Lib/test/test_inspect/test_inspect.py
index 6060494c9be684..766b3fe571b5f9 100644
--- a/Lib/test/test_inspect/test_inspect.py
+++ b/Lib/test/test_inspect/test_inspect.py
@@ -824,7 +824,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__])
@@ -932,6 +932,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
 
diff --git 
a/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst 
b/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst
new file mode 100644
index 00000000000000..7713d805155f9a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-08-14-10-41-11.gh-issue-122981.BHV0Z9.rst
@@ -0,0 +1,2 @@
+Fix :func:`inspect.getsource` for generated classes with Python base classes
+(e.g. enums).

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to