is there a way to clear python argparse? - python

Consider the following script:
import argparse
parser1 = argparse.ArgumentParser()
parser1.add_argument('-a')
args1 = parser1.parse_args()
parser2 = argparse.ArgumentParser()
parser2.add_argument('-b')
args2 = parser2.parse_args()
I have several questions:
Is parse_args a one-time method or is there a way to clear the
arguments before adding new ones? (e.g. something like
args1.clear() or parser1.clear())
The result of this script is unusable. Although this script accepts
the -a argument, it does not accept any value for 'a'. Nor does it
accept any -b argument. Is there some way to make any of the arguments really work?
This is my actual scenario: I have 2 scripts. Both import the same
file which has initialization code (load config files, create
loggers, etc.), lets call it init.py This init.py file also parses
the arguments only because it needs one value from it. The problem
is that I need one of the scripts to accept other arguments as well.
Since init.py does something with one argument, I cannot wait with
parse_args. How can I make it work?
Edit:
Here is the output of my script:
[prompt]# python2.7 myscript.py -a
usage: a.py [-h] [-a A]
myscript.py: error: argument -a: expected one argument
[prompt]# python2.7 myscript.py -a 1
Namespace(a='1')
usage: a.py [-h] [-b B]
myscript.py: error: unrecognized arguments: -a 1

Your scenario is quite unclear, but I guess what you're looking for is parse_known_args
Here I guessed that you called init.py from the other files, say caller1.py and caller2.py
Also suppose that init.py only parses -a argument, while the original script will parse the rest.
You can do something like this:
in init.py put this in do_things method:
parser = argparse.ArgumentParser()
parser.add_argument('-a')
parsed = parser.parse_known_args(sys.argv)
print 'From init.py: %s' % parsed['a']
In caller1.py:
init.do_things(sys.argv)
parser = argparse.ArgumentParser()
parser.add_argument('-b')
parsed = parser.parse_known_args(sys.argv)
print 'From caller1.py: %s' % parsed['b']
If you call caller1.py as follows: python caller1.py -a foo -b bar, the result will be:
From init.py: foo
From caller1.py: bar
But if your scenario is not actually like this, I would suggest to use #Michael0x2a answer, which is just to use single ArgumentParser object in caller1.py and pass the value appropriately for init.py

This doesn't really make sense, because for all intents and purposes, the parser object is stateless. There's nothing to clear, since all it does is takes in the console arguments, and returns a Namespace object (a pseudo-dict) without ever modifying anything in the process.
Therefore, you can consider parse_args() to be idempotent. You can repeatedly call it over and over, and the same output will occur. By default, it will read the arguments from sys.argv, which is where the console arguments are stored.
However, note that you can pipe in custom arguments by passing in a list to the parse_args function so that the parser will using something other then sys.argv as input.
I'm not sure what you mean. If you call python myscript.py -a 15, args1 will equal Namespace(a='15'). You can then do args1['a'] to obtain the value of 15. If you want to make the flag act as a toggle, call parser.add_argument('-a', action='store_true'). Here is a list of all available actions.
I would try and confine all the console/interface code into a single module and into a single parser. Basically, remove the code to parse the command line from init.py and the second file into an independent little section. Once you run the parser, which presents a unified interface for everything in your program, pass in the appropriate variables to functions inside init.py. This has the added advantage of keeping the UI separate and more easily interchangeable with the rest of the code.

Related

how to read argparser values from a config file in python?

I have a lot of arguments for my script. And along with the argparser, I want users to also have the option to specify those arguments via a config file.
parser.add_argument('-a','--config_file_name' ...required=False)
parser.add_argument('-b' ...required=True)
parser.add_argument('-c' ...required=False)
....
At this point I just need the logic to implement the following:
Either the users can type in all the arguments in the command line or
They can type in the first argument, specify the file name and the code fills in/overwrites all the remaining optional arguments from the config file.
How can this be achieved?
I don't think this is up to argparse to handle.
Argparse simple needs to check if the argument for the config file is there and pass it on to your program.
You need to handle this in your program, which would mean doing something like:
...
arguments=parser.parse_args()
if len(arguments.config_file_name):
f=fopen(arguments.config_file_name,'rb')
conf_settings = f.read()
for line in conf_settings:
#parse your config format here.
this way, if the config_file_name is set, you will overwrite any possible given arguments, and if not, the program will be executed with the arguments specified by the user.
for example:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("a")
args = parser.parse_args()
if args.a:
#We're getting config from config file here...
else:
#We're getting config from the command line arguments
#Now we can call all functions with correct configuration applied.
One way to solve this problem is with xargs command line utility. This wouldn't give you exactly the command line interface that you describe, but would achieve the same effect.
xargs will run a command with arguments that it has read from standard input. If you pipe your arguments from the config file into xargs then your python program will be called with the arguments stored in the file. For example:
config.txt
-a -b --input "/some/file/path" --output "/another"
You could then use these arguments to your program like so
xargs ./my-prog.py --optional-arg < config.txt
because of the way that argparse works, it will take the value of the last argument if duplicates are found. Thus, if you have duplicate arguments, the ones from the config file will be chosen.

