Manually pass commands into argparse? | Python 2.7 - python-2.7

I am making a terminal game using Python's wonderful Cmd library. But i was curious if i could somehow put argparse code into it. Like use argparse to handle the 'args' from my cmd.Cmd() class.
To do this, i was really hoping that argparse had a way to manually pass args into it. I skimmed over the docs, but didn't notice anything like that.

parse_args() takes an optional argument args with a list (or tuple) of to parse. parse_args() (without arguments) is equivalent to parse_args(sys.argv[1:]):
In a script, parse_args() will typically be called with no arguments, and the ArgumentParser will automatically determine the command-line arguments from sys.argv.
If you do not have a tuple, but a single string, shell-like argument splitting can be accomplished using shlex.split()
>>> shlex.split('"A" B C\\ D')
['A', 'B', 'C D']
Note that argparse will print usage and help messages as well as exit() on fatal errors. You can override .error() to handle errors yourself:
class ArgumentParserNoExit(argparse.ArgumentParser):
def error(self, message):
raise ValueError(message) # or whatever you like

You could also try namedtuple to manually provide the input arguments,
from collections import namedtuple
ManualInput = namedtuple("ManualInput", ["arg1", "arg2"])
args = ManualInput(1, 4)
you will get
In [1]: print(args.arg2)
Out[1]: 4

Related

Python argparse argument that is python keyword

I want to have a python command line argument --lambda, but I can't access it as lambda is a python keyword.
import argparse
p = argparse.ArgumentParser()
p.add_argument('--lambda')
args = p.parse_args()
print args.lambda
I get:
print args.lambda
^
SyntaxError: invalid syntax
How can I do this?
You can add a different name for the attribute with dest e.g.
import argparse
p = argparse.ArgumentParser()
p.add_argument('--lambda', dest='llambda')
args = p.parse_args()
print args.llambda
argparse uses hasattr and getattr to set values in the Namespace. This allows you to use flags/dest that are not valid in the args.dest syntax. Here the problem is with a restricted key word. It could also be a string with special characters. So getattr(args, 'lambda') should work.
vars(args) creates a dictionary, allowing you to use vars(args)['lambda'].
But changing the dest is a cleaner solution. That's part of why that parameter is allowed.
(For a positional argument, choose a valid dest right away.)

Python: assigning variables from function(*args) using argparse

I'm trying to assign my arguments from argparse to variables. I have two scripts one is the parser and the other is a module. When I try to assign a variable I get a tuple object has no attribute error. Any guidance would be appreciated.
def main():
parser = argparse.ArgumentParser(description='A simple front end script interface')
subparsers = parser.add_subparsers(help='(run various listed scripts..)', dest='mode')
add_pyrr_command_options(subparsers)
args = parser.parse_args()
if args.mode == "pyrr":
pyrr.parse_cmds(args)
else:
parser.print_usage()
pyrr.py
def parse_cmds(*args):
print(args)
pass
(Namespace(mode='pyrr', plugin_name='ntuser', reg_loc='/user/home', rip_loc='/user/some'),)
When I try to assign a variable via researched methods (e.g. arg.plugin_name) I get a AttributeError: 'tuple' object has no attribute 'pyrr'
So args is a Namespace object
Namespace(mode='pyrr', plugin_name='ntuser', reg_loc='/user/home', rip_loc='/user/some')
And as your 1st script shows you can use args.mode.
In (with corrected indent)
def parse_cmds(*args):
print(args)
pass
args is a tuple (because of the *args), e.g. (Namespace(...),). With plain args you could continue to access mode with:
def parse_cmds(args):
args.mode
Another option is to pass a dictionary via **kwargs
def parse_cmds(**vargs):
# vargs is a keyword dictionary
parse_cmds(vars(args)) # converting namespace to dictionary
I think you are on the right track. You just to need to distinguish between namespace object, dictionaries, and tuples.
In your examples 'pyrr' is the string value of args.mode, and also the name of the imported pyrr.py module.

Passing an argument to main that calls a function in python

