Closed NathanMolinier closed 1 year ago
Here is what currently happens, line-by line:
python src/bcm/run/extract_disc_cords.py -h
-h
(L97)--datapath
, --contrast
) are added to the parser (L101, L103)--out-text-file
, which calls parser.parse_args()
as part of the default
value.
parser.parse_args()
is equivalent to saying parser.parse_args(args=None)
args=None
, argparse will use sys.argv[1:]
-h
that we specified on the command line!! And so, the parser exits the program at the end of -h
, while we were in the middle of adding the third argument.To avoid exiting early when running -h
, we could potentially try this:
# Make sure we remove `-h` and `--help` before we try to use `parse_args` within the `default` value
argv_no_h = [arg for arg in sys.argv[1:] if arg not in ['-h', '--help']]
# Then, when we're inside `parser.add_argument`, we make sure to specify `parser.parse_args(argv_no_h)`
parser.add_argument('-txt', '--out-txt-file', default=os.path.abspath(os.path.join('results/files', f'{os.path.basename(os.path.normpath(parser.parse_args(argv_no_h).datapath))}_{CONTRAST[parser.parse_args(argv_no_h).contrast][0]}_hg{parser.parse_args(argv_no_h).ndiscs}_discs_coords.txt')),
type=str, metavar='N',help='Generated txt file path (default="results/files/(datapath_basename)_(test_CONTRAST)_hg(nb_class_hourglass)_discs_coords.txt")')
This will fix the "exiting early" problem, but it will reveal a new issue:
(venv_bcm) joshua@tadpole:~/repos/disc-labeling-benchmark$ python src/bcm/run/extract_disc_cords.py -h
usage: extract_disc_cords.py [-h] [--datapath <folder>] -c CONTRAST
extract_disc_cords.py: error: the following arguments are required: -c/--contrast
--contrast
is a mandatory argument. So, as it is currently written, we can't just run -h
by itself, because -h
is dependent on parser.parse_args()
, which is in turn dependent on -c
.
Overall, I think that the best thing to do is remove the calls to parser.parser_args
while you're in the middle of defining your arguments. This will allow you to call -h
without needing to also call -c
.
So, for example, if we move the values for default=
outside of the parser, we get:
# Before
init_txt_file(parser.parse_args())
# After
arguments = parser.parse_args()
if arguments.out_txt_file is None:
arguments.out_txt_file = os.path.abspath(os.path.join('results/files', f'{os.path.basename(os.path.normpath(arguments.datapath))}_{CONTRAST[arguments.contrast][0]}_hg{arguments.ndiscs}_discs_coords.txt'))
if arguments.skeleton_dir is None:
arguments.skeleton_dir = os.path.join(parser.parse_args().datapath, 'skeletons')
init_txt_file(arguments)
And -h
works just fine now. :)
Thank you @joshuacwnewton for your time and your comment ! I thought about using something similar after the parser definition but for me it is also making the script harder to debug when default values are defined after. However, I believe this is the only solution to have a working help.
Description
To Improve code clarity and usage, some default options were configured within the parser based on other parser values, example:
https://github.com/spinalcordtoolbox/disc-labeling-benchmark/blob/d172ad3d9d33c56fcffc73c2ca68f4766435f675/src/bcm/run/extract_disc_cords.py#L105-L106
Where
parser.parse_args().datapath
is used in the default option of--out-txt-file
.However, even if this type of use is possible, a problem is visible when using the bash help
Output:
Thus not showing other arguments after this use of a
complex default
Solutions
Parser defaults need therefore to be simple or defined after all the arguments have been added.