global_platform: install_cap_parser: argument groups cannot be nested

pySim-shell currently does not work on systems with Python 3.14+:

  File ".../pysim/pySim/global_platform/__init__.py", line 868, in AddlShellCommands
    install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group()
  File "/usr/lib/python3.14/argparse.py", line 1794, in add_argument_group
    raise ValueError('argument groups cannot be nested')
  ValueError('argument groups cannot be nested')

The problem is that install_cap_parser creates a nested group inside
of mutually exclusive group.  argparse never supported group nesting
properly, so it has been deprecated since Python 3.11, and eventually
got removed in Python 3.14.

Remove group nesting, adjust the usage string, and implement the
mutual exclusiveness/inclusiveness manually in do_install_cap().

Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579
This commit is contained in:
Vadim Yanitskiy
2026-03-10 18:29:17 +07:00
parent a5a5865c7c
commit 27031e78d9

View File

@@ -859,22 +859,28 @@ class ADF_SD(CardADF):
_rsp_hex, _sw = self._cmd.lchan.scc.send_apdu_checksw(cmd_hex) _rsp_hex, _sw = self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)
self._cmd.poutput("Loaded a total of %u bytes in %u blocks. Don't forget install_for_install (and make selectable) now!" % (total_size, block_nr)) self._cmd.poutput("Loaded a total of %u bytes in %u blocks. Don't forget install_for_install (and make selectable) now!" % (total_size, block_nr))
install_cap_parser = argparse.ArgumentParser() install_cap_parser = argparse.ArgumentParser(usage='%(prog)s FILE (--install-parameters | --install-parameters-*)')
install_cap_parser.add_argument('cap_file', type=str, metavar='FILE', install_cap_parser.add_argument('cap_file', type=str, metavar='FILE',
help='JAVA-CARD CAP file to install') help='JAVA-CARD CAP file to install')
install_cap_parser_inst_prm_g = install_cap_parser.add_mutually_exclusive_group() # Ideally, the parser should enforce that:
install_cap_parser_inst_prm_g.add_argument('--install-parameters', type=is_hexstr, default=None, # * either the `--install-parameters` is given alone,
help='install Parameters (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') # * or all `--install-parameters-*` are given together.
install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group() # We tried to achieve this using mutually exclusive groups (add_mutually_exclusive_group).
install_cap_parser_inst_prm_g_grp.add_argument('--install-parameters-volatile-memory-quota', # However, group nesting was never supported, often failed to work correctly, and was unintentionally
type=int, default=None, # exposed through inheritance. It has been deprecated since version 3.11, removed in version 3.14.
help='volatile memory quota (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') # Hence, we have to implement the enforcement manually.
install_cap_parser_inst_prm_g_grp.add_argument('--install-parameters-non-volatile-memory-quota', install_cap_parser_inst_prm_grp = install_cap_parser.add_argument_group('Install Parameters')
type=int, default=None, install_cap_parser_inst_prm_grp.add_argument('--install-parameters', type=is_hexstr, default=None,
help='non volatile memory quota (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') help='install Parameters (GPC_SPE_034, section 11.5.2.3.7, table 11-49)')
install_cap_parser_inst_prm_g_grp.add_argument('--install-parameters-stk', install_cap_parser_inst_prm_grp.add_argument('--install-parameters-volatile-memory-quota',
type=is_hexstr, default=None, type=int, default=None,
help='Load Parameters (ETSI TS 102 226, section 8.2.1.3.2.1)') help='volatile memory quota (GPC_SPE_034, section 11.5.2.3.7, table 11-49)')
install_cap_parser_inst_prm_grp.add_argument('--install-parameters-non-volatile-memory-quota',
type=int, default=None,
help='non volatile memory quota (GPC_SPE_034, section 11.5.2.3.7, table 11-49)')
install_cap_parser_inst_prm_grp.add_argument('--install-parameters-stk',
type=is_hexstr, default=None,
help='Load Parameters (ETSI TS 102 226, section 8.2.1.3.2.1)')
@cmd2.with_argparser(install_cap_parser) @cmd2.with_argparser(install_cap_parser)
def do_install_cap(self, opts): def do_install_cap(self, opts):
@@ -888,9 +894,15 @@ class ADF_SD(CardADF):
load_file_aid = cap.get_loadfile_aid() load_file_aid = cap.get_loadfile_aid()
module_aid = cap.get_applet_aid() module_aid = cap.get_applet_aid()
application_aid = module_aid application_aid = module_aid
if opts.install_parameters: # `--install-parameters` and `--install-parameters-*` are mutually exclusive
if opts.install_parameters is not None:
install_parameters = opts.install_parameters; install_parameters = opts.install_parameters;
else: else:
# `--install-parameters-*` are mutually inclusive
if opts.install_parameters_non_volatile_memory_quota is None or \
opts.install_parameters_volatile_memory_quota is None or \
opts.install_parameters_stk is None:
raise ValueError("Either --install-parameters alone, or all --install-parameters-* must be specified")
install_parameters = gen_install_parameters(opts.install_parameters_non_volatile_memory_quota, install_parameters = gen_install_parameters(opts.install_parameters_non_volatile_memory_quota,
opts.install_parameters_volatile_memory_quota, opts.install_parameters_volatile_memory_quota,
opts.install_parameters_stk) opts.install_parameters_stk)