diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index 8204c762cce8a2b..5121e89b333b2b2 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -1090,7 +1090,8 @@ def type_repr(value): """ if isinstance(value, (type, types.FunctionType, types.BuiltinFunctionType)): - if value.__module__ == "builtins": + # Built-in methods have __module__ set to None. + if value.__module__ is None or value.__module__ == "builtins": return value.__qualname__ return f"{value.__module__}.{value.__qualname__}" elif isinstance(value, _Template): diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index 5087c3ca425f1fc..a01e0f3d4491e2f 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -1850,6 +1850,10 @@ def nested(): type_repr(nested), f"{__name__}.TestTypeRepr.test_type_repr..nested" ) self.assertEqual(type_repr(len), "len") + # gh-152692: built-in methods have __module__ set to None + self.assertEqual(type_repr([].append), "list.append") + self.assertEqual(type_repr((1).bit_length), "int.bit_length") + self.assertEqual(type_repr(dict.fromkeys), "dict.fromkeys") self.assertEqual(type_repr(type_repr), "annotationlib.type_repr") self.assertEqual(type_repr(times_three), f"{__name__}.times_three") self.assertEqual(type_repr(...), "...") diff --git a/Misc/NEWS.d/next/Library/2026-06-30-15-00-00.gh-issue-152692.tr3pr0.rst b/Misc/NEWS.d/next/Library/2026-06-30-15-00-00.gh-issue-152692.tr3pr0.rst new file mode 100644 index 000000000000000..d92011f2c5acd7d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-15-00-00.gh-issue-152692.tr3pr0.rst @@ -0,0 +1,4 @@ +Fix :func:`annotationlib.type_repr` returning a string such as +``None.list.append`` for bound built-in methods, whose ``__module__`` is +``None``. It now returns the qualified name, as it already did for other +builtins.