AttrCtrl: add _default_to_none flag
This commit is contained in:
parent
523a8cc5c3
commit
b79865dba4
2 changed files with 39 additions and 4 deletions
|
|
@ -41,15 +41,25 @@ class AttrCtrl(metaclass=AttrCtrlMeta):
|
|||
Ensure that attribute's type matches that of the instance attribute, or the class
|
||||
attribute, if _use_class_attr is True. If the instance or class attribute is set
|
||||
to None, no type checking is performed.
|
||||
|
||||
If _default_to_none is True, return None when accessing non-existent attributes
|
||||
instead of raising AttributeError.
|
||||
"""
|
||||
_autolock = True
|
||||
_lock = False
|
||||
_use_class_attr = False
|
||||
_default_to_none = False
|
||||
_skip_type_check = ()
|
||||
|
||||
def lock(self):
|
||||
self._lock = True
|
||||
|
||||
def __getattr__(self,name):
|
||||
if self._lock and self._default_to_none:
|
||||
return None
|
||||
else:
|
||||
raise AttributeError(f'{type(self).__name__} object has no attribute {name!r}')
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
|
||||
if self._lock:
|
||||
|
|
@ -63,7 +73,7 @@ class AttrCtrl(metaclass=AttrCtrlMeta):
|
|||
type(ref_val).__name__,
|
||||
type(value).__name__ ) )
|
||||
|
||||
if not hasattr(self,name):
|
||||
if not (name in self.__dict__ or hasattr(type(self),name)):
|
||||
raise AttributeError(f'{type(self).__name__} object has no attribute {name!r}')
|
||||
|
||||
ref_val = getattr(type(self),name) if self._use_class_attr else getattr(self,name)
|
||||
|
|
@ -101,15 +111,15 @@ class Lockable(AttrCtrl):
|
|||
super().lock()
|
||||
|
||||
def __setattr__(self,name,value):
|
||||
if self._lock and hasattr(self,name):
|
||||
if self._lock and (name in self.__dict__ or hasattr(type(self),name)):
|
||||
val = getattr(self,name)
|
||||
if name not in (self._set_ok + self._reset_ok):
|
||||
raise AttributeError(f'attribute {name!r} of {type(self).__name__} object is read-only')
|
||||
elif name not in self._reset_ok:
|
||||
#print(self.__dict__)
|
||||
if not (
|
||||
val is None or (not (val == 0) and not val) or
|
||||
( self._use_class_attr and name not in self.__dict__ ) ):
|
||||
(val != 0 and not val) or
|
||||
(self._use_class_attr and name not in self.__dict__) ):
|
||||
raise AttributeError(
|
||||
f'attribute {name!r} of {type(self).__name__} object is already set,'
|
||||
+ ' and resetting is forbidden' )
|
||||
|
|
|
|||
|
|
@ -40,6 +40,16 @@ class unit_test(object):
|
|||
acc.bar = 'bar val'
|
||||
acc.bar = 1 # class attribute bar is None, so can be set to any type
|
||||
|
||||
class MyAttrCtrlDflNone(AttrCtrl):
|
||||
_default_to_none = True
|
||||
foo = 'fooval'
|
||||
bar = None
|
||||
|
||||
acdn = MyAttrCtrlDflNone()
|
||||
assert acdn.foo == 'fooval', f'{acdn.foo}'
|
||||
assert acdn.bar == None, f'{acdn.bar}'
|
||||
assert acdn.baz == None, f'{acdn.baz}'
|
||||
|
||||
qmsg('OK')
|
||||
qmsg_r('Testing class Lockable...')
|
||||
|
||||
|
|
@ -102,6 +112,14 @@ class unit_test(object):
|
|||
assert lca._lock == True
|
||||
assert lca.foo == True
|
||||
|
||||
class MyLockableAutolockDflNone(Lockable):
|
||||
_default_to_none = True
|
||||
foo = 0
|
||||
|
||||
lcdn = MyLockableAutolockDflNone()
|
||||
assert lcdn.foo == 0
|
||||
assert lcdn.bar == None
|
||||
|
||||
class MyLockableBad(Lockable):
|
||||
_set_ok = ('foo','bar')
|
||||
foo = 1
|
||||
|
|
@ -131,15 +149,22 @@ class unit_test(object):
|
|||
def bad17(): lb = MyLockableBad()
|
||||
def bad18(): aca.lock()
|
||||
|
||||
def bad19(): acdn.baz = None
|
||||
def bad20(): lcdn.foo = 1
|
||||
def bad21(): lcdn.bar = None
|
||||
|
||||
ut.process_bad_data((
|
||||
('attr (1)', 'AttributeError', 'has no attr', bad1 ),
|
||||
('attr (2)', 'AttributeError', 'has no attr', bad9 ),
|
||||
('attr (3)', 'AttributeError', 'has no attr', bad10 ),
|
||||
('attr (4)', 'AttributeError', 'has no attr', bad19 ),
|
||||
('attr (5)', 'AttributeError', 'has no attr', bad21 ),
|
||||
('attr type (1)', 'AttributeError', 'type', bad2 ),
|
||||
("attr type (2)", 'AttributeError', 'type', bad4 ),
|
||||
("attr type (3)", 'AttributeError', 'type', bad5 ),
|
||||
("attr (can't set)", 'AttributeError', 'read-only', bad6 ),
|
||||
("attr (can't set)", 'AttributeError', 'read-only', bad7 ),
|
||||
("attr (can't set)", 'AttributeError', 'read-only', bad20 ),
|
||||
("attr (can't reset)", 'AttributeError', 'reset', bad3 ),
|
||||
("attr (can't reset)", 'AttributeError', 'reset', bad8 ),
|
||||
("attr (can't reset)", 'AttributeError', 'reset', bad11 ),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue