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])))
Related
I have a script with several functions (before that I had one script per function)
Each function will require different arguments (some positional/mandatory, some optional).
I'd like to be able to call a specific function within the script and then hand over the argparse arguments.
Commandline:
python3 getSites.py getSites host token
I thought that using
if __name__ == '__main__':
globals()[sys.argv[1]]()
to use sys.argv[1] as the choice for the fuction and then within the function use:
def getSites():
parser = argparse.ArgumentParser(description="SentinelOne Site Statistics (#mianly for licnese usage")
parser.add_argument('host', type=str, help='REQUIRED: Please enter the Host (i.e. everything after "https://" and before ".domain.com"')
parser.add_argument('token', type=str, help='REQUIRED: Please enter your token (without the string "ApiToken")')
parser.add_argument('-s', '--savepath', type=str,
help='OPTIONAL: full path of the directory where to write the resulting XLS file. Defaults to directory of the script itself')
parser.add_argument('-a', '--accountid', type=str,
help='OPTIONAL: Enter the AccountID to query. Defaults to all accounts / sites the token user has access to')
f_args = parser.parse_args()
would work but when entering e.g.
python3 getSites.py getSites firsthost 98456984652984652984652985
I get
getSites.py: error: unrecognized arguments: 98456984652984652984652985
My Questions:
Is it possible to archive this without the "overcomplicated" -c switch when calling the script?
should I rather go with moving the required arguments from argparse into the function? i.e. getsites(host, token) and then use argparse only for the optional arguments?
Benefit of the second method would be that I could also call the function from within a python script, not only from command line. On the other hand: the user would need to know exactly what they have to provide, as that won't be shown when runnign the script with -h
I'm a bit confused here and would appreciate and help for a newbie.
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.
I have been trying to set up a main parser with two subs parser so that when called alone, the main parser would display a help message.
def help_message():
print "help message"
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='sp')
parser_a = subparsers.add_parser('a')
parser_a.required = False
#some options...
parser_b = subparsers.add_parser('b')
parser_b.required = False
#some options....
args = parser.parse_args([])
if args.sp is None:
help_message()
elif args.sp == 'a':
print "a"
elif args.sp == 'b':
print "b"
This code works well on Python 3 and I would like it to work aswell on Python 2.x
I am getting this when running 'python myprogram.py'
myprogram.py: error: too few arguments
Here is my question : How can i manage to write 'python myprogram.py' in shell and get the help message instead of the error.
I think you are dealing the bug discussed in http://bugs.python.org/issue9253
Your subparsers is a positional argument. That kind of argument is always required, unless nargs='?' (or *). I think that is why you are getting the error message in 2.7.
But in the latest py 3 release, the method of testing for required arguments was changed, and subparsers fell through the cracks. Now they are optional (not-required). There's a suggested patch/fudge to make argparse behave as it did before (require a subparser entry). I expect that eventually py3 argparse will revert to the py2 practice (with a possible option of accepting a required=False parameter).
So instead of testing args.sp is None, you may want to test sys.argv[1:] before calling parse_args. Ipython does this to produce it's own help message.
For others - I ended up on this page while trying to figure out why I couldn't just call my script with no arguments while using argparse in general.
The tutorial demonstrates that the difference between an optional argument and a required argument is adding "--" to the name:
parser.add_argument("--show") <--- Optional arg
parser.add_argument("show") <--- Not optional arg
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.
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.