1
# -*- test-case-name: epsilon.test.test_descriptor -*-
4
Provides an 'attribute' class for one-use descriptors.
9
class _MetaAttribute(type):
10
def __new__(meta, name, bases, dict):
12
for kw in ['get', 'set', 'delete']:
14
dict[kw] = staticmethod(dict[kw])
15
secretClass = type.__new__(meta, name, bases, dict)
20
class attribute(object):
22
Convenience class for providing one-shot descriptors, similar to
23
'property'. For example:
25
>>> from epsilon.descriptor import attribute
26
>>> class Dynamo(object):
27
... class dynamic(attribute):
29
... self.dynCount += 1
30
... return self.dynCount
31
... def set(self, value):
32
... self.dynCount += value
46
Traceback (most recent call last):
48
AttributeError: attribute cannot be removed
51
__metaclass__ = _MetaAttribute
53
def __get__(self, oself, type):
55
Private implementation of descriptor interface.
59
return self.get(oself)
61
def __set__(self, oself, value):
63
Private implementation of descriptor interface.
65
return self.set(oself, value)
67
def __delete__(self, oself):
69
Private implementation of descriptor interface.
71
return self.delete(oself)
75
Implement this method to provide attribute setting. Default behavior
76
is that attributes are not settable.
78
raise AttributeError('read only attribute')
82
Implement this method to provide attribute retrieval. Default behavior
83
is that unset attributes do not have any value.
85
raise AttributeError('attribute has no value')
89
Implement this method to provide attribute deletion. Default behavior
90
is that attributes cannot be deleted.
92
raise AttributeError('attribute cannot be removed')
96
def requiredAttribute(requiredAttributeName):
98
Utility for defining attributes on base classes/mixins which require their
99
values to be supplied by their derived classes. C{None} is a common, but
100
almost never suitable default value for these kinds of attributes, as it
101
may cause operations in the derived class to fail silently in peculiar
102
ways. If a C{requiredAttribute} is accessed before having its value
103
changed, a C{AttributeError} will be raised with a helpful error message.
105
@param requiredAttributeName: The name of the required attribute.
106
@type requiredAttributeName: C{str}
109
>>> from epsilon.descriptor import requiredAttribute
111
>>> class FooTestMixin:
112
... expectedResult = requiredAttribute('expectedResult')
114
>>> class BrokenFooTestCase(TestCase, FooTestMixin):
117
>>> brokenFoo = BrokenFooTestCase()
118
>>> print brokenFoo.expectedResult
119
Traceback (most recent call last):
121
AttributeError: Required attribute 'expectedResult' has not been
122
changed from its default value on '<BrokenFooTestCase
125
>>> class WorkingFooTestCase(TestCase, FooTestMixin):
126
... expectedResult = 7
128
>>> workingFoo = WorkingFooTestCase()
129
>>> print workingFoo.expectedResult
133
class RequiredAttribute(attribute):
135
if requiredAttributeName not in self.__dict__:
136
raise AttributeError(
137
('Required attribute %r has not been changed'
138
' from its default value on %r' % (
139
requiredAttributeName, self)))
140
return self.__dict__[requiredAttributeName]
141
def set(self, value):
142
self.__dict__[requiredAttributeName] = value
143
return RequiredAttribute
147
__all__ = ['attribute', 'requiredAttribute']