summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2008-11-17 23:35:24 (GMT)
committerBenjamin Peterson <benjamin@python.org>2008-11-17 23:35:24 (GMT)
commit42fe1a2ff864c3f3491e6dab38b24e27db304633 (patch)
tree0217ed296ba6a64d6463a4f7a6f1e0ad226aeea9 /Lib
parenta8629ce4b8212313d50fa9e4ae22b80f0e81e4b0 (diff)
downloadcpython-42fe1a2ff864c3f3491e6dab38b24e27db304633.zip
cpython-42fe1a2ff864c3f3491e6dab38b24e27db304633.tar.gz
cpython-42fe1a2ff864c3f3491e6dab38b24e27db304633.tar.bz2
backport r67246 from the trunk
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_descr.py59
1 files changed, 50 insertions, 9 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 3c29017..529939a 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1073,20 +1073,21 @@ def consistency_with_epg():
(EditableScrollablePane, ScrollablePane, EditablePane,
Pane, ScrollingMixin, EditingMixin, object))
+def raises(exc, expected, callable, *args):
+ try:
+ callable(*args)
+ except exc, msg:
+ if not str(msg).startswith(expected):
+ raise TestFailed, "Message %r, expected %r" % (str(msg),
+ expected)
+ else:
+ raise TestFailed, "Expected %s" % exc
+
mro_err_msg = """Cannot create a consistent method resolution
order (MRO) for bases """
def mro_disagreement():
if verbose: print "Testing error messages for MRO disagreement..."
- def raises(exc, expected, callable, *args):
- try:
- callable(*args)
- except exc, msg:
- if not str(msg).startswith(expected):
- raise TestFailed, "Message %r, expected %r" % (str(msg),
- expected)
- else:
- raise TestFailed, "Expected %s" % exc
class A(object): pass
class B(A): pass
class C(object): pass
@@ -4171,6 +4172,45 @@ def methodwrapper():
vereq(t.__add__, (7,).__add__)
vereq(hash(t.__add__), hash((7,).__add__))
+def test_getattr_hooks():
+ # issue 4230
+ class Descriptor(object):
+ counter = 0
+ def __get__(self, obj, objtype=None):
+ def getter(name):
+ self.counter += 1
+ raise AttributeError(name)
+ return getter
+
+ descr = Descriptor()
+ class A(object):
+ __getattribute__ = descr
+ class B(object):
+ __getattr__ = descr
+ class C(object):
+ __getattribute__ = descr
+ __getattr__ = descr
+
+ raises(AttributeError, "attr", getattr, A(), "attr")
+ vereq(descr.counter, 1)
+ raises(AttributeError, "attr", getattr, B(), "attr")
+ vereq(descr.counter, 2)
+ raises(AttributeError, "attr", getattr, C(), "attr")
+ vereq(descr.counter, 4)
+
+ import gc
+ class EvilGetattribute(object):
+ # This used to segfault
+ def __getattr__(self, name):
+ raise AttributeError(name)
+ def __getattribute__(self, name):
+ del EvilGetattribute.__getattr__
+ for i in range(5):
+ gc.collect()
+ raise AttributeError(name)
+
+ raises(AttributeError, "attr", getattr, EvilGetattribute(), "attr")
+
def notimplemented():
# all binary methods should be able to return a NotImplemented
if verbose:
@@ -4352,6 +4392,7 @@ def test_main():
methodwrapper()
notimplemented()
test_assign_slice()
+ test_getattr_hooks()
if verbose: print "All OK"