From 27031e78d9b3f9c7c5d2c215c275098bf0f34bcb Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 10 Mar 2026 18:29:17 +0700 Subject: [PATCH] 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 --- pySim/global_platform/__init__.py | 42 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py index 8a99677b..1c0d5219 100644 --- a/pySim/global_platform/__init__.py +++ b/pySim/global_platform/__init__.py @@ -859,22 +859,28 @@ class ADF_SD(CardADF): _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)) - 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', help='JAVA-CARD CAP file to install') - install_cap_parser_inst_prm_g = install_cap_parser.add_mutually_exclusive_group() - install_cap_parser_inst_prm_g.add_argument('--install-parameters', type=is_hexstr, default=None, - help='install Parameters (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') - install_cap_parser_inst_prm_g_grp = install_cap_parser_inst_prm_g.add_argument_group() - install_cap_parser_inst_prm_g_grp.add_argument('--install-parameters-volatile-memory-quota', - type=int, default=None, - help='volatile memory quota (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') - install_cap_parser_inst_prm_g_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_g_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)') + # Ideally, the parser should enforce that: + # * either the `--install-parameters` is given alone, + # * or all `--install-parameters-*` are given together. + # We tried to achieve this using mutually exclusive groups (add_mutually_exclusive_group). + # However, group nesting was never supported, often failed to work correctly, and was unintentionally + # exposed through inheritance. It has been deprecated since version 3.11, removed in version 3.14. + # Hence, we have to implement the enforcement manually. + install_cap_parser_inst_prm_grp = install_cap_parser.add_argument_group('Install Parameters') + install_cap_parser_inst_prm_grp.add_argument('--install-parameters', type=is_hexstr, default=None, + help='install Parameters (GPC_SPE_034, section 11.5.2.3.7, table 11-49)') + install_cap_parser_inst_prm_grp.add_argument('--install-parameters-volatile-memory-quota', + type=int, default=None, + 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) def do_install_cap(self, opts): @@ -888,9 +894,15 @@ class ADF_SD(CardADF): load_file_aid = cap.get_loadfile_aid() module_aid = cap.get_applet_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; 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, opts.install_parameters_volatile_memory_quota, opts.install_parameters_stk)