Day three of learning python.
I'm attempting to understand how to pass flags from the command line and call a function with that flag. However, I'm getting the following error:
Traceback (most recent call last):
File "main.py", line 18, in <module>
parser.add_option("-l", action="callback", callback=printLogs)
AttributeError: 'ArgumentParser' object has no attribute 'add_option'
The code is here:
import argparse
def printLogs():
print("logs!")
parser = argparse.ArgumentParser()
parser.add_argument('-e','--entry', type=str, help='New entry',required=False)
parser.add_option("-l", action="callback", callback=printLogs)
args = parser.parse_args()
I can understand that parser.add_option doesn't exist for parser. This much is clear. I can also see that the OptionParser has been deprecated as per this link. So, OptionParser is out.
The question being: How do I parse the -l argument such that the printLogs function is called when its passed?
The way I would implement this is:
import argparse
def printLogs():
print("logs!")
parser = argparse.ArgumentParser()
parser.add_argument('-e','--entry', type=str, help='New entry')
parser.add_argument("-l", action="store_true", help='print logs')
args = parser.parse_args()
if args.l:
printLogs()
The primary purpose of argparse is to parse the input (sys.argv), and give you a set of argument values (args is a simple namespace object). callbacks is a optparse concept that have not been included in argparse.
The FooAction example in the docs, http://docs.python.org/3.4/library/argparse.html#action, does something like this optparse callback. It prints some information when called, and then does the important thing - set a value in the namespace.
Related
I am currently working on a CLI tool using python's argparse module. It continuously throws this error anytime I run the program. I tried removing both the help and nargs supported arguments and still, nothing seems to work.
Full Error traceback
Traceback (most recent call last):
File "/home/sharhan/.local/share/virtualenvs/backupdb-CXGj3PlQ/bin/backupdb", line 11, in <module>
load_entry_point('backupdb', 'console_scripts', 'backupdb')()
File "/home/sharhan/DEV/PYTHON/CLI-TOOLS/backupdb/src/backupdb/cli.py", line 42, in main
args = create_parser().parse_args()
File "/home/sharhan/DEV/PYTHON/CLI-TOOLS/backupdb/src/backupdb/cli.py", line 27, in create_parser
parser.add_argument(
File "/usr/lib/python3.9/argparse.py", line 1428, in add_argument
action = action_class(**kwargs)
TypeError: DriverAction() got an unexpected keyword argument 'nargs'
This is the code:
from argparse import Action, ArgumentParser
from os import pardir
def DriverAction(Action):
"""
Namespace is a class that stores the arguments passed in the CLI.
collect driver & destination from values and store them in the namespace
using the dot notation appropriately
"""
def __call__(self, parser, namespace, values, option_string=None):
driver, destination = values
namespace.driver = driver.lower()
namespace.destination = destination
def create_parser():
parser = ArgumentParser(description="""
Back up PostgreSQl databases Locally or to AWS S3
"""
)
parser.add_argument(
"url",
help="URL of the database to backup"
)
parser.add_argument(
"--driver",
nargs=2,
action=DriverAction,
required=True,
help="How and where to store the backup",
)
return parser
def main():
import boto3
from backupdb import pgdump, storage
args = create_parser().parse_args()
dump = pgdump.dump(args.url)
if args.driver == 's3':
client = boto3.client('s3')
storage.s3(client, dump.stdout, args.destination, 'mybackupdb.sql')
else:
with open(args.destination, 'wb') as outfile:
storage.local(dump.stdout, outfile)
I'm trying to access to the "resources" folder with the ArgumentParser.
This code and the "resources" folder are in the same folder...
Just to try to run the code, I've put a print function in the predict function. However this error occurs:
predict.py: error: the following arguments are required: resources_path
How can I fix it?
from argparse import ArgumentParser
def parse_args():
parser = ArgumentParser()
parser.add_argument("resources_path", help='/resources')
return parser.parse_args()
def predict(resources_path):
print(resources_path)
pass
if __name__ == '__main__':
args = parse_args()
predict(args.resources_path)
I am guessing from your error message that you are trying to call your program like this:
python predict.py
The argument parser by default gets the arguments from sys.argv, i.e. the command line. You'll have to pass it yourself like this:
python predict.py resources
It's possible that you want the resources argument to default to ./resources if you don't pass anything. (And I further assume you want ./resources, not /resources.) There's a keyword argument for that:
....
parser.add_argument('resources_path', default='./resources')
...
My code looks like this:
parser.add_argument('-i', '--input', help='Input path/to/file.csv', required=True)
parser.add_argument('-oh', '--output-html', help='Output path/to/confusion_matrix.html', required=True)
parser.add_argument('-oc', '--output-csv', help='Output path/to/confusion_matrix.csv', required=True)
args = parser.parse_args()
....
y_true = pd.Series(true_data, name="Actual")
y_pred = pd.Series(pred_data, name="Predicted")
df_confusion = pd.crosstab(y_true, y_pred)
df_confusion.to_html(args.output-html)
df_confusion.to_csv(args.output-csv)
When i try to run it, it gives me this error:
df_confusion.to_html(args.output-html)
AttributeError: 'Namespace' object has no attribute 'output'
However, if i change from
df_confusion.to_html(args.output-html)
To
df_confusion.to_html(args.output)
It works as it should. Can anyone explain why it doesn't work, and how can i make it work with args.output-html?
By default (ie if you don't provide dest kwarg to add_argument) it changes - to _ when creating the attribute since Python attributes can't contain the character - (as a matter of fact they can, but then they are only accessible by using getattr).
It means that you should change args.output-html to args.output_html, and args.output-csv to args.output_csv.
If I import a Python module that is already using argparse, however, I would like to use argparse in my script as well ...how should I go about doing this?
I'm receiving a unrecognized arguments error when using the following code and invoking the script with a -t flag:
Snippet:
#!/usr/bin/env python
....
import conflicting_module
import argparse
...
#################################
# Step 0: Configure settings... #
#################################
parser = argparse.ArgumentParser(description='Process command line options.')
parser.add_argument('--test', '-t')
Error:
unrecognized arguments: -t foobar
You need to guard your imported modules with
if __name__ == '__main__':
...
against it running initialization code such as argument parsing on import. See What does if __name__ == "__main__": do?.
So, in your conflicting_module do
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Process command line options in conflicting_module.py.')
parser.add_argument('--conflicting', '-c')
...
instead of just creating the parser globally.
If the parsing in conflicting_module is a mandatory part of application configuration, consider using
args, rest = parser.parse_known_args()
in your main module and passing rest to conflicting_module, where you'd pass either None or rest to parse_args:
args = parser.parse_args(rest)
That is still a bit bad style and actually the classes and functions in conflicting_module would ideally receive parsed configuration arguments from your main module, which would be responsible for parsing them.
When I run this code I get
AttributeError: 'ArgumentParser' object has no attribute 'max_seed'
Here's the code
import argparse
import ConfigParser
CFG_FILE='/my.cfg'
# Get command line arguments
args = argparse.ArgumentParser()
args.add_argument('verb', choices=['new'])
args.add_argument('--max_seed', type=int, default=1000)
args.add_argument('--cmdline')
args.parse_args()
if args.max_seed:
pass
if args.cmdline:
pass
My source file is called "fuzz.py"
You should first initialize the parser and arguments and only then get the actual arguments from parse_args() (see example from the docs):
import argparse
import ConfigParser
CFG_FILE='/my.cfg'
# Get command line arguments
parser = argparse.ArgumentParser()
parser.add_argument('verb', choices=['new'])
parser.add_argument('--max_seed', type=int, default=1000)
parser.add_argument('--cmdline')
args = parser.parse_args()
if args.max_seed:
pass
if args.cmdline:
pass
Hope that helps.
If you use argparse parsed arguments inside another class (somewhere you do self.args = parser.parse_args() ), you might need to explicitly tell your lint parser to ignore Namespace type checking. As told by #frans at Avoid Pylint warning E1101: 'Instance of .. has no .. member' for class with dynamic attributes
:
Just to provide the answer that works for me now - as [The
Compiler][1] suggested you can add a rule for the problematic class in
your projects .pylintrc:
[TYPECHECK]
ignored-classes=Namespace
[1]: https://stackoverflow.com/users/2085149/the-compiler