Browse Source

AttrCtrl,Lockable: add autolocking

The MMGen Project 3 years ago
parent
commit
ca86da1c1b
5 changed files with 30 additions and 8 deletions
  1. 9 1
      mmgen/base_obj.py
  2. 0 6
      mmgen/daemon.py
  3. 1 0
      mmgen/globalvars.py
  4. 1 0
      mmgen/opts.py
  5. 19 1
      test/unit_tests_d/ut_lockable.py

+ 9 - 1
mmgen/base_obj.py

@@ -20,7 +20,14 @@
 base_obj.py: base objects with no internal imports for the MMGen suite
 """
 
-class AttrCtrl:
+class AttrCtrlMeta(type):
+	def __call__(cls,*args,**kwargs):
+		instance = super().__call__(*args,**kwargs)
+		if instance._autolock:
+			instance._lock = True
+		return instance
+
+class AttrCtrl(metaclass=AttrCtrlMeta):
 	"""
 	After instance is locked, forbid setting any attribute if the attribute is not present
 	in either the class or instance dict.
@@ -29,6 +36,7 @@ class AttrCtrl:
 	attribute, if _use_class_attr is True.  If the instance or class attribute is set
 	to None, no type checking is performed.
 	"""
+	_autolock = True
 	_lock = False
 	_use_class_attr = False
 	_skip_type_check = ()

+ 0 - 6
mmgen/daemon.py

@@ -309,8 +309,6 @@ class MoneroWalletDaemon(RPCDaemon):
 			['--stagenet',                           self.network == 'testnet'],
 		)
 
-		self.lock()
-
 class CoinDaemon(Daemon):
 	networks = ('mainnet','testnet','regtest')
 	cfg_file_hdr = ''
@@ -439,8 +437,6 @@ class CoinDaemon(Daemon):
 
 		self.init_subclass()
 
-		self.lock()
-
 	def init_datadir(self):
 		if self.test_suite:
 			return os.path.join('test','daemons',self.coin.lower())
@@ -774,5 +770,3 @@ class erigon_rpcdaemon(RPCDaemon):
 			['--http.api=eth,web3,txpool'],
 			[f'--http.port={self.rpc_port}'],
 		)
-
-		self.lock()

+ 1 - 0
mmgen/globalvars.py

@@ -40,6 +40,7 @@ class GlobalContext(Lockable):
 	  2 - environmental vars
 	  3 - command line
 	"""
+	_autolock = False
 	_set_ok = ('user_entropy','session')
 	_reset_ok = ('stdout','stderr','accept_defaults')
 	_use_class_attr = True

+ 1 - 0
mmgen/opts.py

@@ -27,6 +27,7 @@ from .base_obj import Lockable
 import mmgen.share.Opts
 
 class UserOpts(Lockable):
+	_autolock = False
 	_set_ok = ('usr_randchars',)
 	_reset_ok = ('quiet','verbose','yes')
 

+ 19 - 1
test/unit_tests_d/ut_lockable.py

@@ -39,6 +39,7 @@ class unit_test(object):
 		qmsg_r('Testing class Lockable...')
 
 		class MyLockable(Lockable): # class has no attrs, like UserOpts
+			_autolock = False
 			_set_ok = ('foo','baz','alpha','beta','gamma','delta','epsilon')
 			_reset_ok = ('bar','baz')
 
@@ -66,6 +67,7 @@ class unit_test(object):
 		lc.epsilon = [0]
 
 		class MyLockableClsCheck(Lockable): # class has attrs, like GlobalContext
+			_autolock = False
 			_use_class_attr = True
 			_set_ok = ('foo','baz')
 			_reset_ok = ('bar','baz')
@@ -82,9 +84,22 @@ class unit_test(object):
 		lcc.bar = 3   # bar is in reset list
 		lcc.baz = 3.2
 		lcc.baz = 3.1 # baz is in both lists
+
 		qmsg('OK')
+		qmsg_r('Testing class Lockable with autolock...')
+
+		class MyLockableAutolock(Lockable):
+			def __init__(self):
+				self.foo = True
 
-		qmsg('Checking error handling:')
+		lca = MyLockableAutolock()
+		assert lca._autolock == True
+		assert lca._lock == True
+		assert lca.foo == True
+
+		qmsg('OK')
+		qmsg_r('Checking error handling...')
+		vmsg('')
 
 		def bad1(): ac.x = 1
 		def bad2(): acc.foo = 1
@@ -103,6 +118,8 @@ class unit_test(object):
 		def bad14(): lc.delta = float(0)
 		def bad15(): lc.epsilon = [0]
 
+		def bad16(): lca.foo = None
+
 		ut.process_bad_data((
 			('attr (1)',           'AttributeError', 'has no attr', bad1 ),
 			('attr (2)',           'AttributeError', 'has no attr', bad9 ),
@@ -119,6 +136,7 @@ class unit_test(object):
 			("attr (can't reset)", 'AttributeError', 'reset',       bad13 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad14 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad15 ),
+			("attr (can't set)",   'AttributeError', 'read-only',   bad16 ),
 		))
 
 		qmsg('OK')