argparse error with parsing required arguments - python

I have a script saved as workspace.py
import argparse
import os
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('title', type=str, help="Will be displayed as the title")
parser.add_argument('-f', '--folder', help='Point to the folder you want to read from (defaults to current folder in command prompt)', type=str, default=os.getcwd())
args = parser.parse_args()
print(args)
someFunction(args.folder, args.title)
Which I call from terminal with:
workspace.py myTitle
Resulting in the error
workspace.py: error: the following arguments are required: title
I have no idea why this is happening because I supply "myTitle" in the terminal. If I specify a default= for the title argument it works perfectly with that value. The part that is throwing me is it doesn't even get to the print(args) so I cannot see what the program thinks is what, but instead fails at args = parser.parse_args()
I tried to even redo the exact example at: https://docs.python.org/2/howto/argparse.html#introducing-positional-arguments (copied below)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo", help="echo the string you use here")
args = parser.parse_args()
print args.echo
Running
workspace.py hello
Results in (after adding parenthesis to the print for 3.X)
workspace.py: error: the following arguments are required: echo
Is there something I'm missing? Why does it not just print "hello"? Is there some Python 3 specific syntax I'm missing or something?

I've gotten it to work if I run python workspace.py someString instead of workspace.py someString. I do not understand why this version works, since command prompt obviously recognizes it as Python and runs it correctly until args = parser.parse_args(). There were no errors like 'workspace.py' is not recognized as an internal or external command, operable program or batch file. There was no problem importing modules either. Consider the below command prompt session if you are running into a similar error. Maybe you will simply have to include python in your commands like I have to...
C:\Users\rparkhurst\PycharmProjects\Workspace>workspace.py MyTitle
usage: workspace.py [-h] [-f FOLDER] title
workspace.py: error: the following arguments are required: title
C:\Users\rparkhurst\PycharmProjects\Workspace>python workspace.py MyTitle
Namespace(folder='C:\\Users\\rparkhurst\\PycharmProjects\\Workspace', title='MyTitle')

Related

Retrieving args from running a script via sagemaker processing: unrecognized arguments

I am testing a job. For that, I run the script via notebook using the following code.
I want to be able to retrieve the value of the arg
"dataset" via "argparse". I don't understand what I am doing wrong here:
The notebook that runs the job:
from sagemaker.processing import Processor, ProcessingInput, ProcessingOutput
from sagemaker.network import NetworkConfig
netconfig = NetworkConfig(XXX)
dataset= 'A'
processor = Processor(image_uri='XXX',
role='XXX',
instance_count=1,
instance_type="XXX",
network_config=netconfig)
processor.run(inputs=[ProcessingInput(
source='s3://input-bucket/settings_dataset_A.json',
destination='/opt/ml/processing/input')],
outputs=[ProcessingOutput(
source='/opt/ml/processing/output',
destination='s3://output-bucket')],
arguments=["--verbose", "--dataset", dataset],
wait=True,
logs=True)
and the code in the script:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', help="verbose",action="store_true")
parser.add_argument("--dataset", type=str, required =False)
args = parser.parse_args()
print('Arguments:', sys.argv)
print(args.dataset)
It gives an error: "unrecognized argument" but it is able to print the correct value ! And then it just stops running the rest of the code.
Do you see anything wrong with the code above ? Thanks a lot

"Invalid choice" error while using argparse