I'm trying to pass arguments to my python script using argparse and consequently call functions. Any ideas where I might be going wrong?
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('-d','--d', dest='action', action='store_const',const=do_comparison,
help="Diff the current and most recent map file memory information)")
options = parser.parse_args()
return options
def do_comparison(parsed_args):
# do things
def main(args):
options = parse_args()
if __name__ == '__main__':
sys.exit(main())
In my comment I missed the fact that you are using store_const and const=do_comparison. So you are trying some sort of callback.
options from parse_args is a argparse.Namespace object. This is a simple object, similar to a dictionary. In fact vars(options) returns a dictionary.
When main is run (with -d), options.action will be set to the const, a function. But remember, in Python, functions are first class objects, and can be set to variables, etc just like numbers and strings. To be used the function has to be 'called'.
options.action()
should end up calling do_comparison. Actually since that function requires an argument, you should use
options.action(options)
or some other way of providing a varible or object to the function.
Of course you'll have to be careful about the case where you don't specify -d. Then options.action will have the default value (e.g. None). If the default isn't a callable, then this call will produce an error.
The argparse documentation illustrates this kind of action in the section dealing with subparsers (subcommands). I vaguely recall a tutorial that set an argument value to functions like add and multiply, creating a simple arithmetic expression evaluator.
Usually the values in the Namespace are strings, or numbers, and to use them you test for string equality. e.g.
if options.action is None:
# default action
elif options.action == 'print':
print(options)
else:
do some other backup or error
A callback kind of action is possible, and may be convenient in some cases, but it isn't the usual arrangement.
You asked about using successfully store a string following the -d, to be used as the function arg with:
parser.add_argument('-d','--d', dest='action', dest='function_input', action='store_const', const=diff_map)
A 'store_const' action does not take an argument (in effect nargs=0). It's more like store_true. In fact store_true is just a store_const with has default=False and const=True.
What you need is another argument, whick could occur either before or after the -d. argparse tries to be order flexible.
Here's a simple script with a callable argument, and flexible positional argument.
import argparse
def action1(*args):
print 'action1',args
def action0(*args):
print 'action0',args
parser = argparse.ArgumentParser()
parser.add_argument('-d', dest='action', action='store_const', const=action1, default=action0)
parser.add_argument('args', nargs='*')
args = parser.parse_args()
args.action(args.args)
resulting runs
1238:~/mypy$ python stack32214076.py
action0 ([],)
1238:~/mypy$ python stack32214076.py one two three
action0 (['one', 'two', 'three'],)
1238:~/mypy$ python stack32214076.py one two three -d
action1 (['one', 'two', 'three'],)
1239:~/mypy$ python stack32214076.py -d one two three
action1 (['one', 'two', 'three'],)
1239:~/mypy$ python stack32214076.py -d
action1 ([],)
TO make -d value perform some action on value, try:
parser.add_argument('-d','--action')
The default action type stores one value (e.g. action='store', nargs=None)
args = parser.parse_args()
if args.action: # or is not None
do_comparison(args.action)
If -d is not given args.action will have default None value, and nothing happens here.
If -d astr is given acts.action will have the string value 'astr'. This if just calls the do_comparison function with this value. It's the present of this (nondefault) value that triggers the function call.
This is a rather straight forward use of a parser and an argument.

How to check if any sys.argv argument equals a specific string in Python

In Python I would like to check if any argument that has been passed to my script equals "-h" (so that I can display a help banner and exit).
Should I loop through sys.argv values or is there a more simple way to achieve this?
Just check if the desired string exists in the list:
import sys
if "__main__" == __name__:
if "-h" in sys.argv:
print "This is a help text."
import sys
def help_required():
return "-h" in sys.argv[1:]
If all you are aiming to do is to search for -h in the arguments then you can just iterate over the sys.argv list and see if you find that value.
However it looks like the problem you are actually trying to solve is to create a parser for your command line arguments. If that's the case I think the best approach is to just use the argparse module which is designed to solve exactly this problem and avoid re-inventing the wheel. By default argparse adds a help option with -h or --help. (However that default behaviour can be changed if need be, see the part of the docs that deals with that: https://docs.python.org/3/library/argparse.html#add-help)
You can achieve with what lebeef and dlask mentioned. i would prefer to use fileinput and it is more sophcicated. You can import fileinput
import fileinput
if "-h" in fileinput.input():
display_help_text()

How can i make argparse suparser match any string?

i am using
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
add_parser = subparsers.add_parser("add", help="Add parser")
add_parser.add_argument("-project", default="global")
edit_parser = subparsers.add_parser("edit", help="Edit parser")
I want to achieve smething like this:
python myprogram.py add
python myprogram.py edit
python myprogram.py "A random string"
Where in the first two usecases my program can asign the right subparser based on the keyword "add" or "edit". I am interested in the last case, where it maps to any random string that i provide.
There isn't a direct way of doing this. The use of subparsers is an extension of a positional argument with choices.
parser.add_argument('cmd', choices=['add', 'edit', ...])
It accepts a string if it is in choices. There isn't a builtin pattern matching mechanism.
I think your simplest solution would be to add one step:
custom = subparser.add_parser('custom', help='give a random string')
custom.add_argument('anystring', help='random quoted string')
python myprogram.py custom 'any random string'
I can imagine writing a custom choices class that could do both kinds of matching. It would require a custom __contains__ method (and maybe a new __iter__ to list choices in the help). But incorporating that into the _SubParsersAction class would require some serious coding.
A few more details. Your subparser object is an _SubParsersAction. Its choices attribute is an OrderedDict. When you add_parser, it creates a new ArgumentParser (the add_parser object), and enters it into the dict with the named key (plus any aliases). When parsing your input, argparse matches the strings against the keys of this dictionary. So, to implement your ideal, you'd have to change this dictionary lookup.
Another option is to look at sys.argv[1:] at the start. If one of your 'cmds' is present call the parser to get the full subparser action. Otherwise handle the inputs yourself, or call another parser that handles 'a random string' as an ordinary positional argument. Sometimes it just isn't worth the effort to twist argparse into a special shape.