1 #=======================================================================
3 __version__
= '''0.0.22'''
4 __sub_version__
= '''20040729152425'''
5 __copyright__
= '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 from __future__
import generators
15 #-----------------------------------------------------------------------
16 #-------------------------------------------------classinstancemethod---
18 class classinstancemethod(object):
21 a universal class/instance/direct method constructor/dispatcher.
23 def __init__(self
, func
, inst_func
=None, direct_func
=None):
27 self
.inst_func
= inst_func
!= None and inst_func
or func
28 self
.direct_func
= direct_func
!= None and direct_func
or func
29 def __call__(self
, *p
, **n
):
32 # we are called directly...
33 return self
.direct_func(*p
, **n
)
34 def __get__(self
, obj
, cls
=None):
38 # we are called from a class...
39 return new
.instancemethod(self
.func
, cls
, type(cls
))
41 # we are called from an instance...
42 return new
.instancemethod(self
.inst_func
, obj
, cls
)
46 #-----------------------------------------------------------------------
47 #-----------------------------------------------------ObjectWithAttrs---
48 # XXX might be good to rename this... and to add method interface
50 # TODO add update callbacks (__attr_update_callbacks__ = {<attr>: <meth>[, ...]})
51 # TODO add regex attribute naming.... (e.g. if <attr> is a regexp
52 # object use it to match the attr name...)
53 # NOTE: might be good to use a predicate...
54 class ObjectWithAttrs(object):
56 a generic object class with attribute creation an update automation.
58 this class checks attribute format.
60 # this defines an acl object to be used...
62 # this will restrict the attribute that can be created for this
63 # object to the ones mentioned in the list (DO NOT SET HERE!).
65 __attr_format__
= None
66 # this defines a tuple of attributes that must be defined on object
69 __essential_attrs__
= None
70 ## # this defines the callbacks for attr update... (RPC only at the
73 ## __attr_update_callbacks__ = {}
74 # if this is unset the checks will ignore all attrs that are not in
77 __strict_attr_format__
= True
78 # this will enable attribute type checking... (change for legacy
79 # support only... though might be good for a speedup)
80 __check_attr_types__
= True
81 # this defines the values that are to be treated as "no-vals" (e.g.
82 # ignored on type checks...)
83 __none_values__
= ('', None)
85 def __init__(self
, name
, attrs
={}):
87 create an object with attrs from a dict...
89 super(ObjectWithAttrs
, self
).__init
__(name
)
90 # check essential attrs....
91 if hasattr(self
, '__essential_attrs__') and self
.__essential
_attrs
__ != None:
92 essential_attrs
= [ (type(attr
) not in (str, unicode) and attr
[0] or attr
) \
93 for attr
in self
.__essential
_attrs
__ ]
95 if False in [ attr
in attrs
and self
._isattrwritable
(attr
, \
97 strict
=hasattr(self
, '__strict_attr_format__') and self
.__strict
_attr
_format
__, \
98 format
=self
.__essential
_attrs
__) \
99 or (err
.append(attr
), False)[-1] \
100 for attr
in essential_attrs
]:
101 raise TypeError, 'essential attribute format mismatch in %s.' % (err
,)
103 # the isconsisten protocol...
104 def __isconsistent__(self
):
106 check object consistency...
108 return _checkarttrs(self
.__dict
__)
109 # NOTE: this is not very efficient if more than one attr is added
110 # in a loop (e.g. on object init)...
111 def _isattrwritable(self
, name
, value
, format
=None, strict
=True, message
=None, none_vals
=False):
113 this predicate will return true if the attribute is writable.
115 NOTE: this function impements error reporting a side-effect.
117 the error message[s] will be appended to the message argument (if present).
119 NOTE: the argument "message" must be of type list (if present).
120 NOTE: the "message" argument will be modified during this functions execution.
123 if hasattr(self
, '__attr_format__') and self
.__attr
_format
__ != None and len(self
.__attr
_format
__) != 0:
124 format
= self
.__attr
_format
__
129 # cache the complex format...
131 [ cformat
.update({e
[0]: e
[1:]}) for e
in format
if type(e
) not in (str, unicode) ]
132 ## # NOTE: both of the folowing are quite slow...
133 ## # cache the regex format...
135 ## # cache the predicate format...
137 if hasattr(self
, '__check_attr_types__') and self
.__check
_attr
_types
__:
138 if name
not in format
:
142 etype
= len(e
) > 0 and type(e
[0]) not in (str, unicode) and e
[0] or ''
144 if none_vals
and hasattr(self
, '__none_values__') and \
145 self
.__none
_values
__ and value
in self
.__none
_values
__:
149 if type(etype
) in (str, unicode) or issubclass(type(value
), etype
):
152 # we get here if issubclass failse when
153 # comparing types with a function/lambda
155 # check predicate....
156 # XXX (temporary??) the predicate can only be a
157 # function or a lambda...
158 ## if callable(etype):
159 if type(etype
) in (types
.LambdaType
, types
.FunctionType
):
163 except Exception, msg
:
165 # implement the side-effect...
167 if type(message
) != list:
168 raise TypeError, 'message paramiter must be of type "list".'
176 elif name
not in format
and name
not in cformat
:
179 # sloooow _checkarttrs version... (uses _isattrwritable in a
181 def _checkarttrs(self
, attrs
, errors
=None, none_vals
=False):
183 check if attribute dict given is compatible with format (see self._isattrwritable for details...)
185 NOTE: this function impements error reporting a side-effect.
187 all the the arguments that generate errors will be appended to the errors argument (if present).
189 NOTE: the argument "errors" must be of type list (if present).
190 NOTE: the "errors" argument will be modified during this functions execution.
192 # NOTE: this is very inefficient!!!
194 for name
, val
in attrs
.items():
195 if not self
._isattrwritable
(name
, val
, strict
=(hasattr(self
, '__strict_attr_format__') and self
.__strict
_attr
_format
__), none_vals
=none_vals
):
197 elif type(errors
) == list:
199 for name
, val
in attrs
.items():
200 if not self
._isattrwritable
(name
, val
, strict
=(hasattr(self
, '__strict_attr_format__') and self
.__strict
_attr
_format
__), none_vals
=none_vals
):
205 raise TypeError, 'errors paramiter must be of type "list".'
207 def update(self
, attrs
):
209 update object attributes.
211 NOTE: in strict mode this will disallow an update of non-existant
214 # XXX comment the folowing two lines out if __setattr__ is used...
216 if not self
._checkarttrs
(attrs
, errors
=err
):
217 raise AttributeError, 'can\'t update object %s, attribute format mismatch in %s.' % (self
, err
)
218 if self
.__acl
__ != None:
219 acl_setattr
= self
.__acl
__.setattr
220 for n
, v
in attrs
.items():
221 acl_setattr(self
, n
, v
)
223 for n
, v
in attrs
.items():
225 # the attribute interface....
227 def __setattr__(self
, name
, val
):
230 if not self
._isattrwritable
(name
, val
, strict
=(hasattr(self
, '__strict_attr_format__') and self
.__strict
_attr
_format
__)):
231 raise TypeError, 'attribute "%s" does not comply with the format of %s object.' % (name
, self
)
232 ## self.__dict__[name] = val
233 super(ObjectWithAttrs
, self
).__setattr
__(name
, val
)
234 def __delattr__(self
, name
):
237 if hasattr(self
, '__essential_attrs__') and self
.__essential
_attrs
__ != None:
238 if name
in self
.__essential
_attrs
__ or \
239 name
in [ attr
[0] for attr
in self
.__essential
_attrs
__ if type(attr
) not in (str, unicode) ]:
240 raise TypeError, 'can not remove essential attribute "%s" of %s object.' % (name
, self
)
241 del self
.__dict
__[name
]
243 # TODO make this prittier....
245 return cls
.getattributetextformat()
246 __help__
= classmethod(__help__
)
247 def getattributetextformat(cls
):
249 this will return a text definition of the attr format of obj.
251 def _format_str(struct
):
254 if type(elem
) is str:
258 elif type(elem
) in (tuple, list):
260 atype
= len(elem
) > 1 \
261 and (type(elem
[1]) not in (str, unicode) and elem
[1].__name
__ or False) \
263 doc
= (len(elem
) > 1 and type(elem
[1]) in (str, unicode) and elem
[1] or '') \
264 + (len(elem
) > 2 and type(elem
[2]) in (str, unicode) and elem
[2] or '')
265 res
+= ' %-30s : %s\n' % ('%s (%s)' % (name
, atype
), doc
)
268 res
= 'Essential Attributes:\n'
269 if hasattr(cls
, '__essential_attrs__') and cls
.__essential
_attrs
__ != None:
270 r
= _format_str(cls
.__essential
_attrs
__)
271 res
+= r
== '' and ' None\n' or r
276 res
+= 'Attribute Format:\n'
277 if hasattr(cls
, '__attr_format__') and cls
.__attr
_format
__ != None:
278 r
= _format_str(cls
.__attr
_format
__)
279 res
+= r
== '' and ' None\n' or r
283 getattributetextformat
= classmethod(getattributetextformat
)
284 def getattributeformat(cls
, name
=None):
287 def _format_dict(struct
, target_name
=None):
290 if type(elem
) is str:
294 elif type(elem
) in (tuple, list):
296 atype
= len(elem
) > 1 \
297 and (type(elem
[1]) not in (str, unicode) and elem
[1].__name
__ or False) \
299 doc
= (len(elem
) > 1 and type(elem
[1]) in (str, unicode) and elem
[1] or '') \
300 + (len(elem
) > 2 and type(elem
[2]) in (str, unicode) and elem
[2] or '')
301 # return type of requested attr...
302 if target_name
!= None and target_name
== name
:
303 return [name
, atype
, doc
]
304 res
[name
] = (atype
, doc
)
305 if target_name
!= None:
306 # if name was not found....
312 if hasattr(cls
, '__essential_attrs__') and cls
.__essential
_attrs
__ != None:
313 res
= _format_dict(cls
.__essential
_attrs
__, name
)
314 if res
== [] and hasattr(cls
, '__attr_format__') and cls
.__attr
_format
__ != None:
315 res
= _format_dict(cls
.__attr
_format
__, name
)
320 if hasattr(cls
, '__essential_attrs__') and cls
.__essential
_attrs
__ != None:
321 res
['essential'] = _format_dict(cls
.__essential
_attrs
__)
323 if hasattr(cls
, '__attr_format__') and cls
.__attr
_format
__ != None:
324 res
['format'] = _format_dict(cls
.__attr
_format
__)
326 getattributeformat
= classmethod(getattributeformat
)
330 #=======================================================================
331 # vim:set ts=4 sw=4 nowrap :