Browse Source

AttrCtrl,Lockable: add autolocking

The MMGen Project 4 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
 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
 	After instance is locked, forbid setting any attribute if the attribute is not present
 	in either the class or instance dict.
 	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
 	attribute, if _use_class_attr is True.  If the instance or class attribute is set
 	to None, no type checking is performed.
 	to None, no type checking is performed.
 	"""
 	"""
+	_autolock = True
 	_lock = False
 	_lock = False
 	_use_class_attr = False
 	_use_class_attr = False
 	_skip_type_check = ()
 	_skip_type_check = ()

+ 0 - 6
mmgen/daemon.py

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

+ 1 - 0
mmgen/globalvars.py

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

+ 1 - 0
mmgen/opts.py

@@ -27,6 +27,7 @@ from .base_obj import Lockable
 import mmgen.share.Opts
 import mmgen.share.Opts
 
 
 class UserOpts(Lockable):
 class UserOpts(Lockable):
+	_autolock = False
 	_set_ok = ('usr_randchars',)
 	_set_ok = ('usr_randchars',)
 	_reset_ok = ('quiet','verbose','yes')
 	_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...')
 		qmsg_r('Testing class Lockable...')
 
 
 		class MyLockable(Lockable): # class has no attrs, like UserOpts
 		class MyLockable(Lockable): # class has no attrs, like UserOpts
+			_autolock = False
 			_set_ok = ('foo','baz','alpha','beta','gamma','delta','epsilon')
 			_set_ok = ('foo','baz','alpha','beta','gamma','delta','epsilon')
 			_reset_ok = ('bar','baz')
 			_reset_ok = ('bar','baz')
 
 
@@ -66,6 +67,7 @@ class unit_test(object):
 		lc.epsilon = [0]
 		lc.epsilon = [0]
 
 
 		class MyLockableClsCheck(Lockable): # class has attrs, like GlobalContext
 		class MyLockableClsCheck(Lockable): # class has attrs, like GlobalContext
+			_autolock = False
 			_use_class_attr = True
 			_use_class_attr = True
 			_set_ok = ('foo','baz')
 			_set_ok = ('foo','baz')
 			_reset_ok = ('bar','baz')
 			_reset_ok = ('bar','baz')
@@ -82,9 +84,22 @@ class unit_test(object):
 		lcc.bar = 3   # bar is in reset list
 		lcc.bar = 3   # bar is in reset list
 		lcc.baz = 3.2
 		lcc.baz = 3.2
 		lcc.baz = 3.1 # baz is in both lists
 		lcc.baz = 3.1 # baz is in both lists
+
 		qmsg('OK')
 		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 bad1(): ac.x = 1
 		def bad2(): acc.foo = 1
 		def bad2(): acc.foo = 1
@@ -103,6 +118,8 @@ class unit_test(object):
 		def bad14(): lc.delta = float(0)
 		def bad14(): lc.delta = float(0)
 		def bad15(): lc.epsilon = [0]
 		def bad15(): lc.epsilon = [0]
 
 
+		def bad16(): lca.foo = None
+
 		ut.process_bad_data((
 		ut.process_bad_data((
 			('attr (1)',           'AttributeError', 'has no attr', bad1 ),
 			('attr (1)',           'AttributeError', 'has no attr', bad1 ),
 			('attr (2)',           'AttributeError', 'has no attr', bad9 ),
 			('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',       bad13 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad14 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad14 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad15 ),
 			("attr (can't reset)", 'AttributeError', 'reset',       bad15 ),
+			("attr (can't set)",   'AttributeError', 'read-only',   bad16 ),
 		))
 		))
 
 
 		qmsg('OK')
 		qmsg('OK')