I seem to be having an issue with a program I am working on in python. I have tried using sys.argv, getopt and now argparse and I am still having the same issues. Whenever I try to call myscript.py from the command line with any working arguments, the program appears to start up then it just exits the code and prints the following in the command line:
Loading configurations... <---- indicates program is starting
usage: myprogram.py [-h] [-c string] [-v]
miner.py: error: unrecognized arguments: -i 0 -d 0
myprogram.py snippet
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i','--interval', action="store", type=int, dest='interval',help='Amount of time between each switch in seconds.')
parser.add_argument('-d','--donate', action="store", type=int,dest='donate',help='Amount of time to donate your mining rig in percentage per hour.')
results = parser.parse_args()
class globalbavars:
if len(sys.argv) == 1:
interval = 8
donate = 1
interval = results.interval
donate = results.donate
I usually almost always figure out issues with my program on my own through fierce debugging but this one legitimately has me scratching my head. I can't figure out what is causing this issue. I don't even think that it's an issue with my code considering I've tried parsing with sys.argv, get opt and argparse and got the same results. Can someone help me out?
Related
I am fairly new to Python.
I need a piece of code to run when either
(i) No command line arguments are passed
(ii) A particular command line argument, say "help", is passed
I have tried working with argparse and sys but I can't seem to get both to work.
For the argparse, I tried "default='help'" while adding the argument:
parser=add_argument("arg1",default="help")
For the sys.argv, I tried the following code:
if (sys.argv[1] == 'help') or not (len(sys.argv) > 1)
But this just gave me an "Index out of range" error.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--arg1", default="help")
args = parser.parse_args()
def help():
print("I'm here to help, sorta")
if args.arg1 == "help":
help()
Running this without any command line arguments will output the help message. Running this with python3 program.py --arg1 help (assuming this code is in the file program.py) will also output the help message. Finally, running python3 program.py --arg1 nohelp will not output the help message (not just 'nohelp', but anything other than 'help').
I am trying to run code using user's args as:
parser = argparse.ArgumentParser()
args = parser.parse_args()
parser = argparse.ArgumentParser(description='Script for running daily batch jobs for T3000 Project')
parser.add_argument("from_date", help='date in string yyyy-mm-dd', default='2017-10-1')
parser.add_argument("to_date", help='date in string yyyy-mm-dd', default='2017-12-31')
args = parser.parse_args()
main(
from_date=args.from_date,
to_date=args.to_date
)
While passing the arguments, I am following the path in Pycharm as: Run->Edit Configurations->Script Parameters: "2017-10-31" "2017-11-1"
I am getting error:
driver.py: error: unrecognized arguments: 2017-10-31 2017-11-1
Process finished with exit code 2
I have seen the link, which seems similar to my problem, but given solution didn't work for me. I am missing something I guess. Help will be appreciated.
Your first argument parser:
parser = argparse.ArgumentParser()
args = parser.parse_args()
is expecting no arguments, but you have passed in two. That is where the complaint is coming from. The solution is simply to remove those two lines - I don't know why you have them there in the first place.
I dont understand the comment by #lxop, I had the same error but I require both these lines. My code is the same apart from variables as the code used in the original question.
The solution for me is to set up my parameter in Pycharm as follows, quotations around the parameter are optional. I get the error when -o is missing.
-o filename.csv
My argparse setup line is
parser.add_argument("-o", "--outfile",
help="Enter the name of a .csv file to contain output or default of radarOutTemp.csv will be used",
default="radarOutTemp.csv")
I had a perfectly fine and working piece of code, which used argparse. I've been using it for months for work without any issue. Below is an excrept.
import argparse
import sys
import math
import random
# Setup command line arguments
parser = argparse.ArgumentParser(description='RF Profile Generator', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-o', dest='OutputFile', help='Output filename', required=True, type=argparse.FileType('w', encoding='utf-8'))
parser.add_argument('-a', dest='APPositions', nargs='+', type=float, help='Trackside AP position(s)', required=True)
parser.add_argument('-l', dest='TotalTrackLength', type=float, help='Length of the track (m)', required=True)
parser.add_argument('-p', dest='AttenuatorAddr', nargs='+', help='Programmable attenuator IP address(es)', required=True)
input("A")
# parse the command line arguments
# the parsed values will be stored in the corresponding variables defined by 'dest'
args = parser.parse_args()
input("B")
#More code to follow
However, I ran the code today with the following arguments (which i have been doing all along):
rf.py -o OutputFile -a 10 20 30 40 -l 600 -p 10.0.1.55
and the console output tells me
"error: the following arguments are required: -o, -a, -l, -p"
I do not understand why this has stopped working. To troubleshoot, i added 2 input commands, but the code never reaches input("B")
Could someone please advise me on a possible reason for this to happen. The version of python is 3.4.1, and has not been updated between the last time i ran this code and now.
Thank you very much
Since required=True is present on all the calls to add_argument, my conclusion is that either
somebody else has changed your program, or
this is the first time you have tried to run it without providing those arguments
I do, however, find it odd that running your program with the --help option gives the following output:
usage: so16.py [-h] -o OUTPUTFILE -a APPOSITIONS [APPOSITIONS ...] -l
TOTALTRACKLENGTH -p ATTENUATORADDR [ATTENUATORADDR ...]
RF Profile Generator
optional arguments:
-h, --help show this help message and exit
-o OUTPUTFILE Output filename (default: None)
-a APPOSITIONS [APPOSITIONS ...]
Trackside AP position(s) (default: None)
-l TOTALTRACKLENGTH Length of the track (m) (default: None)
-p ATTENUATORADDR [ATTENUATORADDR ...]
Programmable attenuator IP address(es) (default: None)
I'm puzzled as to why the message implies that required arguments are optional.
the arg include an action field and optional switches that modify the behavior of the actions.
the argparse code is like the below:
parser=argparse.ArgumentParser()
parser.add-argument('action',metavar='action', choices=['analysis','report','update'],nargs='?', default='report')
parser.add-argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser.add-argument('-v',dest='verbose',action='store-true',default=False)
parser.add-argument('-o',dest='offline',action='store-true',default=False)
parser.add-argument('-n',dest='names',required=False)
i want to make the switch option -o, -d, -v only available for action=report, while option -n only available for action=analysis.
i know there is a mutual group setting, but it is just set for the arguments not for the argument values!
btw, does argparse support combine options, like -vo...???
First: Yes, combined options like -vo are supported
Now to the action switching:
Adding a SubParser to your ArgumentParser is exactely what you want to do.
See Section 15.4.5.1. Sub-commands in the Documentation of argparse, everything is explained to some detail and with example there
EDIT:
I know refer to your comment below this post:
If you do not provide a subcommand parameter in the program call, the parser normally gives you a kind advice how to use the program and then exits with a "too few arguments error"
I rewrote your code to show this
test.py
import argparse
parser=argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='sub-command help')
parser_analysis = subparsers.add_parser('analysis', help='analysis help text')
parser_analysis.add_argument('-n',dest='names',required=False)
parser_report = subparsers.add_parser('report', help='report help text')
parser_report.add_argument('-d',dest='delay',type=int, choices=range(1,10),default=1)
parser_report.add_argument('-v',dest='verbose',action='store_true',default=False)
parser_report.add_argument('-o',dest='offline',action='store_true',default=False)
parser_update = subparsers.add_parser('update', help='update help text')
parser.parse_args()
Now some calls of this test.py with different arguments:
$python test.py
usage: test.py [-h] {analysis,report,update} ...
test.py: error: too few arguments
$python test.py -h
usage: test.py [-h] {analysis,report,update} ...
positional arguments:
{analysis,report,update}
sub-command help
analysis analysis help text
report report help text
update update help text
optional arguments:
-h, --help show this help message and exit
$python test.py report -h
usage: test.py report [-h] [-d {1,2,3,4,5,6,7,8,9}] [-v] [-o]
optional arguments:
-h, --help show this help message and exit
-d {1,2,3,4,5,6,7,8,9}
-v
-o
So as I see it the only problem is that the program throws an error after calling python test.py without any subcommand. So I would do s.th. like this
try:
args=parser.parse_args()
except:
exit(0)
to avoid that the user sees that there was an unhandled error. You have then the same behaviour as i.e. the svn command.
If you want to handle this in the way that a default subcommand is executed, you whould have to do s.th. like mentioned in this post answer:
Argparse - How to Specify a Default Subcommand
import sys
#...your parser definitions
if (len(sys.argv) < 2):
args = parser.parse_args(['update'])
else:
args = parser.parse_args()
This would parse a command update if the argument list in sys.argv is smaller than 2. Why 2? Because the first argument in the argument list is always the program which you called, i.e. test.py
The question is, do you really want this behaviour? Because there is no need for calling test.py update if i can always call test.py, so users will probably get lazy and never use test.py update command. Also if you later want a different default behaviour like test.py starting an interactive mode, users which are by then used to calling test.py for updating will get confused or their scripts which use your program get broken.
Is there a Python module for doing gem/git-style command line arguments? What I mean by gem/git style is:
$ ./MyApp.py
The most commonly used MyApp commands are:
add Add file contents to the index
bisect Find by binary search the change that introduced a bug
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
...
$ ./MyApp.py branch
* current-branch
master
With no arguments, the output tells you how you can proceed. And there is a special "help" command:
$ ./MyApp.py help branch
Which gets you deeper tips about the "branch" command.
Edit:
And by doing I mean it does the usage printing for you, exits with invalid input, runs your functions according to your CLI specification. Sort of a "URL mapper" for the command line.
Yes, argparse with add_subparsers().
It's all well explained in the Sub-commands section.
Copying one of the examples from there:
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>> checkout = subparsers.add_parser('checkout', aliases=['co'])
>>> checkout.add_argument('foo')
>>> parser.parse_args(['checkout', 'bar'])
Namespace(foo='bar')
Edit: Unfortunately there's no self generated special help command, but you can get the verbose help message (that you seem to want) with -h or --help like one normally would after the command:
$ ./MyApp.py branch --help
By verbose I don't mean that is like a man page, it's like every other --help kind of help: listing all the arguments, etc...
Example:
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(description='Sub description')
>>> checkout = subparsers.add_parser('checkout', description='Checkout description')
>>> checkout.add_argument('foo', help='This is the foo help')
>>> parser.parse_args(['checkout', '--help'])
usage: checkout [-h] foo
Checkout description
positional arguments:
foo This is the foo help
optional arguments:
-h, --help show this help message and exit
If you need to, it should be easy to implement an help command that redirects to --help.
A reasonable hack to get the gem/git style "help" behavior (I just wrote this for what I'm working on anyway):
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='sub_commands')
parser_branch = subparsers.add_parser('branch', description='list of branches')
parser_help = subparsers.add_parser('help')
parser_help.add_argument('command', nargs="?", default=None)
# I can't find a legitimate way to set a default subparser in the docs
# If you know of one, please let me know!
if len(sys.argv) < 2:
sys.argv.append('--help')
parsed = parser.parse_args()
if parsed.sub_commands == "help":
if not parsed.command:
parser.parse_args(['--help'])
else:
parser.parse_args([parsed.command, '--help'])
argparse is definitely a step up from optparse and other python solutions I've come across. But IMO the gem/git style of handling args is just a more logical and safer way to do things so it's annoying that it's not supported.
I wanted to do something similar to git commands, where I would load a second script based off of one of the command line options, and have that script populate more command line options, and also have the help work.
I was able to do this by disabling the help option, parse known args, add more arguments, re-enable the help option, and then parse the rest of the arguments.
This is what I came up with.
import argparse
#Note add_help=False
arg_parser = argparse.ArgumentParser(description='Add more arguments after parsing.',add_help=False)
arg_parser.add_argument('MODE', default='default',type=str, help='What commands to use')
args = arg_parser.parse_known_args()[0]
if args.MODE == 'branch':
arg_parser.add_argument('-d', '--delete', default='Delete a branch')
arg_parser.add_argument('-m', '--move', default='move a branch')
elif args.MODE == 'clone' :
arg_parser.add_argument('--local', '-l')
arg_parser.add_argument('--shared')
#Finally re-enable the help option, and reparse the arguments
arg_parser.add_argument(
'-h', '--help',
action='help', default=argparse.SUPPRESS,
help=argparse._('show this help message and exit'))
args = arg_parser.parse_args()