util.py: new isAsync() function

This commit is contained in:
The MMGen Project 2025-10-01 15:30:56 +00:00
commit 6ccf29fb21
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
7 changed files with 32 additions and 31 deletions

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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:

View file

@ -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