From c7e68e1281db0fbf0e456e7807e642cb5ee49c3a 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 enforcement manually in do_install_cap(). Change-Id: Idddf72d5a745345e134b23f2f01e0257d0667579 --- pySim/global_platform/__init__.py | 44 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py index 810387bc..6ff4b286 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 distinct `--install-parameters-*` are optionally given instead. + # 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,17 @@ 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: + if opts.install_parameters is not None: + # `--install-parameters` and `--install-parameters-*` are mutually exclusive + # make sure that none of `--install-parameters-*` is given; abort otherwise + if any(p is not None for p in [opts.install_parameters_non_volatile_memory_quota, + opts.install_parameters_volatile_memory_quota, + opts.install_parameters_stk]): + self.install_cap_parser.error('arguments --install-parameters-* are ' + 'not allowed with --install-parameters') install_parameters = opts.install_parameters; else: + # `--install-parameters-*` are all optional install_parameters = gen_install_parameters(opts.install_parameters_non_volatile_memory_quota, opts.install_parameters_volatile_memory_quota, opts.install_parameters_stk)