Skip to content

Commit f9be169

Browse files
committed
re-add AttrCleaner for one spot and add test
1 parent d410c8c commit f9be169

File tree

4 files changed

+131
-118
lines changed

4 files changed

+131
-118
lines changed

bpython/autocomplete.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ def attr_matches(self, text, namespace):
353353
obj = safe_eval(expr, namespace)
354354
except EvaluationError:
355355
return []
356-
matches = self.attr_lookup(obj, expr, attr)
356+
with inspection.AttrCleaner(obj):
357+
matches = self.attr_lookup(obj, expr, attr)
357358
return matches
358359

359360
def attr_lookup(self, obj, expr, attr):

bpython/test/test_autocomplete.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ def asserts_when_called(self):
251251
class Slots(object):
252252
__slots__ = ["a", "b"]
253253

254+
class OverriddenGetattribute(Foo):
255+
def __getattribute__(self,name):
256+
raise AssertionError("custom get attribute invoked")
257+
258+
254259

255260
class TestAttrCompletion(unittest.TestCase):
256261
@classmethod
@@ -298,6 +303,14 @@ def test_descriptor_attributes_not_run(self):
298303
com.matches(2, "a.", locals_={"a": Properties()}),
299304
set(["a.b", "a.a", "a.method", "a.asserts_when_called"]),
300305
)
306+
307+
def test_custom_get_attribute_not_invoked(self):
308+
com = autocomplete.AttrCompletion()
309+
self.assertSetEqual(
310+
com.matches(2, "a.", locals_={"a": OverriddenGetattribute()}),
311+
set(["a.b", "a.a", "a.method"]),
312+
)
313+
301314

302315
def test_slots_not_crash(self):
303316
com = autocomplete.AttrCompletion()

bpython/test/test_inspection.py

Lines changed: 116 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -155,73 +155,124 @@ def test_get_source_file(self):
155155
self.assertEqual(encoding, "utf-8")
156156

157157

