From a904cb78535e529901a5ee75e372436b45a55041 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sat, 29 Aug 2026 15:04:24 +0000 Subject: [PATCH] cfg: opts_data['sets']: improve output, add tests --- mmgen/cfg.py | 24 ++++++++++++++++-------- test/cmdtest_d/opts.py | 19 ++++++++++++++++++- test/misc/opts_main.py | 7 ++++++- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/mmgen/cfg.py b/mmgen/cfg.py index 847e5d99..f05f0aa6 100755 --- a/mmgen/cfg.py +++ b/mmgen/cfg.py @@ -32,6 +32,15 @@ def die2(exit_val, s): sys.stderr.write(s+'\n') sys.exit(exit_val) +def fmt_opt_val(opt, val): + match val: + case True: + return '--{}'.format(opt.replace('_', '-')) + case False: + return '--no-{}'.format(opt.replace('_', '-')) + case _: + return '--{}={}'.format(opt.replace('_', '-'), val) + class GlobalConstants(Lockable): """ These values are non-runtime-configurable. They’re constant for a given machine, @@ -575,9 +584,10 @@ class Config(Lockable): # Step 7: set auto typeset opts from user-supplied data or cfgfile data, in that order: self._set_auto_typeset_opts(self._cfgfile_opts.auto_typeset) - # Step 8: set opts_data['sets'] opts: - if opts_data and 'sets' in opts_data: - self._set_opts_data_sets_opts(opts_data) + # Step 8: process opts_data['sets']: + if opts_data: + if 'sets' in opts_data: + self._set_opts_data_sets_opts(opts_data) if 'usage' in self._uopts: # requires self.coin import importlib @@ -775,11 +785,9 @@ class Config(Lockable): if ((usr_b_val := getattr(self, b_opt, None)) in (None, False)) or usr_b_val == b_val: setattr(self, b_opt, b_val) else: - die(1, 'Option --{}={} conflicts with option --{}={}\n'.format( - b_opt.replace('_', '-'), - usr_b_val, - a_opt.replace('_', '-'), - usr_a_val)) + die('UserOptError', 'Option {} conflicts with option {}\n'.format( + fmt_opt_val(b_opt, usr_b_val), + fmt_opt_val(a_opt, usr_a_val))) def _die_on_incompatible_opts(self): for group in self._incompatible_opts: diff --git a/test/cmdtest_d/opts.py b/test/cmdtest_d/opts.py index b87a8777..fb45e560 100755 --- a/test/cmdtest_d/opts.py +++ b/test/cmdtest_d/opts.py @@ -52,11 +52,15 @@ class CmdTestOpts(CmdTestBase): ('opt_good29', (41, 'good cmdline opt (--etc-max-tx-fee=0.1)', [])), ('opt_good30', (41, 'good cmdline opt (--eth-chain-names=foo,bar)', [])), ('opt_good31', (41, 'good cmdline opt (--xmr-rpc-port=28081)', [])), + ('opt_good32', (41, 'good cmdline opt (A sets B)', [])), + ('opt_good33', (41, 'good cmdline opt (A sets not B)', [])), ('opt_bad_param', (41, 'bad global opt (--pager=1)', [])), ('opt_bad_infile', (41, 'bad infile parameter', [])), ('opt_bad_outdir', (41, 'bad outdir parameter', [])), ('opt_bad_incompatible', (41, 'incompatible opts', [])), ('opt_bad_autoset', (41, 'invalid autoset value', [])), + ('opt_bad_sets1', (41, "invalid value for opts_data['sets']", [])), + ('opt_bad_sets2', (41, "invalid value for opts_data['sets']", [])), ('opt_invalid_1', (41, 'invalid cmdline opt ‘--x’', [])), ('opt_invalid_2', (41, 'invalid cmdline opt ‘---’', [])), ('opt_invalid_5', (41, 'invalid cmdline opt (missing parameter)', [])), @@ -111,7 +115,8 @@ class CmdTestOpts(CmdTestBase): def do_run(self, args, expect, exit_val, regex=False): t = self.spawn_prog(args, exit_val=exit_val or None) - t.expect(expect, regex=regex) + if expect: + t.expect(expect, regex=regex) return t def opt_helpscreen(self): @@ -308,6 +313,12 @@ class CmdTestOpts(CmdTestBase): (('cfg.xmr_rpc_port', '28081'),('proto.rpc_port', '28081'),), need_proto = True) + def opt_good32(self): + return self.do_run(['--in-fmt=hex', '--no-foobleize'], None, 0) + + def opt_good33(self): + return self.do_run(['--silent', '--no-verbose'], None, 0) + def opt_bad_param(self): return self.do_run(['--pager=1'], 'no parameter', 1) @@ -325,6 +336,12 @@ class CmdTestOpts(CmdTestBase): def opt_bad_autoset(self): return self.do_run(['--fee-estimate-mode=Fubar'], 'not unique substring', 1) + def opt_bad_sets1(self): + return self.do_run(['--silent', '--verbose'], 'conflicts with', 1) + + def opt_bad_sets2(self): + return self.do_run(['--no-foobleize', '--in-fmt=csv'], 'conflicts with', 1) + def opt_invalid(self, args, expect, opts=[], need_proto=False, exit_val=1): t = self.spawn_prog(args, opts=opts, exit_val=exit_val, need_proto=need_proto) t.expect(expect) diff --git a/test/misc/opts_main.py b/test/misc/opts_main.py index 7cc65a24..2ffdc310 100755 --- a/test/misc/opts_main.py +++ b/test/misc/opts_main.py @@ -6,7 +6,11 @@ from mmgen.cfg import Config from mmgen.util import msg opts_data = { - 'sets': [('print_checksum', True, 'quiet', True)], + 'sets': [ + ('print_checksum', True, 'quiet', True), + ('silent', True, 'verbose', False), + ('no_foobleize', True, 'in_fmt', 'hex'), + ], 'text': { 'desc': 'Opts test', 'usage':'[args] [opts]', @@ -29,6 +33,7 @@ opts_data = { -p, --hash-preset= p Use the scrypt hash parameters defined by preset 'p' -P, --passwd-file= f Get wallet passphrase from file 'f' -q, --quiet Be quieter +-s, --silent Be silent -t, --min-temp= t Minimum temperature (in degrees Celsius) -T, --max-temp= t Maximum temperature (in degrees Celsius) -x, --point= P Point in Euclidean space