1

I have a specific set up where I wanted to call foo.py both as its own script, and possibly as part of another process in another python file.

In order to make its own script, i created a separate function to create an argparser and pass it into the main function:

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--customer_id', help='e.g., 0000', type=int, required=True)
    parser.add_argument('--data_dir', default=os.environ['HOME'], help="Location to df from query.")
    parser.add_argument('--customer_file', help='File containing invoice IDs and category mappings.')
    parser.add_argument("--query_csv", help='Location to save query, or output from previous auto query.',
                        default='raw_ocr_tokens_df.csv')
    return parser

if __name__ == "__main__":
    arg_parser = parse_args()
    main_args = arg_parser.parse_args()
    BaseExtractionQuery(main_args).run_query()

I created a new subclass that also performs a query and takes in the exact same arguments and tries to merge the two argument parsers:

# in bar.py

from foo import parse_args

if __name__ == "__main__":
    arg_parser = parse_args()

    spend_parser = argparse.ArgumentParser('spend_query', conflict_handler='resolve', parents=[arg_parser])
    spend_args = spend_parser.parse_args()

    SpendExtractionQuery(spend_args).run_query()

But when I try to run 'bar.py --help' not only do i not get the original arg parser help message, but i get the help message of a python file in the next repo in my pythonpath:

>> python3 foo.py --help

usage: foo.py [-h] --customer_id CUSTOMER_ID [--data_dir DATA_DIR]
                     [--customer_file CUSTOMER_FILE] [--query_csv QUERY_CSV]

optional arguments:
  -h, --help            show this help message and exit
  --customer_id CUSTOMER_ID
                        e.g., 0000
  --data_dir DATA_DIR   Location to df from query.
  --customer_file CUSTOMER_FILE
                        File containing invoice IDs and category mappings.
  --query_csv QUERY_CSV
                        Location to save query, or output from previous auto
                        query.

>> python3 bar.py --help
usage: bar.py [-h] [--var1 VAR1]  # but this is really the args for baz.py
                   [--var2 VAR2]
                   [--var3 VAR3]
                   [--var4 VAR4]
                   [--var5 VAR5]
                              

optional arguments:
  -h, --help            show this help message and exit

Is there anyway I can force the printing of the help message when passing in a pre-made argparser?

Drivebyluna
  • 344
  • 2
  • 14
  • A `--help` triggers the help of the first parser that sees it. `parser.parse_args(['-h'])` will force a help directly. Or `parser.print_help()`, or for just the help string `parser.format_help()`. – hpaulj Feb 03 '21 at 02:06
  • But shouldn't the first parser be that found in foo.py, since it is the one imported into bar.py ? the '--help' that's being outputted is found in another library entirely. – Drivebyluna Feb 03 '21 at 05:16
  • Somehow the files and imports aren't what you describe. – hpaulj Feb 03 '21 at 05:43
  • My pythonpath is, PYTHONPATH=$FOO_DIR:$BAZ_DIR the file contents of $FOO_DIR are: - src/ -- src/foo.py -- src/bar.py and BAZ_DIR: - baz/ -- baz/baz.py – Drivebyluna Feb 03 '21 at 17:47
  • Ok, i see why the incorrect file is being picked up: i am importing a submodule from the baz folder, so if i remove all code relating to baz.py, i am able to get the correct help message from foo.py. But i still neeed the code from baz.py. Re-ordering the imports doesn't seem to help. – Drivebyluna Feb 03 '21 at 17:55
  • Normally `parse_args()` is run only when the file is used as a script; that's done by 'hiding' it in the `__name__` block. The parser might be defined in a function that's imported, but it shouldn't run upon import. Allowing more than one parser to run is asking for trouble, including this 'help' confusion. – hpaulj Feb 03 '21 at 19:07

1 Answers1

0

The issue was coming from a module-level defined argparser that was being imported in a library which i had no control over. It's a bit of a hack, but the way around this is to parse args before the import:

from foo import create_parser

bar_parser = create_parser().parse_args()

from baz import baz
Drivebyluna
  • 344
  • 2
  • 14