Python argparse, passing multiple arguments into the command line.

I am writing a python script.
It takes two arguments, a file, and the optional argument of a set of rules. The rules need to be formatted as a dictionary.
I am new to argparse and want to make this command line friendly.
If I leave the optional argument out and just type in the file, the script runs perfectly. If I add in a test dictionairy, it returns --
har_parser.py: error: unrecognized arguments:
I am not sure if it my misuse of the command line, which would be an easy fix if I need to change how I am passing in arguments.
Currently I am running the script as so...:
$ python myScript.py arg1 arg2
The other more likely scenario is that I wrote my function incorrectly, due to my novice experience with argparse.
Any direction would be appreciated.
def main():
parser = argparse.ArgumentParser()
parser.add_argument("file", nargs=1)
parser.add_argument("--rules")
args = parser.parse_args()
if args.rules:
print(parseHar(str(args.file[0]), args.rules[0]))
else:
print(parseHar(str(args.file[0])))

Docopt: Is it possible to specify repeating positional argument followed by a single positional argument?

I have a simple python script that uses docopt to parse command line arguments. It looks like this:
#!/usr/bin/env python
__doc__ = """
Usage: mycopy <src>... <dest>
"""
from docopt import docopt
options = docopt(__doc__)
When I run it:
./mycopy source1/ source2/ destination/
it just prints the usage info, meaning that the command line arguments I passed it were wrong. Is something wrong with the usage spec? Is it even possible to do something like this using docopt?
If you put <dest> before <src>..., it works. Accordingly, run it with ./mycopy destination/ source1/ source2/.
I think the docopt hasn't implemented the support for: ARGS... ARG. This case adds some complexity to the implementation. But I agree 'copy src1 src2 ... dest' is more straightforward usage. So maybe you could raise a request to this project: https://github.com/docopt/docopt

Mock command line arguments for Python script with `optparse`?

A Python script that I want to use (called snakefood) is normally run from the commandline and takes commandline arguments, eg:
sfood /path/to/my/project
The parsing of the commandline arguments happens in a file called gendeps.py using optparse. However, I want to use the snakefood module from another script. Is there a way I can somehow mock the passing of commandline arguments to snakefood or a way of rewriting gendeps.py so that it doesn't depend on optparse anymore?
You can always assign a new list to sys.argv:
import sys
sys.argv = ['programname', '-iq', '-q', directory]
gendeps.gendeps()
optparse uses sys.argv[1:] as input when no explicit arguments have been passed in.

How to make a custom command line interface using OptionParser?

I am using the OptionParser from optparse module to parse my command that I get using the raw_input().
I have these questions.
1.) I use OptionParser to parse this input, say for eg. (getting multiple args)
my prompt> -a foo -b bar -c spam eggs
I did this with setting the action='store_true' in add_option() for '-c',now if there is another option with multiple argument say -d x y z then how to know which arguments come from which option? also if one of the arguments has to be parsed again like
my prompt> -a foo -b bar -c spam '-f anotheroption'
2.) if i wanted to do something like this..
my prompt> -a foo -b bar
my prompt> -c spam eggs
my prompt> -d x y z
now each entry must not affect the other options set by the previous command. how to accomplish these?
For part 2: you want a new OptionParser instance for each line you process. And look at the cmd module for writing a command loop like this.
You can also solve #1 using the nargs option attribute as follows:
parser = OptionParser()
parser.add_option("-c", "", nargs=2)
parser.add_option("-d", "", nargs=3)
optparse solves #1 by requiring that an argument always have the same number of parameters (even if that number is 0), variable-parameter arguments are not allowed:
Typically, a given option either takes
an argument or it doesn’t. Lots of
people want an “optional option
arguments” feature, meaning that some
options will take an argument if they
see it, and won’t if they don’t. This
is somewhat controversial, because it
makes parsing ambiguous: if "-a" takes
an optional argument and "-b" is
another option entirely, how do we
interpret "-ab"? Because of this
ambiguity, optparse does not support
this feature.
You would solve #2 by not reusing the previous values to parse_args, so it would create a new values object rather than update.

Categories