| 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.func_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.func_dict |
| except TypeError: pass |
| else: raise TestFailed |
| |
| try: |
| another.func_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.func_defaults |
| |
| def foo(): |
| pass |
| |
| def bar(): |
| pass |
| |
| def temp(): |
| print 1 |
| |
| if foo==bar: |
| raise TestFailed |
| |
| d={} |
| d[foo] = 1 |
| |
| foo.func_code = temp.func_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.func_closure |
| verify(isinstance(c, tuple)) |
| verify(len(c) == 1) |
| verify(c[0].__class__.__name__ == "cell") # don't have a type object handy |
| cantset(f, "func_closure", c) |
| |
| def test_func_doc(): |
| def f(): pass |
| verify(f.__doc__ is None) |
| verify(f.func_doc is None) |
| f.__doc__ = "hello" |
| verify(f.__doc__ == "hello") |
| verify(f.func_doc == "hello") |
| del f.__doc__ |
| verify(f.__doc__ is None) |
| verify(f.func_doc is None) |
| f.func_doc = "world" |
| verify(f.__doc__ == "world") |
| verify(f.func_doc == "world") |
| del f.func_doc |
| verify(f.func_doc is None) |
| verify(f.__doc__ is None) |
| |
| def test_func_globals(): |
| def f(): pass |
| verify(f.func_globals is globals()) |
| cantset(f, "func_globals", globals()) |
| |
| def test_func_name(): |
| def f(): pass |
| verify(f.__name__ == "f") |
| verify(f.func_name == "f") |
| f.__name__ = "g" |
| verify(f.__name__ == "g") |
| verify(f.func_name == "g") |
| f.func_name = "h" |
| verify(f.__name__ == "h") |
| verify(f.func_name == "h") |
| cantset(f, "func_globals", 1) |
| cantset(f, "__name__", 1) |
| # test that you can access func.__name__ in restricted mode |
| s = """def f(): pass\nf.__name__""" |
| exec s in {'__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.func_code) is types.CodeType) |
| f.func_code = g.func_code |
| cantset(f, "func_code", None) |
| # can't change the number of free vars |
| cantset(f, "func_code", f1.func_code, exception=ValueError) |
| cantset(f1, "func_code", f.func_code, exception=ValueError) |
| cantset(f1, "func_code", f2.func_code, exception=ValueError) |
| f1.func_code = g1.func_code |
| |
| def test_func_defaults(): |
| def f(a, b): return (a, b) |
| verify(f.func_defaults is None) |
| f.func_defaults = (1, 2) |
| verify(f.func_defaults == (1, 2)) |
| verify(f(10) == (10, 2)) |
| def g(a=1, b=2): return (a, b) |
| verify(g.func_defaults == (1, 2)) |
| del g.func_defaults |
| verify(g.func_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__ |
| b = f.func_dict |
| verify(a == {}) |
| verify(a is b) |
| f.hello = 'world' |
| verify(a == {'hello': 'world'}) |
| verify(f.func_dict is a is f.__dict__) |
| f.func_dict = {} |
| verify(not hasattr(f, "hello")) |
| f.__dict__ = {'world': 'hello'} |
| verify(f.world == "hello") |
| verify(f.__dict__ is f.func_dict == {'world': 'hello'}) |
| cantset(f, "func_dict", None) |
| 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() |