https://github.com/python/cpython/commit/81c1cdcf4a9aa08cef567e3a75480099db470052
commit: 81c1cdcf4a9aa08cef567e3a75480099db470052
branch: main
author: Peter <[email protected]>
committer: ethanfurman <[email protected]>
date: 2026-06-09T11:00:23-07:00
summary:

gh-139819: rlcompleter – avoid suggesting attributes not accessible on 
instances (GH-139820)

Co-authored-by: Ethan Furman <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-10-09-12-13-29.gh-issue-139819.YxUDyH.rst
M Lib/rlcompleter.py
M Lib/test/test_rlcompleter.py

diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py
index 6c6d9bb6b34244..271b77a322fdd2 100644
--- a/Lib/rlcompleter.py
+++ b/Lib/rlcompleter.py
@@ -40,6 +40,9 @@
 
 __all__ = ["Completer"]
 
+# Sentinel object to distinguish "missing" from "present but None"
+_SENTINEL = object()
+
 class Completer:
     def __init__(self, namespace = None):
         """Create a new completer for the command line.
@@ -194,14 +197,14 @@ def attr_matches(self, text):
                         and
                         isinstance(thisobject.__dict__.get(word),
                                    types.LazyImportType)
-                    ):
+                       ):
                         value = thisobject.__dict__.get(word)
                     else:
-                        value = getattr(thisobject, word, None)
+                        value = getattr(thisobject, word, _SENTINEL)
 
-                    if value is not None:
+                    if value is not _SENTINEL:
                         matches.append(self._callable_postfix(value, match))
-                    else:
+                    elif word in getattr(type(thisobject), '__slots__', ()):
                         matches.append(match)
             if matches or not noprefix:
                 break
diff --git a/Lib/test/test_rlcompleter.py b/Lib/test/test_rlcompleter.py
index e6d727d417b298..c0b5a4da8cb256 100644
--- a/Lib/test/test_rlcompleter.py
+++ b/Lib/test/test_rlcompleter.py
@@ -107,19 +107,35 @@ def test_excessive_getattr(self):
         # we use __dir__ and __getattr__ in class Foo to create a "magic"
         # class attribute 'bar'. This forces `getattr` to call __getattr__
         # (which is doesn't necessarily do).
-        class Foo:
+        # Test 1: Attribute returns None
+        class FooReturnsNone:
             calls = 0
-            bar = ''
+            bar = None
             def __getattribute__(self, name):
                 if name == 'bar':
                     self.calls += 1
                     return None
                 return super().__getattribute__(name)
 
-        f = Foo()
-        completer = rlcompleter.Completer(dict(f=f))
-        self.assertEqual(completer.complete('f.b', 0), 'f.bar')
-        self.assertEqual(f.calls, 1)
+        f1 = FooReturnsNone()
+        completer1 = rlcompleter.Completer(dict(f=f1))
+        self.assertEqual(completer1.complete('f.b', 0), 'f.bar')
+        self.assertEqual(f1.calls, 1)
+
+        # Test 2: Attribute returns non-None value
+        class FooReturnsValue:
+            calls = 0
+            bar = ''
+            def __getattribute__(self, name):
+                if name == 'bar':
+                    self.calls += 1
+                    return ''
+                return super().__getattribute__(name)
+
+        f2 = FooReturnsValue()
+        completer2 = rlcompleter.Completer(dict(f=f2))
+        self.assertEqual(completer2.complete('f.b', 0), 'f.bar')
+        self.assertEqual(f2.calls, 1)
 
     def test_property_method_not_called(self):
         class Foo:
@@ -196,6 +212,7 @@ class Foo:
         completer = rlcompleter.Completer(dict(f=Foo()))
         self.assertEqual(completer.complete('f.', 0), 'f.bar')
 
+
     @unittest.mock.patch('rlcompleter._readline_available', False)
     def test_complete(self):
         completer = rlcompleter.Completer()
diff --git 
a/Misc/NEWS.d/next/Library/2025-10-09-12-13-29.gh-issue-139819.YxUDyH.rst 
b/Misc/NEWS.d/next/Library/2025-10-09-12-13-29.gh-issue-139819.YxUDyH.rst
new file mode 100644
index 00000000000000..ab3a8c6ed16ce4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-10-09-12-13-29.gh-issue-139819.YxUDyH.rst
@@ -0,0 +1,3 @@
+:mod:`rlcompleter`: Avoid suggesting attributes that are not accessible on
+instances (e.g., Enum members showing ``__name__``). Patch by Peter
+(ttw225).

_______________________________________________
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