158-
class TestSafeGetAttribute(unittest.TestCase):
159-
def test_lookup_on_object(self):
160-
a = A()
161-
a.x = 1
162-
self.assertEqual(getattr_safe(a, "x"), 1)
163-
self.assertEqual(getattr_safe(a, "a"), "a")
164-
b = B()
165-
b.y = 2
166-
self.assertEqual(getattr_safe(b, "y"), 2)
167-
self.assertEqual(getattr_safe(b, "a"), "a")
168-
self.assertEqual(getattr_safe(b, "b"), "b")
169-
170-
self.assertEqual(hasattr_safe(b, "y"), True)
171-
self.assertEqual(hasattr_safe(b, "b"), True)
172-
173-
174-
def test_avoid_running_properties(self):
175-
p = Property()
176-
self.assertEqual(getattr_safe(p, "prop"), Property.prop)
177-
self.assertEqual(hasattr_safe(p, "prop"), True)
178-
179-
def test_lookup_with_slots(self):
180-
s = Slots()
181-
s.s1 = "s1"
182-
self.assertEqual(getattr_safe(s, "s1"), "s1")
183-
with self.assertRaises(AttributeError):
184-
getattr_safe(s, "s2")
185-
186-
self.assertEqual(hasattr_safe(s, "s2"), False)
187-
188-
def test_lookup_on_slots_classes(self):
189-
sga = getattr_safe
190-
s = SlotsSubclass()
191-
self.assertIsInstance(sga(Slots, "s1"), member_descriptor)
192-
self.assertIsInstance(sga(SlotsSubclass, "s1"), member_descriptor)
193-
self.assertIsInstance(sga(SlotsSubclass, "s4"), property)
194-
self.assertIsInstance(sga(s, "s4"), property)
195-
196-
self.assertEqual(hasattr_safe(s, "s1"), True)
197-
self.assertEqual(hasattr_safe(s, "s4"), True)
198-
199-
@unittest.skipIf(py3, "Py 3 doesn't allow slots and prop in same class")
200-
def test_lookup_with_property_and_slots(self):
201-
sga = getattr_safe
202-
s = SlotsSubclass()
203-
self.assertIsInstance(sga(Slots, "s3"), property)
204-
self.assertEqual(getattr_safe(s, "s3"), Slots.__dict__["s3"])
205-
self.assertIsInstance(sga(SlotsSubclass, "s3"), property)
206-
207-
def test_lookup_on_overridden_methods(self):
208-
sga = getattr_safe
209-
self.assertEqual(sga(OverriddenGetattr(), "a"), 1)
210-
self.assertEqual(sga(OverriddenGetattribute(), "a"), 1)
211-
self.assertEqual(sga(OverriddenMRO(), "a"), 1)
212-
with self.assertRaises(AttributeError):
213-
sga(OverriddenGetattr(), "b")
214-
with self.assertRaises(AttributeError):
215-
sga(OverriddenGetattribute(), "b")
216-
with self.assertRaises(AttributeError):
217-
sga(OverriddenMRO(), "b")
218-
219-
self.assertEqual(hasattr_safe(OverriddenGetattr(), "b"), False)
220-
self.assertEqual(hasattr_safe(OverriddenGetattribute(), "b"), False)
221-
self.assertEqual(hasattr_safe(OverriddenMRO(), "b"), False)
222-
158+
class A(object):
159+
a = "a"
160+
161+
162+
class B(A):
163+
b = "b"
164+
165+
166+
class Property(object):
167+
@property
168+
def prop(self):
169+
raise AssertionError("Property __get__ executed")
170+
171+
172+
class Slots(object):
173+
__slots__ = ["s1", "s2", "s3"]
174+
175+
if not py3:
176+
177+
@property
178+
def s3(self):
179+
raise AssertionError("Property __get__ executed")
180+
181+
182+
class SlotsSubclass(Slots):
183+
@property
184+
def s4(self):
185+
raise AssertionError("Property __get__ executed")
186+
187+
188+
class OverriddenGetattr(object):
189+
def __getattr__(self, attr):
190+
raise AssertionError("custom __getattr__ executed")
191+
192+
a = 1
223193

224194

