From 69288c3cb0eeed27619774f0d3599e1dca41d400 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 7 Aug 2026 09:37:46 +0000 Subject: [PATCH] ruff B009 (`getattr` with constant attribute value) --- mmgen/cfg.py | 2 +- mmgen/keygen.py | 5 ++--- mmgen/main_tool.py | 4 ++-- mmgen/msg.py | 5 ++--- mmgen/proto/cosmos/tx/protobuf.py | 2 +- mmgen/tx/completed.py | 4 ++-- mmgen/util.py | 4 ++-- mmgen/wallet/__init__.py | 9 +++------ pyproject.toml | 1 - test/include/unit_test.py | 10 +++++----- test/objattrtest.py | 2 +- test/objtest.py | 2 +- test/tooltest2.py | 4 ++-- 13 files changed, 24 insertions(+), 30 deletions(-) diff --git a/mmgen/cfg.py b/mmgen/cfg.py index 06c0e256..215ea163 100755 --- a/mmgen/cfg.py +++ b/mmgen/cfg.py @@ -577,7 +577,7 @@ class Config(Lockable): if 'usage' in self._uopts: # requires self.coin import importlib - getattr(importlib.import_module(UserOpts.help_pkg), 'usage')(self) # exits + importlib.import_module(UserOpts.help_pkg).usage(self) # exits # self.color is finalized, so initialize color: if self.color: # MMGEN_DISABLE_COLOR sets this to False diff --git a/mmgen/keygen.py b/mmgen/keygen.py index de9ff592..ce8ef7e0 100755 --- a/mmgen/keygen.py +++ b/mmgen/keygen.py @@ -70,9 +70,8 @@ def get_backends(pubkey_type): def get_pubkey_type_cls(pubkey_type): import importlib - return getattr( - importlib.import_module(f'mmgen.proto.{backend_data[pubkey_type]["package"]}.keygen'), - 'backend') + return importlib.import_module( + f'mmgen.proto.{backend_data[pubkey_type]["package"]}.keygen').backend def _check_backend(cfg, backend, pubkey_type, *, desc='keygen backend'): diff --git a/mmgen/main_tool.py b/mmgen/main_tool.py index 4d4f4dc2..ccc3df17 100755 --- a/mmgen/main_tool.py +++ b/mmgen/main_tool.py @@ -348,11 +348,11 @@ def process_result(ret, *, pager=False, print_result=False): def get_cmd_cls(cmd): for modname, cmdlist in mods.items(): if cmd in cmdlist: - return getattr(importlib.import_module(f'mmgen.tool.{modname}'), 'tool_cmd') + return importlib.import_module(f'mmgen.tool.{modname}').tool_cmd return False def get_mod_cls(modname): - return getattr(importlib.import_module(f'mmgen.tool.{modname}'), 'tool_cmd') + return importlib.import_module(f'mmgen.tool.{modname}').tool_cmd if gc.prog_name.endswith('-tool'): diff --git a/mmgen/msg.py b/mmgen/msg.py index 9ec495c1..353991b3 100755 --- a/mmgen/msg.py +++ b/mmgen/msg.py @@ -365,9 +365,8 @@ def _get_obj(clsname, cfg, *args, coin=None, network='mainnet', infile=None, dat coin_msg.base.get_proto_from_file(cfg, infile)) try: - msg_cls = getattr( - importlib.import_module(f'mmgen.proto.{proto.base_proto_coin.lower()}.msg'), - 'coin_msg') + msg_cls = importlib.import_module( + f'mmgen.proto.{proto.base_proto_coin.lower()}.msg').coin_msg except: die(1, f'Message signing operations not supported for {proto.base_proto} protocol') diff --git a/mmgen/proto/cosmos/tx/protobuf.py b/mmgen/proto/cosmos/tx/protobuf.py index f7ecaa40..7de70bc1 100755 --- a/mmgen/proto/cosmos/tx/protobuf.py +++ b/mmgen/proto/cosmos/tx/protobuf.py @@ -113,7 +113,7 @@ class TxMsg(BaseMessage): msg_cls = getattr(cls.msgs_cls, id.removeprefix('/types.')) me = BaseMessage.__new__(msg_cls) me.id = id - me.body = getattr(msg_cls, 'Body').loads(bodyBytes) + me.body = msg_cls.Body.loads(bodyBytes) return me @dataclass diff --git a/mmgen/tx/completed.py b/mmgen/tx/completed.py index 36553530..f18e32ec 100755 --- a/mmgen/tx/completed.py +++ b/mmgen/tx/completed.py @@ -64,7 +64,7 @@ class Completed(Base): from .unsigned import Unsigned, AutomountUnsigned from .online import Sent, AutomountSent for cls in (Unsigned, AutomountUnsigned, Sent, AutomountSent): - if ext == getattr(cls, 'ext'): + if ext == cls.ext: return cls if proto.tokensym: @@ -73,7 +73,7 @@ class Completed(Base): else: from .signed import Signed, AutomountSigned for cls in (Signed, AutomountSigned): - if ext == getattr(cls, 'ext'): + if ext == cls.ext: return cls def check_swap_memo(self): diff --git a/mmgen/util.py b/mmgen/util.py index 3c09fd3e..0cbc1c18 100755 --- a/mmgen/util.py +++ b/mmgen/util.py @@ -408,12 +408,12 @@ class oneshot_warning: def do_warning(): from . import color - msg(getattr(color, getattr(wcls, 'color'))('WARNING: ' + getattr(wcls, 'message').format(*fmt_args))) + msg(getattr(color, wcls.color)('WARNING: ' + wcls.message.format(*fmt_args))) if not hasattr(wcls, 'data'): setattr(wcls, 'data', []) - data = getattr(wcls, 'data') + data = wcls.data condition = (div in data) if reverse else (not div in data) if not div in data: diff --git a/mmgen/wallet/__init__.py b/mmgen/wallet/__init__.py index 76885e4b..f442b1df 100755 --- a/mmgen/wallet/__init__.py +++ b/mmgen/wallet/__init__.py @@ -79,15 +79,12 @@ def get_wallet_cls( ext = None, die_on_fail = False): - return getattr( - importlib.import_module('mmgen.wallet.{}'.format( + return importlib.import_module('mmgen.wallet.{}'.format( wtype or get_wallet_data( fmt_code = fmt_code, ext = ext, - die_on_fail = die_on_fail).type - )), - 'wallet') + die_on_fail = die_on_fail).type)).wallet def get_wallet_extensions(key): return { @@ -109,7 +106,7 @@ def format_fmt_codes(): return '\n'.join(ret) + '\n' def _get_me(modname): - return MMGenObject.__new__(getattr(importlib.import_module(f'mmgen.wallet.{modname}'), 'wallet')) + return MMGenObject.__new__(importlib.import_module(f'mmgen.wallet.{modname}').wallet) def Wallet( cfg, diff --git a/pyproject.toml b/pyproject.toml index fc1395f2..37ebc28f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ indent-style = "tab" ignore = [ "ASYNC221", # blocking method in async function (mmgen/rpc/backends/curl.py) "B006", # Do not use mutable data structures for argument defaults - "B009", # Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. "B010", # Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. "B018", # Found useless expression. Either assign it to a variable or remove it. "B023", # Function definition does not bind loop variable `confs` diff --git a/test/include/unit_test.py b/test/include/unit_test.py index 7e67c402..e559c6ca 100755 --- a/test/include/unit_test.py +++ b/test/include/unit_test.py @@ -106,8 +106,8 @@ if cfg.list_subtests: for test in all_tests: mod = importlib.import_module(f'test.{test_subdir}.{test}') if hasattr(mod, 'unit_tests'): - t = getattr(mod, 'unit_tests') - subtests = [k for k, v in t.__dict__.items() if type(v).__name__ == 'function' and k[0] != '_'] + subtests = [k for k, v in mod.unit_tests.__dict__.items() + if type(v).__name__ == 'function' and k[0] != '_'] yield fs.format(test, ' '.join(f'{subtest}' for subtest in subtests)) else: yield test @@ -173,7 +173,7 @@ def run_test(test, subtest=None): silence() if hasattr(t, '_pre_subtest'): - getattr(t, '_pre_subtest')(test, subtest, UnitTestHelpers(subtest)) + t._pre_subtest(test, subtest, UnitTestHelpers(subtest)) try: func = getattr(t, subtest.replace('-', '_')) @@ -198,7 +198,7 @@ def run_test(test, subtest=None): raise if hasattr(t, '_post_subtest'): - getattr(t, '_post_subtest')(test, subtest, UnitTestHelpers(subtest)) + t._post_subtest(test, subtest, UnitTestHelpers(subtest)) if getattr(t, 'silence_output', False): end_silence() @@ -217,7 +217,7 @@ def run_test(test, subtest=None): mod = importlib.import_module(f'test.{test_subdir}.{test}') if hasattr(mod, 'unit_tests'): # new class-based API - t = getattr(mod, 'unit_tests')() + t = mod.unit_tests() altcoin_deps = getattr(t, 'altcoin_deps', ()) win_skip = getattr(t, 'win_skip', ()) mac_skip = getattr(t, 'mac_skip', ()) diff --git a/test/objattrtest.py b/test/objattrtest.py index 713f8b13..fc35f1ea 100755 --- a/test/objattrtest.py +++ b/test/objattrtest.py @@ -167,7 +167,7 @@ def do_loop(): import importlib modname = f'test.objattrtest_d.{proto.coin.lower()}_{proto.network}' mod = importlib.import_module(modname) - test_data = getattr(mod, 'tests') + test_data = mod.tests gmsg(f'Running immutable attribute tests for {proto.coin} {proto.network}') utests = cfg._args diff --git a/test/objtest.py b/test/objtest.py index c95693fe..18ed1913 100755 --- a/test/objtest.py +++ b/test/objtest.py @@ -183,7 +183,7 @@ def do_loop(): import importlib modname = f'test.objtest_d.{proto.coin.lower()}_{proto.network}' mod = importlib.import_module(modname) - test_data = getattr(mod, 'tests') + test_data = mod.tests gmsg(f'Running data object tests for {proto.coin} {proto.network}') clr = None diff --git a/test/tooltest2.py b/test/tooltest2.py index 19c89809..6354d555 100755 --- a/test/tooltest2.py +++ b/test/tooltest2.py @@ -338,8 +338,8 @@ if cfg.tool_api: if cfg.list_tests: Msg('Available tests:') for modname, cmdlist in main_tool.mods.items(): - cls = getattr(importlib.import_module(f'mmgen.tool.{modname}'), 'tool_cmd') - Msg(f' {modname:6} - {docstring_head(cls)}') + cls = importlib.import_module(f'mmgen.tool.{modname}').tool_cmd + Msg(f' {modname:10} - {docstring_head(cls)}') sys.exit(0) if cfg.list_tested_cmds: