1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
def _debug(txt='',*args):
if _debug._mode : print txt%args
def mode(obj):
_debug._mode=bool(obj)
_debug.mode=mode ; del mode ; _debug.mode(0)
class MetaTypedDyn(type):
'''Metaclass of TypedClass based class'''
def __new__(cls,nm,bs,at):
_debug('MetaTyped.__new__%s',(cls,nm,bs,at))
for key in at:
if any([x!='__' for x in (key[:2], key[-2:])]) and 'function' not in `type(at[key])`:
at[key]=TypedAttr(at[key])
return type.__new__(cls,nm,bs,at)
def __getattribute__(cls, key):
_debug('MetaTyped.__getattribute__%s',(cls,key))
cls_attr=type.__getattribute__(cls,key)
if type(cls_attr)==TypedAttr:
return cls_attr.val
return cls_attr
def __setattr__(cls, key, val):
_debug('MetaTyped.__setattr__%s',(cls,key,val))
if key in cls.__dict__:
cls_attr=type.__getattribute__(cls,key)
if type(cls_attr)==TypedAttr:
cls_attr.__set__(None,val)
return None
raise AttributeError('Attribute %s.%s is type %s, it cannot be changed en route'%(cls,key, type(cls_attr)))
type.__setattr__(cls,key,TypedAttr(val))
class TypedAttr(object):
'''TypedAttr is a Descriptor. The allowed type of value is the type of the value
used at the __init__, meaning that it is automaticaly defined. Passing a name arg
at __init__ will do the TypedAttr instance act as an instance attribute (with a
default value).'''
def __init__(s,v,name=None):
_debug('TypedAttr.__init__%s',(s,v,name))
s.val = v
s.type = type(v)
s.name = name
def __get__(s, obj, objtype=None):
_debug('TypedAttr.__get__%s',(s,obj,objtype))
name = s.name
if name is None : return s #class attribute access
elif name not in obj.__dict__ : return s.val #instance attribute default acces
return obj.__dict__[name] #instance attribute acces
def __set__(s,obj,val):
_debug('TypedAttr.__get__%s',(s,obj,val))
if type(val)!=s.type : raise TypeError('expected %s, have %s'%(s.type,type(val)))
elif s.name is None : s.val=val #class
else : setattr(obj,s.name,val) #instance
class TypedClass(object):
'''class designed to be subclassed. All class attributes and instance attributes are
"typed restricted"
NOTE: if __setattr__ is overloaded, TypedClass.__setattr__ must be called !'''
__metaclass__=MetaTypedDyn
def __setattr__(s,nm,v):
if nm[:6]=='_desc_' or nm in s.__class__.__dict__:
object.__setattr__(s,nm,v)
elif nm not in s.__class__.__dict__:
setattr(s.__class__,nm,TypedAttr(v,'_desc_'+nm))
object.__setattr__(s,'_desc_'+nm,v) |
Partager