I'm writing a python script which takes in arguments from command line in the following format:
./myfile subcommand --change --host=myhost --user=whatever
--change is in a way required, meaning that for now this is only option available, but later I will add other options, but eventually user needs to choose between those options.
--host is required. It's not a positional argument.
--user is not required, and there is a default value for it. It's not a positional argument.
I'm using the following code to create this command, but
#!/usr/bin/env python
import argparse
parser = argparse.ArgumentParser(description='My example explanation')
subparsers = parser.add_subparsers(dest='action')
subparsers.required = True
subcommand_parser = subparsers.add_parser('subcommand')
subcommand_parser_subparser = subcommand_parser.add_subparsers()
change_subcommand_parser = subcommand_parser_subparser.add_parser('--change')
change_subcommand_parser.add_argument('--host', required=True)
change_subcommand_parser.add_argument('--user', required=False, default='Salam')
print(parser.parse_args())
When I try this code with the following command in CLI:
./myscript something --change --host hello --user arian
I get the following error:
usage: myscript subcommand [-h] {--change} ...
myscript subcommand: error: invalid choice: 'hello' (choose from '--change')
My questions are:
What's wrong with this code?
How can I make users type --user & --host, and not use them as positional arguments?

Displaying help through command line argument

I have a python program that I am running through command line arguments. I have used sys module.
Below is my test.py Python file where I am taking all the args:
if len(sys.argv) > 1:
files = sys.argv
get_input(files)
The get_input method is in another Python file where I have the options defined.
options = {
'--case1': case1,
'--case2': case2,
}
def get_input(arguments):
for file in arguments[1:]:
if file in options:
options[file]()
else:
invalid_input(file)
To run:
python test.py --case1 --case2
My intentions are that I want to show the user all the commands in case they want to read the docs for that.
They should be able to read all the commands like they usually are in all the package for reading help, python test.py --help . With this they should be able to look into all the commands they can run.
How do I do this?
One of the best quality a Python developer can be proud of is to use built-in libraries instead of custom ones. So let's use argparse:
import argparse
# define your command line arguments
parser = argparse.ArgumentParser(description='My application description')
parser.add_argument('--case1', help='It does something', action='store_true')
parser.add_argument('--case2', help='It does something else, I guess', action='store_true')
# parse command line arguments
args = parser.parse_args()
# Accessing arguments values
print('case1 ', args.case1)
print('case2 ', args.case2)
You can now use your cmd arguments like python myscript.py --case1
This comes with a default --help argument you can now use like: python myscript.py --help which will output:
usage: myscript.py [-h] [--case1] [--case2]
My application description
optional arguments:
-h, --help show this help message and exit
--case1 It does something
--case2 It does something else, I guess
Hi you can use option parser and add your options and related help information.
It has by default help option which shows all the available options which you have added.
The detailed document is here. And below is the example.
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose", default=True,
help="don't print status messages to stdout")
(options, args) = parser.parse_args()

python script envoke -h or --help if no options are chosen

