Run module with argparse with IPython - python

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.

Related

Restrict combination of command line arguments

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

Make argparse behave same way in python 2 and 3

So, I'm writing a program in python using argparse. But my problem is it behaves differently in python 2 and 3. Here's the code
import argparse,sys
class CustomParser(argparse.ArgumentParser):
def error(self, message):
sys.stderr.write('\033[91mError: %s\n\033[0m' % message)
self.print_help()
sys.exit(2)
parser = CustomParser(description='Short sample app')
subparsers = parser.add_subparsers(title='Available sub-commands', dest="choice", help="choose from one of these")
ana = subparsers.add_parser("test",
formatter_class=argparse.RawTextHelpFormatter,
description = 'test',
help ="test")
ana.add_argument("-testf", type=int, help="a test flag", required=True)
args = parser.parse_args()
in python 2 it gives output (just by typing python file.py no -h flag)
Error: too few arguments
usage: test.py [-h] {test} ...
Short sample app
optional arguments:
-h, --help show this help message and exit
Available sub-commands:
{test} choose from one of these
test test
But, if I run the same in python 3 (python3 file.py) it gives no out put. I know if I provide the -h flag then I can see the description. But I want the help description to appear just by typing python3 file.py just like the python 2. Also note, I don't want to make the subparser required.

How to make positional argument optional in argparser based on some condition in python

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]

How to handle optional and mandatory positional arguments with argparse(python)

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

Pass a directory with argparse (no type checking needed)

I've written a file crawler and I'm trying to expand it. I want to use argparse to handle settings for the script including passing the starting directory in at the command line.
Example: /var/some/directory/
I have gotten several other arguments to work but I'm unable to pass this directory in correctly. I don't care if it's preceded by a flag or not, (e.g -d /path/to/start/) but I need to make sure that at the very least, this is argument is used as it will be the only mandatory option for the script to run.
Code Sample:
parser = argparse.ArgumentParser(description='py pub crawler...')
parser.add_argument('-v', '--verbose', help='verbose output from crawler', action="store_true")
parser.add_argument('-d', '--dump', help='dumps and replaces existing dictionaries', action="store_true")
parser.add_argument('-f', '--fake', help='crawl only, nothing stored to DB', action="store_true")
args = parser.parse_args()
if args.verbose:
verbose = True
if args.dump:
dump = True
if args.fake:
fake = True
Simply add:
parser.add_argument('directory',help='directory to use',action='store')
before your args = parser.parse_args() line. A simple test from the commandline shows that it does the right thing (printing args at the end of the script):
$ python test.py /foo/bar/baz
Namespace(directory='/foo/bar/baz', dump=False, fake=False, verbose=False)
$ python test.py
usage: test.py [-h] [-v] [-d] [-f] directory
test.py: error: too few arguments

Categories

Resources