I wrote a python program which accept three optional command line arguments.However i want to restrict combination of args to be entered by user.which are :
python script.py -all
python script.py --country_name
python script.py --country_name --city_name
I any other combination program shouldn't get execute.
Note: I am using argparse python module
Might be easier if I could see your code ... but basically, once you've run:
args = parser.parse_args()
Then you can put your own validation in. eg.
if args.all and (args.country_name or args.city_name):
raise MySuitableError
Argparse has a mutually exclusive group:
import argparse
def main(parser, args):
if args.country_city is not None:
country, city = args.country_city
print(args)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Hello")
group = parser.add_mutually_exclusive_group()
group.add_argument("-all")
group.add_argument("--country_city", nargs="+")
main(parser, parser.parse_args())
Which results in:
python3 test.py -all A --country_city a b
usage: test.py [-h]
[-all ALL | --country_city COUNTRY_CITY [COUNTRY_CITY ...]]
test.py: error: argument --country_city: not allowed with argument -all
python3 test.py --country_city a b
Namespace(all=None, country_city=['a', 'b'])
python3 test.py -all A
Namespace(all='A', country_city=None)
I wouldn't use options at all, but rather positional arguments that can be omitted.
p = ArgumentParser()
p.add_argument('country', nargs='?')
p.add_argument('city', nargs='?')
Then
script.py # equiv to old script.py --all
script.py FI # equiv to old script.py --countryname FI
script.py FI Turku # equivalent to old script.py --countryname FI --cityname Turku
Related
Say I have this file:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_true')
args = parser.parse_args()
print(args)
If I run it with Python, it works fine:
% python -m t --foo
Namespace(foo=True)
However, running it with IPython, I get an error:
% ipython -m t --foo
usage: ipython [-h] [--debug] [--quiet] [--init] [--autoindent] [--no-autoindent] [--automagic] [--no-automagic] [--pdb] [--no-pdb] [--pprint]
[--no-pprint] [--color-info] [--no-color-info] [--ignore-cwd] [--no-ignore-cwd] [--nosep] [--autoedit-syntax]
[--no-autoedit-syntax] [--simple-prompt] [--no-simple-prompt] [--banner] [--no-banner] [--confirm-exit] [--no-confirm-exit]
[--term-title] [--no-term-title] [--classic] [--quick] [-i] [--profile-dir ProfileDir.location]
[--profile TerminalIPythonApp.profile] [--ipython-dir TerminalIPythonApp.ipython_dir] [--log-level TerminalIPythonApp.log_level]
[--config TerminalIPythonApp.extra_config_file] [--autocall TerminalInteractiveShell.autocall]
[--colors TerminalInteractiveShell.colors] [--logfile TerminalInteractiveShell.logfile]
[--logappend TerminalInteractiveShell.logappend] [-c TerminalIPythonApp.code_to_run] [-m TerminalIPythonApp.module_to_run]
[--ext TerminalIPythonApp.extra_extensions] [--gui TerminalIPythonApp.gui] [--pylab [TerminalIPythonApp.pylab]]
[--matplotlib [TerminalIPythonApp.matplotlib]] [--cache-size TerminalInteractiveShell.cache_size]
[extra_args [extra_args ...]]
ipython: error: argument --foo: expected one argument
How can I run it using IPython?
(my end-goal is to run be able to access a running IPython kernel from within my script)
As #hpaulj said, you can use -- as a separator to indicate to IPython to stop processing arguments. This is a commonly used separator in unix commands.
So I have my main.py script which essentially will run certain conditional statements based on what is passed on the command-line. For example , if I use main.py -t, this will run test mode. If I run main.py -j /testdata -c 2222-22-22 -p 2222-22-22 this will run default mode and so on.
How can I stop passing in the flags on command line and be able to run my code, so rather than using the flags -j , -c and -p , I can just pass the values normally .
My code is as follows so far :
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--execute-cur-date", action="store", required=False)
parser.add_argument("-p", "--execute-pre-date", action="store", required=False)
parser.add_argument("-j", "--execute-json-path", action="store", required=False)
parser.add_argument("-t", "--execute-test", action="store_true", required=False)
args = parser.parse_args()
if args.execute_test:
testing()
elif args.execute_json_path and args.execute_cur_date and args.execute_pre_date:
Use the sys module to parse the command line arguments (sys.argv will be a list of the arguments):
#!/usr/bin/env python3
import sys
# The first argument (sys.argv[0]) is the script name
print('Command line arguments:', str(sys.argv))
Running the script:
$ python3 script.py these are my arguments
Command line arguments: ['script.py', 'these', 'are', 'my', 'arguments']
You can find more examples of usage in this tutorial.
You may want to take a look at python-fire https://github.com/google/python-fire
import fire
def main(c=None, p=None, j=None, t=None):
print(c, p, j, t)
if c:
print("C passed")
elif p and j and t:
print("P, J, T passed")
if __name__ == "__main__":
fire.Fire(main)
you can just pass None to skip param.
python main.py None p_val j_val t_val
python main.py c_val
I want my script to take args like:
python myscript.py -i input.fastq -q 23 -l 30 -o outfile.fastq
not like
python myscript.py input.fastq 23 30 outfile.fastq
Is there any package available to do this in python?
You can use argparse for this:
For example python myscript.py -s customscriptvalue
import argparse
# Parse arguments
parser = argparse.ArgumentParser(description='Script options')
parser.add_argument('-s', '--script', help='Custom Script to execute', default=None)
result = parser.parse_args()
# Treat Arguments in your script
arguments = dict(result._get_kwargs())
if arguments['script'] is not None:
scriptMode = True
scriptPath = arguments['script']
See
https://docs.python.org/3/library/argparse.html
I want to write a python code in which, based on some arguments passed from command line I want to make positional argument optional.
For example,
My python program is test.py, and with it I can give --init, --snap, --check options. Now if I have given --snap and --check option, then file name is compulsory i.e.
test.py --snap file1
but if I have given --init option then it should not take any other arguments. i.e. in this case file name is optional:
test.py --init
How to implement this condition
If you are ok with changing the command line you are passing a little bit, then a set of subparsers should work.
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='sub-command help')
init_parser = subparsers.add_parser('init', help='do the init stuff')
snap_parser = subparsers.add_parser('snap', help='do the snap stuff')
snap_parser.add_argument('--file', '-f', required=True)
check_parser = subparsers.add_parser('check', help='do the check stuff')
check_parser.add_argument('--file', '-f', required=True)
args = parser.parse_args()
print args
And then the output...
> python foobar.py init
Namespace()
> python foobar.py check
usage: foobar.py check [-h] --file FILE
foobar.py check: error: argument --file/-f is required
> python foobar.py check --file foobar.txt
Namespace(file='foobar.txt')
General help:
> python foobar.py --help
usage: foobar.py [-h] {init,snap,check} ...
positional arguments:
{init,snap,check} sub-command help
init do the init stuff
snap do the snap stuff
check do the check stuff
optional arguments:
-h, --help show this help message and exit
And specific sub-command help
> python foobar.py snap -h
usage: foobar.py snap [-h] --file FILE
optional arguments:
-h, --help show this help message and exit
--file FILE, -f FILE
Your other option is to use nargs as #1.618 has already mentioned.
argparse allows you to specify that certain args have their own args, like so:
parser.add_argument("--snap", nargs=1)
or use a + to allow for an arbitrary number of "subargs"
After you call parse_args(), the values will be in a list:
filename = args.snap[0]
I have been trying to execute my python script with some arguments passed. The way I want it to be is something like this:
python script.py filepath
but also to support this
python script.py filepath1 filepath2
My implementation has been:
parser = argparse.ArgumentParser()
mand = parser.add_argument_group("Mandatory arguments")
mand.add_argument("path1", help = "path1")
opt = parser.add_argument_group("Optional arguments")
opt.add_argument("path2", help = "path2")
args = parser.parse_args()
It seems to ask for both arguments. Does anyone have any suggestion as to what is the proper way to do this? One of my thoughts was to do two argument groups; one with the path1 and the other with both paths, but it still requested both.
Thanks guys and gals!
P.S. Python 2.7
Use nargs="?" (with argparse)
import argparse
parser = argparse.ArgumentParser()
mand = parser.add_argument_group("Mandatory arguments")
mand.add_argument("path1", help = "path1")
opt = parser.add_argument_group("Optional arguments")
opt.add_argument("path2", help = "path2", nargs="?")
args = parser.parse_args()
print args
See usage string:
$ python argscript.py
usage: argscript.py [-h] path1 [path2]
argscript.py: error: too few arguments
Or with -h:
$ python argscript.py -h
usage: argscript.py [-h] path1 [path2]
optional arguments:
-h, --help show this help message and exit
Mandatory arguments:
path1 path1
Optional arguments:
path2 path2
and try it with one positional argument only:
$ python argscript.py alfa
Namespace(path1='alfa', path2=None)
And with two:
$ python argscript.py alfa beta
Namespace(path1='alfa', path2='beta')
Sorry for a bit off topic answer. I prefer using docopt so in case it would be of interest for you.
Using docopt
Install docopt first:
$ pip install docopt
and with the script:
"""script.py
Usage:
script.py <fname>...
"""
if __name__ == "__main__":
from docopt import docopt
args = docopt(__doc__)
print args
You can use it this way:
Asking for usage script:
$ python script.py
Usage:
script.py <fname>...
Calling with one file name:
$ python script.py alfa
{'<fname>': ['alfa']}
Using with two names:
$ python script.py alfa beta
{'<fname>': ['alfa', 'beta']}
Playing with alternative usage descriptions:
Following would allow one or two file names, but never three or more:
"""script.py
Usage:
script.py <input> [<output>]
"""
if __name__ == "__main__":
from docopt import docopt
args = docopt(__doc__)
print args