Python argparse argument that is python keyword - python-2.7

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.)

Related

Manually pass commands into argparse? | 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

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 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.

How does django convert string to modules

I am trying to understand an other magic thing about django: it can convert strings to modules.
In settings.py, INSTALLED_APPS is declared like that:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
)
All it contains is strings. But django will convert those strings to modules and import them later.
I want to do be able to do the same thing. but i don't know how.
I have a dictionary of renderer dispatcher in settings.py:
RESOUCE_RENDERER = {
'video': 'video_player',
'audio': 'audio_player',
}
I want to use it later like this: RESOURCE_RENDERER['video'](MyVideo).
I cannot assign directly the function name(eg video_player) because it lives in a module that needs settings.py.
Since Django 1.7 there is a simple function for this. For example:
from django.utils.module_loading import import_string
my_module = import_string('path.to.my_module')
You can also get classes from the module:
MyClass = import_string('path.to.my_module.MyClass')
Take a look in django.conf.__init__.py, but basically it uses importlib like so:
try:
mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
raise ImportError("Could not import settings '%s'
(Is it on sys.path? Does it have syntax errors?):
%s" % (self.SETTINGS_MODULE, e))
# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS")
Edit: At the request of the OP I've expanded the example and contributed some more below.
Now, suppose you had a list of functions in this module, defined in for example FUNCTIONS TO CALL, a list of functions. Then, you could call each like this:
ARGUMENTS = '()'
for FUNCTION in FUNCTIONS_TO_CALL:
function_string = FUNCTION + ARGUMENTS
exec(function_string)
This assumes each function has the same set of defined arguments. You could use an if statement to detect the function name listed by the user and supply custom arguments depending on what this is. You could also evaluate from reading the python file what the arguments should be.
You could also check the module object to (I assume this is possible, I don't know) see if that function exists before calling exec() or eval(). I don't know, again, if one can evaluate from the function object what arguments it takes. I suspect so, but this is a separate (possibly already answered?) question.