5

I have a python script using argparse. After typing in python script_name.py -h on the command line, it shows help message for another command but the code still works. The script can recognize options defined in it and run well. It looks like the script is packaged by something. I put argparse in a function and everything works well at the beginning. I just can't find out what causes the help message changed.

Here is the code:

#!/usr/bin/env python

import os
import sys
import json
import logging
import argparse
import handlers


HZZ_DIR = os.path.dirname(os.path.abspath(__file__))
ROOT_DIR = os.path.dirname(os.path.dirname(HZZ_DIR))
logger = logging.getLogger('hzz_logger')
logger.setLevel(logging.DEBUG)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(console)


def parse_args():
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument('job', choices=['ws','lm','np'],
            help="ws: workspace; lm: limit; np: npranking")
    arg_parser.add_argument('-a', '--action', nargs=1,
            help="for Limit and NPranking: get/plot (limit/pull)")
    arg_parser.add_argument('-b', '--blinded', action='store_true',
            help="for Limit: true -- do expected only, false -- do observed as well.")
    arg_parser.add_argument('-v', '--version', nargs=1, type=int,
            help="input version")
    arg_parser.add_argument('-t', '--tag', nargs=1,
            help='workspace tag')
    arg_parser.add_argument('-m', '--mass', nargs='+', type=int,
            help='signal mass(es)')
    arg_parser.add_argument('-c', '--config', nargs=1,
            help='configure file')
    arg_parser.add_argument('-u', '--update', action='store_true',
            help="update default settings")
    args = arg_parser.parse_args()
    return args

def load_settings(args):
    pass


def run_job(settings):
    pass


def execute():
    args = parse_args()
    settings = load_settings(args)
    run_job(settings)


if __name__ == '__main__':
    execute()

The help message is pasted here, which is actually the help message a command not directly used in this code. The options for this command can also be recognized...

$ python hzz_handler.py -h
Usage: python [-l] [-b] [-n] [-q] [dir] [[file:]data.root] [file1.C ... fileN.C]
Options:
  -b : run in batch mode without graphics
  -x : exit on exception
  -n : do not execute logon and logoff macros as specified in .rootrc
  -q : exit after processing command line macro files
  -l : do not show splash screen
 dir : if dir is a valid directory cd to it before executing

  -?      : print usage
  -h      : print usage
  --help  : print usage
  -config : print ./configure options
  -memstat : run with memory usage monitoring
xealits
  • 4,224
  • 4
  • 27
  • 36
Yicheng
  • 71
  • 7
  • which error? (you need to include your traceback) – thebjorn Jun 10 '16 at 13:45
  • 5
    The help message you are shown seems to be from pyROOT, which has a habit of taking over sys.argv. Any chance you are importing it somewhere in your code? – dorian Jun 10 '16 at 13:51
  • 3
    Yes you are right! **pyROOT** is imported in **handlers**. How can I prevent it from taking over sys.argv or at least is there a way I can print out the help message correctly? @dorian – Yicheng Jun 10 '16 at 14:17
  • It seems the only way to get the correct help message is don't import `pyROOT` before parsing arguments, so I move `import handlers` into `run_job() ` where it is used... – Yicheng Jun 10 '16 at 14:50
  • Parsers like `argparse` read `sys.argv` without changing it. That means several parsers can read the same input. `-h` normally displays its stuff and then exits, so you see the help from the first one to run. You may need to use `parse_known_args` if your commandline includes stuff for both parsers. – hpaulj Jun 10 '16 at 15:19
  • 2
    According to this [link](https://root.cern.ch/phpBB3/viewtopic.php?t=15601), a possible solution seems to be this: `import ROOT; ROOT.PyConfig.IgnoreCommandLineOptions = True` – dorian Jun 13 '16 at 11:58
  • That's a better solution! Thank you. @dorian – Yicheng Jun 14 '16 at 12:10
  • I think @dorian should post his comment as an answer. – xealits Oct 21 '19 at 14:06

2 Answers2

1

Wow, another anti-Pythonic ROOT mystery! Your question and the comments are really helpful. Why did not anybody post the answer with ROOT.PyConfig.IgnoreCommandLineOptions = True?

Here is a primitive work-around:

import argparse

# notice! ROOT takes over argv and prints its own help message when called from command line!
# instead I want the help message for my script
# therefore, check first if you are running from the command line
# and setup the argparser before ROOT cuts in

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        formatter_class = argparse.RawDescriptionHelpFormatter,
        description = "my script",
        epilog = "Example:\n$ python my_script.py -h"
        )

    parser.add_argument("param", type=str, help="a parameter")
    parser.add_argument("-d", "--debug",    action='store_true', help="DEBUG level of logging")

    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.INFO)

    logging.debug("parsed args: %s" % repr(args))


import ROOT

...

if __name__ == '__main__':
    <do something with args>
xealits
  • 4,224
  • 4
  • 27
  • 36
0

In sort the answer is that always calls import ROOT after the argparse. Then ROOT won't take over the argparse and prints the required message that we want.

ramkrishna
  • 632
  • 1
  • 7
  • 24