195+
class OverriddenGetattribute(object):
196+
def __getattribute__(self, attr):
197+
raise AssertionError("custom __getattribute__ executed")
198+
199+
a = 1
200+
201+
202+
class OverriddenMRO(object):
203+
def __mro__(self):
204+
raise AssertionError("custom mro executed")
205+
206+
a = 1
207+
208+
member_descriptor = type(Slots.s1)
209+
210+
class TestSafeGetAttribute(unittest.TestCase):
211+
def test_lookup_on_object(self):
212+
a = A()
213+
a.x = 1
214+
self.assertEqual(inspection.getattr_safe(a, "x"), 1)
215+
self.assertEqual(inspection.getattr_safe(a, "a"), "a")
216+
b = B()
217+
b.y = 2
218+
self.assertEqual(inspection.getattr_safe(b, "y"), 2)
219+
self.assertEqual(inspection.getattr_safe(b, "a"), "a")
220+
self.assertEqual(inspection.getattr_safe(b, "b"), "b")
221+
222+
self.assertEqual(inspection.hasattr_safe(b, "y"), True)
223+
self.assertEqual(inspection.hasattr_safe(b, "b"), True)
224+
225+
226+
def test_avoid_running_properties(self):
227+
p = Property()
228+
self.assertEqual(inspection.getattr_safe(p, "prop"), Property.prop)
229+
self.assertEqual(inspection.hasattr_safe(p, "prop"), True)
230+
231+
def test_lookup_with_slots(self):
232+
s = Slots()
233+
s.s1 = "s1"
234+
self.assertEqual(inspection.getattr_safe(s, "s1"), "s1")
235+
with self.assertRaises(AttributeError):
236+
inspection.getattr_safe(s, "s2")
237+
238+
self.assertEqual(inspection.hasattr_safe(s, "s1"), True)
239+
self.assertEqual(inspection.hasattr_safe(s, "s2"), False)
240+
241+
def test_lookup_on_slots_classes(self):
242+
sga = inspection.getattr_safe
243+
s = SlotsSubclass()
244+
self.assertIsInstance(sga(Slots, "s1"), member_descriptor)
245+
self.assertIsInstance(sga(SlotsSubclass, "s1"), member_descriptor)
246+
self.assertIsInstance(sga(SlotsSubclass, "s4"), property)
247+
self.assertIsInstance(sga(s, "s4"), property)
248+
249+
self.assertEqual(inspection.hasattr_safe(s, "s1"), False)
250+
self.assertEqual(inspection.hasattr_safe(s, "s4"), True)
251+
252+
@unittest.skipIf(py3, "Py 3 doesn't allow slots and prop in same class")
253+
def test_lookup_with_property_and_slots(self):
254+
sga = inspection.getattr_safe
255+
s = SlotsSubclass()
256+
self.assertIsInstance(sga(Slots, "s3"), property)
257+
self.assertEqual(inspection.getattr_safe(s, "s3"), Slots.__dict__["s3"])
258+
self.assertIsInstance(sga(SlotsSubclass, "s3"), property)
259+
260+
def test_lookup_on_overridden_methods(self):
261+
sga = inspection.getattr_safe
262+
self.assertEqual(sga(OverriddenGetattr(), "a"), 1)
263+
self.assertEqual(sga(OverriddenGetattribute(), "a"), 1)
264+
self.assertEqual(sga(OverriddenMRO(), "a"), 1)
265+
with self.assertRaises(AttributeError):
266+
sga(OverriddenGetattr(), "b")
267+
with self.assertRaises(AttributeError):
268+
sga(OverriddenGetattribute(), "b")
269+
with self.assertRaises(AttributeError):
270+
sga(OverriddenMRO(), "b")
271+
272+
self.assertEqual(inspection.hasattr_safe(OverriddenGetattr(), "b"), False)
273+
self.assertEqual(inspection.hasattr_safe(OverriddenGetattribute(), "b"), False)
274+
self.assertEqual(inspection.hasattr_safe(OverriddenMRO(), "b"), False)
275+
225276

226277
if __name__ == "__main__":
227278
unittest.main()

bpython/test/test_simpleeval.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -133,58 +133,6 @@ def test_with_namespace(self):
133133
self.assertCannotEval("a[1].a|bc", {})
134134

135135

136-
class A(object):
137-
a = "a"
138-
139-
140-
class B(A):
141-
b = "b"
142-
143-
144-
class Property(object):
145-
@property
146-
def prop(self):
147-
raise AssertionError("Property __get__ executed")
148-
149-
150-
class Slots(object):
151-
__slots__ = ["s1", "s2", "s3"]
152-
153-
if not py3:
154-
155-
@property
156-
def s3(self):
157-
raise AssertionError("Property __get__ executed")
158-
159-
160-
class SlotsSubclass(Slots):
161-
@property
162-
def s4(self):
163-
raise AssertionError("Property __get__ executed")
164-
165-
166-
class OverriddenGetattr(object):
167-
def __getattr__(self, attr):
168-
raise AssertionError("custom __getattr__ executed")
169-
170-
a = 1
171-
172-
173-
class OverriddenGetattribute(object):
174-
def __getattribute__(self, attr):
175-
raise AssertionError("custom __getattribute__ executed")
176-
177-
a = 1
178-
179-
180-
class OverriddenMRO(object):
181-
def __mro__(self):
182-
raise AssertionError("custom mro executed")
183-
184-
a = 1
185-
186-
187-
member_descriptor = type(Slots.s1)
188136

189137

190138
if __name__ == "__main__":

0 commit comments

Comments
 (0)