Description
In Osmocom, we use cmd2 in pysim — command-line tools for SIM/UICC/USIM/ISIM card analysis and programming. For documentation, we rely on sphinx together with sphinx-argparse to auto-generate docs for each cmd2 command.
This setup has worked well until recently, but we've started seeing artifacts in the generated documentation:
https://ftp.osmocom.org/docs/pysim/master/osmopysim-usermanual.pdf#subsubsection*.56
change_chv
usage: build.py [-h] [--pin-nr PIN_NR] [NEWPIN] [PIN]
Suddenly we're getting build.py
instead of the command name (change_chv
) in usage.
The usage we're getting when actually running the program looks good:
pySIM-shell (00:MF)> change_chv --help
usage: change_chv [-h] [--pin-nr PIN_NR] [NEWPIN] [PIN]
Change PIN code to a new PIN code
positional arguments:
NEWPIN PIN code value. If none given, CSV file will be queried
PIN PIN code value. If none given, CSV file will be queried
options:
-h, --help show this help message and exit
--pin-nr PIN_NR PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)
Below is definition of the change_chv
command:
@with_default_category('ISO7816 Commands')
class Iso7816Commands(CommandSet):
# ...
change_chv_parser = argparse.ArgumentParser()
change_chv_parser.add_argument('NEWPIN', nargs='?', type=is_decimal,
help='PIN code value. If none given, CSV file will be queried')
change_chv_parser.add_argument('PIN', nargs='?', type=is_decimal,
help='PIN code value. If none given, CSV file will be queried')
change_chv_parser.add_argument(
'--pin-nr', type=int, default=1, help='PUK Number, 1=PIN1, 2=PIN2 or custom value (decimal)')
@cmd2.with_argparser(change_chv_parser)
def do_change_chv(self, opts):
"""Change PIN code to a new PIN code"""
new_pin = self.get_code(opts.NEWPIN, "PIN" + str(opts.pin_nr))
pin = self.get_code(opts.PIN, "PIN" + str(opts.pin_nr))
(data, sw) = self._cmd.lchan.scc.change_chv(
opts.pin_nr, h2b(pin), h2b(new_pin))
self._cmd.poutput("CHV change successful")
print(f'prog={change_chv_parser.prog}') # XXX: debug
I figured out that @cmd2.with_argparser
(actually _set_parser_prog()
) is in charge of updating the prog
attribute.
Sphinx is using this attribute to generate the usage.
- v2.4.3 was the last version to retain the old behavior (
prog=change_chv
). - v2.5.0 exhibits the new behavior (
prog=build.py
).
git-bisect pointed out to 8d88c35:
8d88c357ca0764b114c68d8175d2cd33146b83d7 is the first bad commit
commit 8d88c357ca0764b114c68d8175d2cd33146b83d7 (HEAD)
Author: Eric Lin
Date: Mon Sep 25 17:44:21 2023 -0400
Changed with_argparser() and as_subcommand_to() to accept either an ArgumentParser or a
factory callable that returns an ArgumentParser.
Changed Cmd constructor to construct an instance-specific ArgumentParser using either the factory callable
or by deep-copying the provided ArgumentParser.
With this change a new argparse instance should be created for each instance of Cmd.
Addresses #1002
Apparently we end up with prog=__name__
after this commit. This looks like a side-effect.
For the record, here's our internal ticket: https://osmocom.org/issues/6776.