| from test.test_support import verbose, TestFailed, verify |
| import types |
| |
| class F: |
| def a(self): |
| pass |
| |
| def b(): |
| 'my docstring' |
| pass |
| |
| # __module__ is a special attribute |
| verify(b.__module__ == __name__) |
| verify(verify.__module__ == "test.test_support") |
| |
| # setting attributes on functions |
| try: |
| b.publish |
| except AttributeError: pass |
| else: raise TestFailed, 'expected AttributeError' |
| |
| if b.__dict__ != {}: |
| raise TestFailed, 'expected unassigned func.__dict__ to be {}' |
| |
| b.publish = 1 |
| if b.publish != 1: |
| raise TestFailed, 'function attribute not set to expected value' |
| |
| docstring = 'its docstring' |
| b.__doc__ = docstring |
| if b.__doc__ != docstring: |
| raise TestFailed, 'problem with setting __doc__ attribute' |
| |
| if 'publish' not in dir(b): |
| raise TestFailed, 'attribute not in dir()' |
| |
| try: |
| del b.__dict__ |
| except TypeError: pass |
| else: raise TestFailed, 'del func.__dict__ expected TypeError' |
| |
| b.publish = 1 |
| try: |
| b.__dict__ = None |
| except TypeError: pass |
| else: raise TestFailed, 'func.__dict__ = None expected TypeError' |
| |
| d = {'hello': 'world'} |
| b.__dict__ = d |
| if b.__dict__ is not d: |
| raise TestFailed, 'func.__dict__ assignment to dictionary failed' |
| if b.hello != 'world': |
| raise TestFailed, 'attribute after func.__dict__ assignment failed' |
| |
| f1 = F() |
| f2 = F() |
| |
| try: |
| F.a.publish |
| except AttributeError: pass |
| else: raise TestFailed, 'expected AttributeError' |
| |
| try: |
| f1.a.publish |
| except AttributeError: pass |
| else: raise TestFailed, 'expected AttributeError' |
| |
| # In Python 2.1 beta 1, we disallowed setting attributes on unbound methods |
| # (it was already disallowed on bound methods). See the PEP for details. |
| try: |
| F.a.publish = 1 |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed, 'expected AttributeError or TypeError' |
| |
| # But setting it explicitly on the underlying function object is okay. |
| F.a.im_func.publish = 1 |
| |
| if F.a.publish != 1: |
| raise TestFailed, 'unbound method attribute not set to expected value' |
| |
| if f1.a.publish != 1: |
| raise TestFailed, 'bound method attribute access did not work' |
| |
| if f2.a.publish != 1: |
| raise TestFailed, 'bound method attribute access did not work' |
| |
| if 'publish' not in dir(F.a): |
| raise TestFailed, 'attribute not in dir()' |
| |
| try: |
| f1.a.publish = 0 |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed, 'expected AttributeError or TypeError' |
| |
| # See the comment above about the change in semantics for Python 2.1b1 |
| try: |
| F.a.myclass = F |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed, 'expected AttributeError or TypeError' |
| |
| F.a.im_func.myclass = F |
| |
| f1.a.myclass |
| f2.a.myclass |
| f1.a.myclass |
| F.a.myclass |
| |
| if f1.a.myclass is not f2.a.myclass or \ |
| f1.a.myclass is not F.a.myclass: |
| raise TestFailed, 'attributes were not the same' |
| |
| # try setting __dict__ |
| try: |
| F.a.__dict__ = (1, 2, 3) |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed, 'expected TypeError or AttributeError' |
| |
| F.a.im_func.__dict__ = {'one': 11, 'two': 22, 'three': 33} |
| |
| if f1.a.two != 22: |
| raise TestFailed, 'setting __dict__' |
| |
| from UserDict import UserDict |
| d = UserDict({'four': 44, 'five': 55}) |
| |
| try: |
| F.a.__dict__ = d |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed |
| |
| if f2.a.one != f1.a.one != F.a.one != 11: |
| raise TestFailed |
| |
| # im_func may not be a Python method! |
| import new |
| F.id = new.instancemethod(id, None, F) |
| |
| eff = F() |
| if eff.id() != id(eff): |
| raise TestFailed |
| |
| try: |
| F.id.foo |
| except AttributeError: pass |
| else: raise TestFailed |
| |
| try: |
| F.id.foo = 12 |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed |
| |
| try: |
| F.id.foo |
| except AttributeError: pass |
| else: raise TestFailed |
| |
| try: |
| eff.id.foo |
| except AttributeError: pass |
| else: raise TestFailed |
| |
| try: |
| eff.id.foo = 12 |
| except (AttributeError, TypeError): pass |
| else: raise TestFailed |
| |
| try: |
| eff.id.foo |
| except AttributeError: pass |
| else: raise TestFailed |
| |
| # Regression test for a crash in pre-2.1a1 |
| def another(): |
| pass |
| |
| try: |
| del another.__dict__ |
| except TypeError: pass |
| else: raise TestFailed |
| |
| try: |
| del another.__dict__ |
| except TypeError: pass |
| else: raise TestFailed |
| |
| try: |
| another.__dict__ = None |
| except TypeError: pass |
| else: raise TestFailed |
| |
| try: |
| del another.bar |
| except AttributeError: pass |
| else: raise TestFailed |
| |
| # This isn't specifically related to function attributes, but it does test a |
| # core dump regression in funcobject.c |
| del another.__defaults__ |
| |
| def foo(): |
| pass |
| |
| def bar(): |
| pass |
| |
| def temp(): |
| print(1) |
| |
| if foo==bar: |
| raise TestFailed |
| |
| d={} |
| d[foo] = 1 |
| |
| foo.__code__ = temp.__code__ |
| |
| d[foo] |
| |
| # Test all predefined function attributes systematically |
| |
| def cantset(obj, name, value, exception=(AttributeError, TypeError)): |
| verify(hasattr(obj, name)) # Otherwise it's probably a typo |
| try: |
| setattr(obj, name, value) |
| except exception: |
| pass |
| else: |
| raise TestFailed, "shouldn't be able to set %s to %r" % (name, value) |
| try: |
| delattr(obj, name) |
| except (AttributeError, TypeError): |
| pass |
| else: |
| raise TestFailed, "shouldn't be able to del %s" % name |
| |
| def test_func_closure(): |
| a = 12 |
| def f(): print(a) |
| c = f.__closure__ |
| verify(isinstance(c, tuple)) |
| verify(len(c) == 1) |
| verify(c[0].__class__.__name__ == "cell") # don't have a type object handy |
| cantset(f, "__closure__", c) |
| |
| def test_func_doc(): |
| def f(): pass |
| verify(f.__doc__ is None) |
| f.__doc__ = "hello" |
| verify(f.__doc__ == "hello") |
| del f.__doc__ |
| verify(f.__doc__ is None) |
| |
| def test_func_globals(): |
| def f(): pass |
| verify(f.__globals__ is globals()) |
| cantset(f, "__globals__", globals()) |
| |
| def test_func_name(): |
| def f(): pass |
| verify(f.__name__ == "f") |
| f.__name__ = str8("g") |
| verify(f.__name__ == str8("g")) |
| cantset(f, "__globals__", 1) |
| cantset(f, "__name__", 1) |
| # test that you can access func.__name__ in restricted mode |
| s = """def f(): pass\nf.__name__""" |
| exec(s, {'__builtins__':{}}) |
| |
| |
| def test_func_code(): |
| a = b = 24 |
| def f(): pass |
| def g(): print(12) |
| def f1(): print(a) |
| def g1(): print(b) |
| def f2(): print(a, b) |
| verify(type(f.__code__) is types.CodeType) |
| f.__code__ = g.__code__ |
| cantset(f, "__code__", None) |
| # can't change the number of free vars |
| cantset(f, "__code__", f1.__code__, exception=ValueError) |
| cantset(f1, "__code__", f.__code__, exception=ValueError) |
| cantset(f1, "__code__", f2.__code__, exception=ValueError) |
| f1.__code__ = g1.__code__ |
| |
| def test_func_defaults(): |
| def f(a, b): return (a, b) |
| verify(f.__defaults__ is None) |
| f.__defaults__ = (1, 2) |
| verify(f.__defaults__ == (1, 2)) |
| verify(f(10) == (10, 2)) |
| def g(a=1, b=2): return (a, b) |
| verify(g.__defaults__ == (1, 2)) |
| del g.__defaults__ |
| verify(g.__defaults__ is None) |
| try: |
| g() |
| except TypeError: |
| pass |
| else: |
| raise TestFailed, "shouldn't be allowed to call g() w/o defaults" |
| |
| def test_func_dict(): |
| def f(): pass |
| a = f.__dict__ |
| verify(a == {}) |
| f.hello = 'world' |
| verify(a == {'hello': 'world'}) |
| verify(a is f.__dict__) |
| f.__dict__ = {'world': 'hello'} |
| verify(f.world == "hello") |
| verify(f.__dict__ == {'world': 'hello'}) |
| cantset(f, "__dict__", None) |
| |
| def test_im_class(): |
| class C: |
| def foo(self): pass |
| verify(C.foo.im_class is C) |
| verify(C().foo.im_class is C) |
| cantset(C.foo, "im_class", C) |
| cantset(C().foo, "im_class", C) |
| |
| def test_im_func(): |
| def foo(self): pass |
| class C: |
| pass |
| C.foo = foo |
| verify(C.foo.im_func is foo) |
| verify(C().foo.im_func is foo) |
| cantset(C.foo, "im_func", foo) |
| cantset(C().foo, "im_func", foo) |
| |
| def test_im_self(): |
| class C: |
| def foo(self): pass |
| verify(C.foo.im_self is None) |
| c = C() |
| verify(c.foo.im_self is c) |
| cantset(C.foo, "im_self", None) |
| cantset(c.foo, "im_self", c) |
| |
| def test_im_dict(): |
| class C: |
| def foo(self): pass |
| foo.bar = 42 |
| verify(C.foo.__dict__ == {'bar': 42}) |
| verify(C().foo.__dict__ == {'bar': 42}) |
| cantset(C.foo, "__dict__", C.foo.__dict__) |
| cantset(C().foo, "__dict__", C.foo.__dict__) |
| |
| def test_im_doc(): |
| class C: |
| def foo(self): "hello" |
| verify(C.foo.__doc__ == "hello") |
| verify(C().foo.__doc__ == "hello") |
| cantset(C.foo, "__doc__", "hello") |
| cantset(C().foo, "__doc__", "hello") |
| |
| def test_im_name(): |
| class C: |
| def foo(self): pass |
| verify(C.foo.__name__ == "foo") |
| verify(C().foo.__name__ == "foo") |
| cantset(C.foo, "__name__", "foo") |
| cantset(C().foo, "__name__", "foo") |
| |
| def testmore(): |
| test_func_closure() |
| test_func_doc() |
| test_func_globals() |
| test_func_name() |
| test_func_code() |
| test_func_defaults() |
| test_func_dict() |
| # Tests for instance method attributes |
| test_im_class() |
| test_im_func() |
| test_im_self() |
| test_im_dict() |
| test_im_doc() |
| test_im_name() |
| |
| testmore() |