Browse Source

util.py: new `isAsync()` function

The MMGen Project 2 months ago
parent
commit
6ccf29fb21
7 changed files with 32 additions and 31 deletions
  1. 3 5
      mmgen/main_tool.py
  2. 3 3
      mmgen/proto/btc/regtest.py
  3. 6 6
      mmgen/rpc/local.py
  4. 8 6
      mmgen/tw/view.py
  5. 3 0
      mmgen/util.py
  6. 7 7
      test/include/unit_test.py
  7. 2 4
      test/tooltest2.py

+ 3 - 5
mmgen/main_tool.py

@@ -23,7 +23,7 @@ mmgen-tool:  Perform various MMGen- and cryptocoin-related operations.
 
 import sys, os, importlib
 from .cfg import gc, Config
-from .util import msg, Msg, die, capfirst, suf, async_run
+from .util import msg, Msg, die, capfirst, suf, async_run, isAsync
 
 opts_data = {
 	'filter_codes': ['-'],
@@ -391,10 +391,8 @@ if gc.prog_name.endswith('-tool'):
 
 	args, kwargs = process_args(cmd, args, cls)
 
-	ret = getattr(cls(cfg, cmdname=cmd), cmd)(*args, **kwargs)
-
-	if type(ret).__name__ == 'coroutine':
-		ret = async_run(ret)
+	func = getattr(cls(cfg, cmdname=cmd), cmd)
+	ret = async_run(func(*args, **kwargs)) if isAsync(func) else func(*args, **kwargs)
 
 	process_result(
 		ret,

+ 3 - 3
mmgen/proto/btc/regtest.py

@@ -21,7 +21,7 @@ proto.btc.regtest: Coin daemon regression test mode setup and operations
 """
 
 import os, shutil, json
-from ...util import msg, gmsg, die, capfirst, suf
+from ...util import msg, gmsg, die, capfirst, suf, isAsync
 from ...util2 import cliargs_convert
 from ...protocol import init_proto
 from ...rpc import rpc_init
@@ -256,8 +256,8 @@ class MMGenRegtest(MMGenObject):
 		print(ret if isinstance(ret, str) else json.dumps(ret, cls=json_encoder, indent=4))
 
 	async def cmd(self, args):
-		ret = getattr(self, args[0])(*args[1:])
-		return (await ret) if type(ret).__name__ == 'coroutine' else ret
+		func = getattr(self, args[0])
+		return await func(*args[1:]) if isAsync(func) else func(*args[1:])
 
 	async def fork(self, coin): # currently disabled
 

+ 6 - 6
mmgen/rpc/local.py

@@ -14,7 +14,7 @@ rpc.local: local RPC client class for the MMGen Project
 
 import sys, json, asyncio, importlib
 
-from ..util import msg, die, fmt, oneshot_warning
+from ..util import msg, die, fmt, oneshot_warning, isAsync
 
 from . import util
 
@@ -55,7 +55,7 @@ class RPCClient:
 		self.timeout = self.cfg.http_timeout or 60
 		self.auth = None
 
-	def _get_backend(self, backend):
+	def _get_backend_cls(self, backend):
 		dfl_backends = {
 			'linux': 'httplib',
 			'darwin': 'httplib',
@@ -63,14 +63,14 @@ class RPCClient:
 		def get_cls(backend_id):
 			return getattr(importlib.import_module(f'mmgen.rpc.backends.{backend_id}'), backend_id)
 		backend_id = backend or self.cfg.rpc_backend
-		return get_cls(dfl_backends[sys.platform] if backend_id == 'auto' else backend_id)(self)
+		return get_cls(dfl_backends[sys.platform] if backend_id == 'auto' else backend_id)
 
 	def set_backend(self, backend=None):
-		self.backend = self._get_backend(backend)
+		self.backend = self._get_backend_cls(backend)(self)
 
 	async def set_backend_async(self, backend=None):
-		ret = self._get_backend(backend)
-		self.backend = (await ret) if type(ret).__name__ == 'coroutine' else ret
+		cls = self._get_backend_cls(backend)
+		self.backend = await cls(self) if isAsync(cls.__init__) else cls(self)
 
 	# Call family of methods - direct-to-daemon RPC call:
 	# - positional params are passed to the daemon, 'timeout' and 'wallet' kwargs to the backend

+ 8 - 6
mmgen/tw/view.py

@@ -27,7 +27,7 @@ from ..cfg import gv
 from ..objmethods import MMGenObject
 from ..obj import get_obj, MMGenIdx, MMGenList
 from ..color import nocolor, yellow, orange, green, red, blue
-from ..util import msg, msg_r, fmt, die, capfirst, suf, make_timestr
+from ..util import msg, msg_r, fmt, die, capfirst, suf, make_timestr, isAsync
 from ..rpc import rpc_init
 from ..base_obj import AsyncInit
 
@@ -288,8 +288,10 @@ class TwView(MMGenObject, metaclass=AsyncInit):
 
 		lbl_id = ('account', 'label')['label_api' in self.rpc.caps]
 
-		res = self.gen_data(rpc_data, lbl_id)
-		self.data = MMGenList(await res if type(res).__name__ == 'coroutine' else res)
+		self.data = MMGenList(
+			await self.gen_data(rpc_data, lbl_id) if isAsync(self.gen_data) else
+			self.gen_data(rpc_data, lbl_id))
+
 		self.disp_data = list(self.filter_data())
 
 		if not self.data:
@@ -607,9 +609,9 @@ class TwView(MMGenObject, metaclass=AsyncInit):
 
 			match reply:
 				case ch if ch in key_mappings:
-					ret = action_classes[ch].run(self, action_methods[ch])
-					if type(ret).__name__ == 'coroutine':
-						await ret
+					func = action_classes[ch].run
+					arg = action_methods[ch]
+					await func(self, arg) if isAsync(func) else func(self, arg)
 				case 'q':
 					msg('')
 					if self.scroll:

+ 3 - 0
mmgen/util.py

@@ -487,3 +487,6 @@ def cached_property(orig_func):
 			setattr(self, attr_name, orig_func(self))
 		return getattr(self, attr_name)
 	return new_func
+
+def isAsync(func):
+	return bool(func.__code__.co_flags & 128)

+ 7 - 7
test/include/unit_test.py

@@ -32,7 +32,7 @@ if not os.getenv('MMGEN_DEVTOOLS'):
 
 from mmgen.cfg import Config, gc, gv
 from mmgen.color import gray, brown, orange, yellow, red
-from mmgen.util import msg, msg_r, gmsg, ymsg, Msg
+from mmgen.util import msg, msg_r, gmsg, ymsg, Msg, isAsync
 
 from test.include.common import set_globals, end_msg
 
@@ -151,9 +151,7 @@ class UnitTestHelpers:
 		for (desc, exc_chk, emsg_chk, func) in data:
 			try:
 				cfg._util.vmsg_r('  {}{:{w}}'.format(pfx, desc+':', w=desc_w+1))
-				ret = func()
-				if type(ret).__name__ == 'coroutine':
-					asyncio.run(ret)
+				asyncio.run(func()) if isAsync(func) else func()
 			except Exception as e:
 				exc = type(e).__name__
 				emsg = e.args[0] if e.args else '(unspecified error)'
@@ -187,9 +185,11 @@ def run_test(test, subtest=None):
 				elif not cfg.quiet:
 					msg_r(f'Testing {func.__defaults__[0]}...')
 
-			ret = func(test, UnitTestHelpers(subtest))
-			if type(ret).__name__ == 'coroutine':
-				ret = asyncio.run(ret)
+			if isAsync(func):
+				ret = asyncio.run(func(test, UnitTestHelpers(subtest)))
+			else:
+				ret = func(test, UnitTestHelpers(subtest))
+
 			if do_desc and not cfg.quiet:
 				msg('OK\n' if cfg.verbose else 'OK')
 		except:

+ 2 - 4
test/tooltest2.py

@@ -36,7 +36,7 @@ from test.include.common import set_globals, end_msg, init_coverage
 from mmgen import main_tool
 from mmgen.cfg import Config
 from mmgen.color import green, blue, purple, cyan, gray
-from mmgen.util import msg, msg_r, Msg, die
+from mmgen.util import msg, msg_r, Msg, die, isAsync
 
 skipped_tests = ['mn2hex_interactive']
 coin_dependent_groups = ('Coin', 'File')
@@ -134,9 +134,7 @@ def call_method(cls, method, cmd_name, args, mmtype, stdin_input):
 			vmsg(f'Input: {stdin_input!r}')
 			sys.exit(0)
 	else:
-		ret = method(*aargs, **kwargs)
-		if type(ret).__name__ == 'coroutine':
-			ret = asyncio.run(ret)
+		ret = asyncio.run(method(*aargs, **kwargs)) if isAsync(method) else method(*aargs, **kwargs)
 		cfg._set_quiet(oq_save)
 		return ret