Trying to make my script more generic so I added some flags. My problem is the help only works if you type -h , obviously. I want to envoke -h when no flags are selected.
For example:
python 0_log_cleaner.py
Traceback (most recent call last):
File "0_log_cleaner.py", line 51, in <module>
getFiles(options.path,options.org_phrase,options.new_phrase,options.org_AN,options.new_AN,options.dst_path)
File "0_log_cleaner.py", line 37, in getFiles
for filename in os.listdir(path):
TypeError: coercing to Unicode: need string or buffer, NoneType found
but if I add -h I get:
python 0_log_cleaner.py -h
Usage: Example:
python 0_log_cleaner.py --sp original_logs/ --dp clean_logs/ --od CNAME --nd New_CNAME --oan 10208 --nan NewAN
Options:
-h, --help show this help message and exit
--sp=PATH Path to the source logs ie original_logs/
--dp=DST_PATH Path to where sanitized logs will be written to ie
clean_logs
--od=ORG_PHRASE original domain name ie www.clientName.com, use the command
-od clientName
--nd=NEW_PHRASE domain name to replace -od. ie -od clientName -nd domain
makes all log that use to be www.clientName.com into
www.domain.com
--oan=ORG_AN original AN number
--nan=NEW_AN AN number to replace original. ie -oan 12345 -nan AAAA1
replaces all instances of the AN number 12345 with AAAA1
EDIT 3 ANSWER
sample of my code to produce ^
import argparse
import sys
usage = "Description of function"
parser = argparse.ArgumentParser(description=usage)
parser.add_argument("--sp", dest="path", help='Path to the source logs ie logs/')
...
...(additional add arugments)
args = parser.parse_args()
def getFiles(path,org_phrase,new_phrase,org_AN,new_AN,dst_path):
if not len(sys.argv) > 1:
parser.print_help()
else:
run your logic
borrowed from here : Argparse: Check if any arguments have been passed
Here's how the final code looks like:
import argparse
import sys
usage = "Description of function"
parser = argparse.ArgumentParser(description=usage)
parser.add_argument("--sp", dest="path", help='Path to the source logs ie logs/')
...
...(additional add arugments)
args = parser.parse_args()
def getFiles(path,org_phrase,new_phrase,org_AN,new_AN,dst_path):
if not len(sys.argv) > 1:
parser.print_help()
else:
run your logic
If someone is still interested in a (very simple) solution:
parser = argparse.ArgumentParser()
parser.add_argument("jfile", type=str, help="Give the JSON file name.")
parser.add_argument("--output", type=str, help="Type in the final excel files name.")
try:
args = parser.parse_args()
return args
except:
parser.print_help()
My professor wanted the script to force the -h / --help page even when there are too few arguments. Instead of going like "python SCRIPT.py -h".
So what I did here was like: "Try to parse the arguments. And if it works, give them back to the main methode. Otherwise, if you fail (except), print the help(). Okay? Nice". ;)
Without knowing the method you are parsing with, I will assume the following (comment me if I am wrong or edit your question with some code on how you handle your parsing):
You are parsing everything and putting it in a variable. let parsed be that variable.
You are checking parsed for the existence of any of your option flags.
You probably not checking for the non-existence of arguments:
parsed = '' <- empty string
# or if you are using a list:
# parsed = []
if parsed: <- if parsed is not empty ("" or []) returns true
Do your stuff here, because you have options now
else: <- Differently options were not provided
Invoke the same method that you invoke when the option is -h
Also as #dhke suggests, consider using argparse if you are not using it already!
EDIT #1:
Translated for your specific case:
args = parser.parse_args() <-- ending line of your provided code
if not args:
parser.print_help()
else:
Do your stuff

Python/argparse: How to make an argument (i.e. --clear) don't warn me "error: too few arguments"?

I have this cmd line parsing stuf and I need to make "--clear" a valid unique parameter. However I'm getting an "Error: Too few arguments" when I only use "--clear" as an unique parameter.
parser = argparse.ArgumentParser(
prog="sl",
formatter_class=argparse.RawDescriptionHelpFormatter,
description="Shoot/Project launcher application",
epilog="")
parser.add_argument("project", metavar="projectname",
help="Name of the project/shot to use")
parser.add_argument("-p", metavar="project_name",
help="Name of the project")
parser.add_argument("-s", metavar="shot_name",
help="Name of the shot")
parser.add_argument("--clear",action='store_true',
help="Clear the information about the current selected project")
parser.add_argument("--test",
help="test parameter")
args=parser.parse_args()
Any ideas? Thanks
Update:
Trying to answer some questions of the comments.
When I launch the app like:
sl project
it works fine.
But if I launch it like:
sl --clear
I got a simple "sl: error: too few arguments"
The --clear argument is not the problem here; project is a required argument.
If you should be able to call your program without naming a project, make project optional by adding nargs='?':
parser.add_argument("project", metavar="projectname",
help="Name of the project/shot to use", nargs='?')
If it is an error to not specify a project name when other command-line switches are used, do so explicitly after parsing:
args = parser.parse_args()
if not args.clear and args.project is None:
parser.error('Please provide a project')
Calling parser.error() prints the error message, the help text and exits with return code 2:
$ python main.py --clear
Namespace(clear=True, p=None, project=None, s=None, test=None)
$ python main.py
usage: sl [-h] [-p project_name] [-s shot_name] [--clear] [--test TEST]
[projectname]
sl: error: Please provide a project
Add default values for each argument (--clear is no exception)

Categories