8

I am trying to write a daemon service, which can be controlled in the command line. For example, to start the service

python3 test.py -c start -d /mydownloadfolder/ -j /myconfig.json

to stop the service,

python3 test.py -c stop

The -d -j parameters are required only when I start the service. Therefore, I need to implement conditionally required arguments based on the value of another argument.

I did some search and found this useful post Python Argparse conditionally required arguments The difference is: instead of checking the existence of '--command', I need to check the value of the '--command'.

Here is my tentative solution:

PARSER.add_argument('-c', '--command', required=True, help='provide a valid command: start, stop, restart, or status')
NEED_MORE_ARGS = PARSER.parse_args().command.lower().startswith('start')
PARSER.add_argument('-d', '--download', required=NEED_MORE_ARGS , default=LOCAL_DOWNLOAD, help='set account download folder')
PARSER.add_argument('-j', '--input',  required=NEED_MORE_ARGS, default=JSON_INPUT, help='set input json file')

I parsed the args in the middle to get NEED_MORE_ARGS(boolean), and then add other args. The code seems not clean. Is there a better way to do this?

==============

Updated: The tentative solution does not work. :(

3
  • I think the link pretty well covers the options. There's nothing built into argparse that does this kind of cross checking. I prefer the post-parsing testing option. But also consider - what kind of help do you want to provide? Commented Aug 29, 2018 at 22:34
  • 1
    I might add that if you don't need the '-c' flag, you could use the subparsers mechanism. 'stop' could then be a subparser without any added arguments, 'start' one with 2 required arguments. Commented Aug 29, 2018 at 22:43
  • 1
    In the link you mentioned the best answer talks about looking at sys.argv. That makes sense to me. Forget about argparse at first and just check for -c and stop or start in argv. Then use argparse based on what you found in sys.argv. Or just forget argparse and handle sys.argv yourself. Seems simpler to me. Commented Aug 29, 2018 at 23:20

1 Answer 1

7

I think you can use two parsers to do that:

import argparse

if __name__ == '__main__':
    command_parser = argparse.ArgumentParser()
    command_parser.add_argument('-c', '--command', required=True,
                                help='provide a valid command: start, stop, restart, or status')

    if command_parser.parse_known_args()[0].command.lower().startswith('start'):
        option_parser = argparse.ArgumentParser()
        option_parser.add_argument('-d', '--download', required=True, help='set account download folder')
        option_parser.add_argument('-j', '--input', required=True, help='set input json file')
        option_parser.parse_known_args()

or you can use a subparser, which is probably better in your case:

import argparse

if __name__ == '__main__':
    command_parser = argparse.ArgumentParser()

    subparsers = command_parser.add_subparsers(help='Choose a command')

    start_parser = subparsers.add_parser('start', help='"start" help')
    start_parser.add_argument('-d', '--download', required=True, help='set account download folder')
    start_parser.add_argument('-j', '--input', required=True, help='set input json file')
    start_parser.set_defaults(action=lambda: 'start')

    stop_parser = subparsers.add_parser('stop', help='"stop" help')
    stop_parser.set_defaults(action=lambda: 'stop')

    command_parser.parse_args()

in this case command line syntax will be bit different:

python3 test.py start -d /mydownloadfolder/ -j /myconfig.json

python3 test.py stop
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the suggestion

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.