mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	attribute. Deleting it, or setting it to a non-dictionary result in a TypeError. Note that getting it the first time magically initializes it to an empty dict so that func.__dict__ will always appear to be a dictionary (never None). Closes SF bug #446645.
		
			
				
	
	
		
			212 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from test_support import verbose, TestFailed
 | 
						|
 | 
						|
class F:
 | 
						|
    def a(self):
 | 
						|
        pass
 | 
						|
 | 
						|
def b():
 | 
						|
    'my docstring'
 | 
						|
    pass
 | 
						|
 | 
						|
# 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 TypeError: pass
 | 
						|
else: raise TestFailed, 'expected 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 TypeError: pass
 | 
						|
else: raise TestFailed, 'expected TypeError'
 | 
						|
 | 
						|
# See the comment above about the change in semantics for Python 2.1b1
 | 
						|
try:
 | 
						|
    F.a.myclass = F
 | 
						|
except TypeError: pass
 | 
						|
else: raise TestFailed, 'expected 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 TypeError: pass
 | 
						|
else: raise TestFailed, 'expected TypeError'
 | 
						|
 | 
						|
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 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 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 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]
 |