# Test descriptor-related enhancements from test_support import verify, verbose, TestFailed from copy import deepcopy def testunop(a, res, expr="len(a)", meth="__len__"): if verbose: print "checking", expr dict = {'a': a} verify(eval(expr, dict) == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) verify(m(a) == res) bm = getattr(a, meth) verify(bm() == res) def testbinop(a, b, res, expr="a+b", meth="__add__"): if verbose: print "checking", expr dict = {'a': a, 'b': b} verify(eval(expr, dict) == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) verify(m(a, b) == res) bm = getattr(a, meth) verify(bm(b) == res) def testternop(a, b, c, res, expr="a[b:c]", meth="__getslice__"): if verbose: print "checking", expr dict = {'a': a, 'b': b, 'c': c} verify(eval(expr, dict) == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) verify(m(a, b, c) == res) bm = getattr(a, meth) verify(bm(b, c) == res) def testsetop(a, b, res, stmt="a+=b", meth="__iadd__"): if verbose: print "checking", stmt dict = {'a': deepcopy(a), 'b': b} exec stmt in dict verify(dict['a'] == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) dict['a'] = deepcopy(a) m(dict['a'], b) verify(dict['a'] == res) dict['a'] = deepcopy(a) bm = getattr(dict['a'], meth) bm(b) verify(dict['a'] == res) def testset2op(a, b, c, res, stmt="a[b]=c", meth="__setitem__"): if verbose: print "checking", stmt dict = {'a': deepcopy(a), 'b': b, 'c': c} exec stmt in dict verify(dict['a'] == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) dict['a'] = deepcopy(a) m(dict['a'], b, c) verify(dict['a'] == res) dict['a'] = deepcopy(a) bm = getattr(dict['a'], meth) bm(b, c) verify(dict['a'] == res) def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"): if verbose: print "checking", stmt dict = {'a': deepcopy(a), 'b': b, 'c': c, 'd': d} exec stmt in dict verify(dict['a'] == res) t = type(a) m = getattr(t, meth) verify(m == t.__dict__[meth]) dict['a'] = deepcopy(a) m(dict['a'], b, c, d) verify(dict['a'] == res) dict['a'] = deepcopy(a) bm = getattr(dict['a'], meth) bm(b, c, d) verify(dict['a'] == res) def lists(): if verbose: print "Testing list operations..." testbinop([1], [2], [1,2], "a+b", "__add__") testbinop([1,2,3], 2, 1, "b in a", "__contains__") testbinop([1,2,3], 4, 0, "b in a", "__contains__") testbinop([1,2,3], 1, 2, "a[b]", "__getitem__") testternop([1,2,3], 0, 2, [1,2], "a[b:c]", "__getslice__") testsetop([1], [2], [1,2], "a+=b", "__iadd__") testsetop([1,2], 3, [1,2,1,2,1,2], "a*=b", "__imul__") testunop([1,2,3], 3, "len(a)", "__len__") testbinop([1,2], 3, [1,2,1,2,1,2], "a*b", "__mul__") testbinop([1,2], 3, [1,2,1,2,1,2], "b*a", "__rmul__") testset2op([1,2], 1, 3, [1,3], "a[b]=c", "__setitem__") testset3op([1,2,3,4], 1, 3, [5,6], [1,5,6,4], "a[b:c]=d", "__setslice__") def dicts(): if verbose: print "Testing dict operations..." testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__") testbinop({1:2,3:4}, 1, 1, "b in a", "__contains__") testbinop({1:2,3:4}, 2, 0, "b in a", "__contains__") testbinop({1:2,3:4}, 1, 2, "a[b]", "__getitem__") d = {1:2,3:4} l1 = [] for i in d.keys(): l1.append(i) l = [] for i in iter(d): l.append(i) verify(l == l1) l = [] for i in d.__iter__(): l.append(i) verify(l == l1) l = [] for i in dictionary.__iter__(d): l.append(i) verify(l == l1) d = {1:2, 3:4} testunop(d, 2, "len(a)", "__len__") verify(eval(repr(d), {}) == d) verify(eval(d.__repr__(), {}) == d) testset2op({1:2,3:4}, 2, 3, {1:2,2:3,3:4}, "a[b]=c", "__setitem__") def dict_constructor(): if verbose: print "Testing dictionary constructor ..." d = dictionary() verify(d == {}) d = dictionary({}) verify(d == {}) d = dictionary(mapping={}) verify(d == {}) d = dictionary({1: 2, 'a': 'b'}) verify(d == {1: 2, 'a': 'b'}) for badarg in 0, 0L, 0j, "0", [0], (0,): try: dictionary(badarg) except TypeError: pass else: raise TestFailed("no TypeError from dictionary(%r)" % badarg) try: dictionary(senseless={}) except TypeError: pass else: raise TestFailed("no TypeError from dictionary(senseless={}") try: dictionary({}, {}) except TypeError: pass else: raise TestFailed("no TypeError from dictionary({}, {})") class Mapping: dict = {1:2, 3:4, 'a':1j} def __getitem__(self, i): return self.dict[i] try: dictionary(Mapping()) except TypeError: pass else: raise TestFailed("no TypeError from dictionary(incomplete mapping)") Mapping.keys = lambda self: self.dict.keys() d = dictionary(mapping=Mapping()) verify(d == Mapping.dict) def test_dir(): if verbose: print "Testing dir() ..." junk = 12 verify(dir() == ['junk']) del junk # Just make sure these don't blow up! for arg in 2, 2L, 2j, 2e0, [2], "2", u"2", (2,), {2:2}, type, test_dir: dir(arg) # Try classic classes. class C: Cdata = 1 def Cmethod(self): pass cstuff = ['Cdata', 'Cmethod', '__doc__', '__module__'] verify(dir(C) == cstuff) c = C() # c.__doc__ is an odd thing to see here; ditto c.__module__. verify(dir(c) == cstuff) c.cdata = 2 c.cmethod = lambda self: 0 verify(dir(c) == cstuff + ['cdata', 'cmethod']) class A(C): Adata = 1 def Amethod(self): pass astuff = ['Adata', 'Amethod'] + cstuff verify(dir(A) == astuff) a = A() verify(dir(a) == astuff) a.adata = 42 a.amethod = lambda self: 3 verify(dir(a) == astuff + ['adata', 'amethod']) # The same, but with new-style classes. Since these have object as a # base class, a lot more gets sucked in. def interesting(strings): return [s for s in strings if not s.startswith('_')] class C(object): Cdata = 1 def Cmethod(self): pass cstuff = ['Cdata', 'Cmethod'] verify(interesting(dir(C)) == cstuff) c = C() verify(interesting(dir(c)) == cstuff) c.cdata = 2 c.cmethod = lambda self: 0 verify(interesting(dir(c)) == cstuff + ['cdata', 'cmethod']) class A(C): Adata = 1 def Amethod(self): pass astuff = ['Adata', 'Amethod'] + cstuff verify(interesting(dir(A)) == astuff) a = A() verify(interesting(dir(a)) == astuff) a.adata = 42 a.amethod = lambda self: 3 verify(interesting(dir(a)) == astuff + ['adata', 'amethod']) binops = { 'add': '+', 'sub': '-', 'mul': '*', 'div': '/', 'mod': '%', 'divmod': 'divmod', 'pow': '**', 'lshift': '<<', 'rshift': '>>', 'and': '&', 'xor': '^', 'or': '|', 'cmp': 'cmp', 'lt': '<', 'le': '<=', 'eq': '==', 'ne': '!=', 'gt': '>', 'ge': '>=', } for name, expr in binops.items(): if expr.islower(): expr = expr + "(a, b)" else: expr = 'a %s b' % expr binops[name] = expr unops = { 'pos': '+', 'neg': '-', 'abs': 'abs', 'invert': '~', 'int': 'int', 'long': 'long', 'float': 'float', 'oct': 'oct', 'hex': 'hex', } for name, expr in unops.items(): if expr.islower(): expr = expr + "(a)" else: expr = '%s a' % expr unops[name] = expr def numops(a, b, skip=[]): dict = {'a': a, 'b': b} for name, expr in binops.items(): if name not in skip: name = "__%s__" % name if hasattr(a, name): res = eval(expr, dict) testbinop(a, b, res, expr, name) for name, expr in unops.items(): name = "__%s__" % name if hasattr(a, name): res = eval(expr, dict) testunop(a, res, expr, name) def ints(): if verbose: print "Testing int operations..." numops(100, 3) def longs(): if verbose: print "Testing long operations..." numops(100L, 3L) def floats(): if verbose: print "Testing float operations..." numops(100.0, 3.0) def complexes(): if verbose: print "Testing complex operations..." numops(100.0j, 3.0j, skip=['lt', 'le', 'gt', 'ge']) class Number(complex): __slots__ = ['prec'] def __init__(self, *args, **kwds): self.prec = kwds.get('prec', 12) def __repr__(self): prec = self.prec if self.imag == 0.0: return "%.*g" % (prec, self.real) if self.real == 0.0: return "%.*gj" % (prec, self.imag) return "(%.*g+%.*gj)" % (prec, self.real, prec, self.imag) __str__ = __repr__ a = Number(3.14, prec=6) verify(`a` == "3.14") verify(a.prec == 6) def spamlists(): if verbose: print "Testing spamlist operations..." import copy, xxsubtype as spam def spamlist(l, memo=None): import xxsubtype as spam return spam.spamlist(l) # This is an ugly hack: copy._deepcopy_dispatch[spam.spamlist] = spamlist testbinop(spamlist([1]), spamlist([2]), spamlist([1,2]), "a+b", "__add__") testbinop(spamlist([1,2,3]), 2, 1, "b in a", "__contains__") testbinop(spamlist([1,2,3]), 4, 0, "b in a", "__contains__") testbinop(spamlist([1,2,3]), 1, 2, "a[b]", "__getitem__") testternop(spamlist([1,2,3]), 0, 2, spamlist([1,2]), "a[b:c]", "__getslice__") testsetop(spamlist([1]), spamlist([2]), spamlist([1,2]), "a+=b", "__iadd__") testsetop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*=b", "__imul__") testunop(spamlist([1,2,3]), 3, "len(a)", "__len__") testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "a*b", "__mul__") testbinop(spamlist([1,2]), 3, spamlist([1,2,1,2,1,2]), "b*a", "__rmul__") testset2op(spamlist([1,2]), 1, 3, spamlist([1,3]), "a[b]=c", "__setitem__") testset3op(spamlist([1,2,3,4]), 1, 3, spamlist([5,6]), spamlist([1,5,6,4]), "a[b:c]=d", "__setslice__") # Test subclassing class C(spam.spamlist): def foo(self): return 1 a = C() verify(a == []) verify(a.foo() == 1) a.append(100) verify(a == [100]) verify(a.getstate() == 0) a.setstate(42) verify(a.getstate() == 42) def spamdicts(): if verbose: print "Testing spamdict operations..." import copy, xxsubtype as spam def spamdict(d, memo=None): import xxsubtype as spam sd = spam.spamdict() for k, v in d.items(): sd[k] = v return sd # This is an ugly hack: copy._deepcopy_dispatch[spam.spamdict] = spamdict testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__") testbinop(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__") testbinop(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__") testbinop(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__") d = spamdict({1:2,3:4}) l1 = [] for i in d.keys(): l1.append(i) l = [] for i in iter(d): l.append(i) verify(l == l1) l = [] for i in d.__iter__(): l.append(i) verify(l == l1) l = [] for i in type(spamdict({})).__iter__(d): l.append(i) verify(l == l1) straightd = {1:2, 3:4} spamd = spamdict(straightd) testunop(spamd, 2, "len(a)", "__len__") testunop(spamd, repr(straightd), "repr(a)", "__repr__") testset2op(spamdict({1:2,3:4}), 2, 3, spamdict({1:2,2:3,3:4}), "a[b]=c", "__setitem__") # Test subclassing class C(spam.spamdict): def foo(self): return 1 a = C() verify(a.items() == []) verify(a.foo() == 1) a['foo'] = 'bar' verify(a.items() == [('foo', 'bar')]) verify(a.getstate() == 0) a.setstate(100) verify(a.getstate() == 100) def pydicts(): if verbose: print "Testing Python subclass of dict..." verify(issubclass(dictionary, dictionary)) verify(isinstance({}, dictionary)) d = dictionary() verify(d == {}) verify(d.__class__ is dictionary) verify(isinstance(d, dictionary)) class C(dictionary): state = -1 def __init__(self, *a, **kw): if a: assert len(a) == 1 self.state = a[0] if kw: for k, v in kw.items(): self[v] = k def __getitem__(self, key): return self.get(key, 0) def __setitem__(self, key, value): assert isinstance(key, type(0)) dictionary.__setitem__(self, key, value) def setstate(self, state): self.state = state def getstate(self): return self.state verify(issubclass(C, dictionary)) a1 = C(12) verify(a1.state == 12) a2 = C(foo=1, bar=2) verify(a2[1] == 'foo' and a2[2] == 'bar') a = C() verify(a.state == -1) verify(a.getstate() == -1) a.setstate(0) verify(a.state == 0) verify(a.getstate() == 0) a.setstate(10) verify(a.state == 10) verify(a.getstate() == 10) verify(a[42] == 0) a[42] = 24 verify(a[42] == 24) if verbose: print "pydict stress test ..." N = 50 for i in range(N): a[i] = C() for j in range(N): a[i][j] = i*j for i in range(N): for j in range(N): verify(a[i][j] == i*j) def pylists(): if verbose: print "Testing Python subclass of list..." class C(list): def __getitem__(self, i): return list.__getitem__(self, i) + 100 def __getslice__(self, i, j): return (i, j) a = C() a.extend([0,1,2]) verify(a[0] == 100) verify(a[1] == 101) verify(a[2] == 102) verify(a[100:200] == (100,200)) def metaclass(): if verbose: print "Testing __metaclass__..." class C: __metaclass__ = type def __init__(self): self.__state = 0 def getstate(self): return self.__state def setstate(self, state): self.__state = state a = C() verify(a.getstate() == 0) a.setstate(10) verify(a.getstate() == 10) class D: class __metaclass__(type): def myself(cls): return cls verify(D.myself() == D) d = D() verify(d.__class__ is D) class M1(type): def __new__(cls, name, bases, dict): dict['__spam__'] = 1 return type.__new__(cls, name, bases, dict) class C: __metaclass__ = M1 verify(C.__spam__ == 1) c = C() verify(c.__spam__ == 1) class _instance(object): pass class M2(object): def __new__(cls, name, bases, dict): self = object.__new__(cls) self.name = name self.bases = bases self.dict = dict return self __new__ = staticmethod(__new__) def __call__(self): it = _instance() # Early binding of methods for key in self.dict: if key.startswith("__"): continue setattr(it, key, self.dict[key].__get__(it, self)) return it class C: __metaclass__ = M2 def spam(self): return 42 verify(C.name == 'C') verify(C.bases == ()) verify('spam' in C.dict) c = C() verify(c.spam() == 42) # More metaclass examples class autosuper(type): # Automatically add __super to the class # This trick only works for dynamic classes # so we force __dynamic__ = 1 def __new__(metaclass, name, bases, dict): # XXX Should check that name isn't already a base class name dict["__dynamic__"] = 1 cls = super(autosuper, metaclass).__new__(metaclass, name, bases, dict) # Name mangling for __super removes leading underscores while name[:1] == "_": name = name[1:] if name: name = "_%s__super" % name else: name = "__super" setattr(cls, name, super(cls)) return cls class A: __metaclass__ = autosuper def meth(self): return "A" class B(A): def meth(self): return "B" + self.__super.meth() class C(A): def meth(self): return "C" + self.__super.meth() class D(C, B): def meth(self): return "D" + self.__super.meth() verify(D().meth() == "DCBA") class E(B, C): def meth(self): return "E" + self.__super.meth() verify(E().meth() == "EBCA") class autogetset(type): # Automatically create getset attributes when methods # named _get_x and/or _set_x are found def __new__(metaclass, name, bases, dict): hits = {} for key, val in dict.iteritems(): if key.startswith("_get_"): key = key[5:] get, set = hits.get(key, (None, None)) get = val hits[key] = get, set elif key.startswith("_set_"): key = key[5:] get, set = hits.get(key, (None, None)) set = val hits[key] = get, set for key, (get, set) in hits.iteritems(): dict[key] = getset(get, set) return super(autogetset, metaclass).__new__(metaclass, name, bases, dict) class A: __metaclass__ = autogetset def _get_x(self): return -self.__x def _set_x(self, x): self.__x = -x a = A() verify(not hasattr(a, "x")) a.x = 12 verify(a.x == 12) verify(a._A__x == -12) class multimetaclass(autogetset, autosuper): # Merge of multiple cooperating metaclasses pass class A: __metaclass__ = multimetaclass def _get_x(self): return "A" class B(A): def _get_x(self): return "B" + self.__super._get_x() class C(A): def _get_x(self): return "C" + self.__super._get_x() class D(C, B): def _get_x(self): return "D" + self.__super._get_x() verify(D().x == "DCBA") def pymods(): if verbose: print "Testing Python subclass of module..." log = [] import sys MT = type(sys) class MM(MT): def __init__(self): MT.__init__(self) def __getattr__(self, name): log.append(("getattr", name)) return MT.__getattr__(self, name) def __setattr__(self, name, value): log.append(("setattr", name, value)) MT.__setattr__(self, name, value) def __delattr__(self, name): log.append(("delattr", name)) MT.__delattr__(self, name) a = MM() a.foo = 12 x = a.foo del a.foo verify(log == [("setattr", "foo", 12), ("getattr", "foo"), ("delattr", "foo")], log) def multi(): if verbose: print "Testing multiple inheritance..." class C(object): def __init__(self): self.__state = 0 def getstate(self): return self.__state def setstate(self, state): self.__state = state a = C() verify(a.getstate() == 0) a.setstate(10) verify(a.getstate() == 10) class D(dictionary, C): def __init__(self): type({}).__init__(self) C.__init__(self) d = D() verify(d.keys() == []) d["hello"] = "world" verify(d.items() == [("hello", "world")]) verify(d["hello"] == "world") verify(d.getstate() == 0) d.setstate(10) verify(d.getstate() == 10) verify(D.__mro__ == (D, dictionary, C, object)) # SF bug #442833 class Node(object): def __int__(self): return int(self.foo()) def foo(self): return "23" class Frag(Node, list): def foo(self): return "42" verify(Node().__int__() == 23) verify(int(Node()) == 23) verify(Frag().__int__() == 42) verify(int(Frag()) == 42) def diamond(): if verbose: print "Testing multiple inheritance special cases..." class A(object): def spam(self): return "A" verify(A().spam() == "A") class B(A): def boo(self): return "B" def spam(self): return "B" verify(B().spam() == "B") verify(B().boo() == "B") class C(A): def boo(self): return "C" verify(C().spam() == "A") verify(C().boo() == "C") class D(B, C): pass verify(D().spam() == "B") verify(D().boo() == "B") verify(D.__mro__ == (D, B, C, A, object)) class E(C, B): pass verify(E().spam() == "B") verify(E().boo() == "C") verify(E.__mro__ == (E, C, B, A, object)) class F(D, E): pass verify(F().spam() == "B") verify(F().boo() == "B") verify(F.__mro__ == (F, D, E, B, C, A, object)) class G(E, D): pass verify(G().spam() == "B") verify(G().boo() == "C") verify(G.__mro__ == (G, E, D, C, B, A, object)) def objects(): if verbose: print "Testing object class..." a = object() verify(a.__class__ == object == type(a)) b = object() verify(a is not b) verify(not hasattr(a, "foo")) try: a.foo = 12 except (AttributeError, TypeError): pass else: verify(0, "object() should not allow setting a foo attribute") verify(not hasattr(object(), "__dict__")) class Cdict(object): pass x = Cdict() verify(x.__dict__ is None) x.foo = 1 verify(x.foo == 1) verify(x.__dict__ == {'foo': 1}) def slots(): if verbose: print "Testing __slots__..." class C0(object): __slots__ = [] x = C0() verify(not hasattr(x, "__dict__")) verify(not hasattr(x, "foo")) class C1(object): __slots__ = ['a'] x = C1() verify(not hasattr(x, "__dict__")) verify(x.a == None) x.a = 1 verify(x.a == 1) del x.a verify(x.a == None) class C3(object): __slots__ = ['a', 'b', 'c'] x = C3() verify(not hasattr(x, "__dict__")) verify(x.a is None) verify(x.b is None) verify(x.c is None) x.a = 1 x.b = 2 x.c = 3 verify(x.a == 1) verify(x.b == 2) verify(x.c == 3) def dynamics(): if verbose: print "Testing __dynamic__..." verify(object.__dynamic__ == 0) verify(list.__dynamic__ == 0) class S1: __metaclass__ = type verify(S1.__dynamic__ == 0) class S(object): pass verify(S.__dynamic__ == 0) class D(object): __dynamic__ = 1 verify(D.__dynamic__ == 1) class E(D, S): pass verify(E.__dynamic__ == 1) class F(S, D): pass verify(F.__dynamic__ == 1) try: S.foo = 1 except (AttributeError, TypeError): pass else: verify(0, "assignment to a static class attribute should be illegal") D.foo = 1 verify(D.foo == 1) # Test that dynamic attributes are inherited verify(E.foo == 1) verify(F.foo == 1) class SS(D): __dynamic__ = 0 verify(SS.__dynamic__ == 0) verify(SS.foo == 1) try: SS.foo = 1 except (AttributeError, TypeError): pass else: verify(0, "assignment to SS.foo should be illegal") # Test dynamic instances class C(object): __dynamic__ = 1 a = C() verify(not hasattr(a, "foobar")) C.foobar = 2 verify(a.foobar == 2) C.method = lambda self: 42 verify(a.method() == 42) C.__repr__ = lambda self: "C()" verify(repr(a) == "C()") C.__int__ = lambda self: 100 verify(int(a) == 100) verify(a.foobar == 2) verify(not hasattr(a, "spam")) def mygetattr(self, name): if name == "spam": return "spam" else: return object.__getattr__(self, name) C.__getattr__ = mygetattr verify(a.spam == "spam") a.new = 12 verify(a.new == 12) def mysetattr(self, name, value): if name == "spam": raise AttributeError return object.__setattr__(self, name, value) C.__setattr__ = mysetattr try: a.spam = "not spam" except AttributeError: pass else: verify(0, "expected AttributeError") verify(a.spam == "spam") class D(C): pass d = D() d.foo = 1 verify(d.foo == 1) def errors(): if verbose: print "Testing errors..." try: class C(list, dictionary): pass except TypeError: pass else: verify(0, "inheritance from both list and dict should be illegal") try: class C(object, None): pass except TypeError: pass else: verify(0, "inheritance from non-type should be illegal") class Classic: pass try: class C(object, Classic): pass except TypeError: pass else: verify(0, "inheritance from object and Classic should be illegal") try: class C(type(len)): pass except TypeError: pass else: verify(0, "inheritance from CFunction should be illegal") try: class C(object): __slots__ = 1 except TypeError: pass else: verify(0, "__slots__ = 1 should be illegal") try: class C(object): __slots__ = [1] except TypeError: pass else: verify(0, "__slots__ = [1] should be illegal") def classmethods(): if verbose: print "Testing class methods..." class C(object): def foo(*a): return a goo = classmethod(foo) c = C() verify(C.goo(1) == (C, 1)) verify(c.goo(1) == (C, 1)) verify(c.foo(1) == (c, 1)) class D(C): pass d = D() verify(D.goo(1) == (D, 1)) verify(d.goo(1) == (D, 1)) verify(d.foo(1) == (d, 1)) verify(D.foo(d, 1) == (d, 1)) def staticmethods(): if verbose: print "Testing static methods..." class C(object): def foo(*a): return a goo = staticmethod(foo) c = C() verify(C.goo(1) == (1,)) verify(c.goo(1) == (1,)) verify(c.foo(1) == (c, 1,)) class D(C): pass d = D() verify(D.goo(1) == (1,)) verify(d.goo(1) == (1,)) verify(d.foo(1) == (d, 1)) verify(D.foo(d, 1) == (d, 1)) def classic(): if verbose: print "Testing classic classes..." class C: def foo(*a): return a goo = classmethod(foo) c = C() verify(C.goo(1) == (C, 1)) verify(c.goo(1) == (C, 1)) verify(c.foo(1) == (c, 1)) class D(C): pass d = D() verify(D.goo(1) == (D, 1)) verify(d.goo(1) == (D, 1)) verify(d.foo(1) == (d, 1)) verify(D.foo(d, 1) == (d, 1)) class E: # *not* subclassing from C foo = C.foo verify(E().foo == C.foo) # i.e., unbound verify(repr(C.foo.__get__(C())).startswith("= 0) verify(str(c1) == repr(c1)) verify(-1 not in c1) for i in range(10): verify(i in c1) verify(10 not in c1) # Test the default behavior for dynamic classes class D(object): __dynamic__ = 1 def __getitem__(self, i): if 0 <= i < 10: return i raise IndexError d1 = D() d2 = D() verify(not not d1) verify(hash(d1) == id(d1)) verify(cmp(d1, d2) == cmp(id(d1), id(d2))) verify(d1 == d1) verify(d1 != d2) verify(not d1 != d1) verify(not d1 == d2) # Note that the module name appears in str/repr, and that varies # depending on whether this test is run standalone or from a framework. verify(str(d1).find('D instance at ') >= 0) verify(str(d1) == repr(d1)) verify(-1 not in d1) for i in range(10): verify(i in d1) verify(10 not in d1) # Test overridden behavior for static classes class Proxy(object): def __init__(self, x): self.x = x def __nonzero__(self): return not not self.x def __hash__(self): return hash(self.x) def __eq__(self, other): return self.x == other def __ne__(self, other): return self.x != other def __cmp__(self, other): return cmp(self.x, other.x) def __str__(self): return "Proxy:%s" % self.x def __repr__(self): return "Proxy(%r)" % self.x def __contains__(self, value): return value in self.x p0 = Proxy(0) p1 = Proxy(1) p_1 = Proxy(-1) verify(not p0) verify(not not p1) verify(hash(p0) == hash(0)) verify(p0 == p0) verify(p0 != p1) verify(not p0 != p0) verify(not p0 == p1) verify(cmp(p0, p1) == -1) verify(cmp(p0, p0) == 0) verify(cmp(p0, p_1) == 1) verify(str(p0) == "Proxy:0") verify(repr(p0) == "Proxy(0)") p10 = Proxy(range(10)) verify(-1 not in p10) for i in range(10): verify(i in p10) verify(10 not in p10) # Test overridden behavior for dynamic classes class DProxy(object): __dynamic__ = 1 def __init__(self, x): self.x = x def __nonzero__(self): return not not self.x def __hash__(self): return hash(self.x) def __eq__(self, other): return self.x == other def __ne__(self, other): return self.x != other def __cmp__(self, other): return cmp(self.x, other.x) def __str__(self): return "DProxy:%s" % self.x def __repr__(self): return "DProxy(%r)" % self.x def __contains__(self, value): return value in self.x p0 = DProxy(0) p1 = DProxy(1) p_1 = DProxy(-1) verify(not p0) verify(not not p1) verify(hash(p0) == hash(0)) verify(p0 == p0) verify(p0 != p1) verify(not p0 != p0) verify(not p0 == p1) verify(cmp(p0, p1) == -1) verify(cmp(p0, p0) == 0) verify(cmp(p0, p_1) == 1) verify(str(p0) == "DProxy:0") verify(repr(p0) == "DProxy(0)") p10 = DProxy(range(10)) verify(-1 not in p10) for i in range(10): verify(i in p10) verify(10 not in p10) def weakrefs(): if verbose: print "Testing weak references..." import weakref class C(object): pass c = C() r = weakref.ref(c) verify(r() is c) del c verify(r() is None) del r class NoWeak(object): __slots__ = ['foo'] no = NoWeak() try: weakref.ref(no) except TypeError, msg: verify(str(msg).find("weakly") >= 0) else: verify(0, "weakref.ref(no) should be illegal") class Weak(object): __slots__ = ['foo', '__weakref__'] yes = Weak() r = weakref.ref(yes) verify(r() is yes) del yes verify(r() is None) del r def getsets(): if verbose: print "Testing getset..." class C(object): def getx(self): return self.__x def setx(self, value): self.__x = value def delx(self): del self.__x x = getset(getx, setx, delx) a = C() verify(not hasattr(a, "x")) a.x = 42 verify(a._C__x == 42) verify(a.x == 42) del a.x verify(not hasattr(a, "x")) verify(not hasattr(a, "_C__x")) C.x.__set__(a, 100) verify(C.x.__get__(a) == 100) ## C.x.__set__(a) ## verify(not hasattr(a, "x")) def supers(): if verbose: print "Testing super..." class A(object): def meth(self, a): return "A(%r)" % a verify(A().meth(1) == "A(1)") class B(A): def __init__(self): self.__super = super(B, self) def meth(self, a): return "B(%r)" % a + self.__super.meth(a) verify(B().meth(2) == "B(2)A(2)") class C(A): __dynamic__ = 1 def meth(self, a): return "C(%r)" % a + self.__super.meth(a) C._C__super = super(C) verify(C().meth(3) == "C(3)A(3)") class D(C, B): def meth(self, a): return "D(%r)" % a + super(D, self).meth(a) verify (D().meth(4) == "D(4)C(4)B(4)A(4)") def inherits(): if verbose: print "Testing inheritance from basic types..." class hexint(int): def __repr__(self): return hex(self) def __add__(self, other): return hexint(int.__add__(self, other)) # (Note that overriding __radd__ doesn't work, # because the int type gets first dibs.) verify(repr(hexint(7) + 9) == "0x10") verify(repr(hexint(1000) + 7) == "0x3ef") class octlong(long): __slots__ = [] def __str__(self): s = oct(self) if s[-1] == 'L': s = s[:-1] return s def __add__(self, other): return self.__class__(super(octlong, self).__add__(other)) __radd__ = __add__ verify(str(octlong(3) + 5) == "010") # (Note that overriding __radd__ here only seems to work # because the example uses a short int left argument.) verify(str(5 + octlong(3000)) == "05675") class precfloat(float): __slots__ = ['prec'] def __init__(self, value=0.0, prec=12): self.prec = int(prec) float.__init__(value) def __repr__(self): return "%.*g" % (self.prec, self) verify(repr(precfloat(1.1)) == "1.1") class madtuple(tuple): _rev = None def rev(self): if self._rev is not None: return self._rev L = list(self) L.reverse() self._rev = self.__class__(L) return self._rev a = madtuple((1,2,3,4,5,6,7,8,9,0)) verify(a.rev() == madtuple((0,9,8,7,6,5,4,3,2,1))) verify(a.rev().rev() == madtuple((1,2,3,4,5,6,7,8,9,0))) for i in range(512): t = madtuple(range(i)) u = t.rev() v = u.rev() verify(v == t) class madstring(str): _rev = None def rev(self): if self._rev is not None: return self._rev L = list(self) L.reverse() self._rev = self.__class__("".join(L)) return self._rev s = madstring("abcdefghijklmnopqrstuvwxyz") verify(s.rev() == madstring("zyxwvutsrqponmlkjihgfedcba")) verify(s.rev().rev() == madstring("abcdefghijklmnopqrstuvwxyz")) for i in range(256): s = madstring("".join(map(chr, range(i)))) t = s.rev() u = t.rev() verify(u == s) class madunicode(unicode): _rev = None def rev(self): if self._rev is not None: return self._rev L = list(self) L.reverse() self._rev = self.__class__(u"".join(L)) return self._rev u = madunicode("ABCDEF") verify(u.rev() == madunicode(u"FEDCBA")) verify(u.rev().rev() == madunicode(u"ABCDEF")) def all(): lists() dicts() dict_constructor() test_dir() ints() longs() floats() complexes() spamlists() spamdicts() pydicts() pylists() metaclass() pymods() multi() diamond() objects() slots() dynamics() errors() classmethods() staticmethods() classic() compattr() newslot() altmro() overloading() methods() specials() weakrefs() getsets() supers() inherits() all() if verbose: print "All OK"