I'm trying to pass arguments in a Flask application with argparse:
app = Flask(__name__)
parser = argparse.ArgumentParser()
parser.add_argument("-e", "--environ", dest='environ', default='production',
help="Server environment")
args = parser.parse_args()
if args.environ == 'dev':
app.config.from_pyfile("dev.cfg", silent=True)
else:
app.config.from_pyfile("product.cfg", silent=True)
Everything is OK when I run the script directly.
However I don't know how to pass "-e dev" argument in uwsgi config file, pyargv cannot handle this kind of argument.
You can use this code:
parser.add_argument("-e", "--environ", dest='environ', default='production', help="Server environment", required=False)
Related
Trying to run my script using argparser, where the program does not run, unless correct argument is in place, however it does not seem to work;
AttributeError: 'Namespace' object has no attribute 'func'
import sys
import argparse
from develop import Autogit as gt
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# Create argument command
parser_update = subparsers.add_parser('--sync', help='Sync local and remote repos')
parser_update.set_defaults(func=gt.run)
# Adding arguments
parser.add_argument('--sync', type=str, required=True)
if len(sys.argv) <= 1:
sys.argv.append('--help')
options = parser.parse_args()
options.func() # <--- Causes the error
if __name__ == '__main__':
main()
Also when the --sync arg is given it ask for another, then when I add one more argument. SYNC, then it returns attribute error.
Edit
Trying to make the program run the develop.Autogit.run
Working..
Had to also add args as argument in the run funciton i am calling.
I think what you are trying to accomplish is setting a default, typically this is done with ArgumentParser.set_defaults(). You need to do this with the uninitialised function. See this example:
import sys
import argparse
def f(args):
print("In func")
print(args)
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# Create argument command
parser_update = subparsers.add_parser("sync", help="Sync local and remote repos")
parser_update.set_defaults(func=f) # <-- notice it's `f` not `f()`
options = parser.parse_args()
options.func(options)
if __name__ == "__main__":
main()
As an aside, you will have more problems with your snippet as you are defining the same parameter (--sync) in multiple places. When using subparsers it is customary to make these positional (no leading --) so they act as subcommands.
Here is a typical command line that I would use with subcommands:
import sys
import argparse
def f(args):
print("In func f")
print(args)
def g(args):
print("In func g")
print(args)
def main():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command")
parser_update = subparsers.add_parser("sync", help="Sync local and remote repos")
parser_update.set_defaults(func=f)
parser_delete = subparsers.add_parser("delete", help="Delete sub-command")
parser_delete.set_defaults(func=g)
options = parser.parse_args()
if options.command is not None:
options.func(options)
else:
parser.print_help()
parser.exit()
if __name__ == "__main__":
main()
How to pass command line option as variable to my pytest non test file e.g. database name.
When i try:
import sys
import getopt
"""argv = sys.argv[1:]
opts, args = getopt.getopt(argv, "e:")
for opt, arg in opts:
if opt in ['-e']:
if arg == "test1":
base_url = "url-test1.com"
db_name = "db_test1"
elif arg == 'test2':
base_url = "url-test2.com"
db_name = "db_test2"
elif arg == 'test3':
base_url = "url-test3.com"
db_name = "db_test3"
return base_url
and run
python -m pytest -e test1
looks like pytest can't get -e flag
ERROR: usage: main.py [options] [file_or_dir] [file_or_dir] [...]
main.py: error: unrecognized arguments: -e
inifile: None
I also try pytest addoption and passing variable to test files works fine but how to pass cmnd line option as value to non test file?
def pytest_addoption(parser):
parser.addoption("--url", action="store", default="url-test1.com")
parser.addoption("--db", action="store", default="test1")
#pytest.fixture()
def url(request):
return request.config.getoption("--url")
def db_name(request):
return request.config.getoption("--db") #I want to pass this value to mysql.connector as database=db_name
EDIT 1
so my db_connect.py lokks like that
import mysql.connector
import argparse
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--db', required=True, type=str, help="Your database name")
return parser.parse_args()
def main():
args = parse_args()
db = args.db
return db
mydb = mysql.connector.connect(
user='username',
password='password',
host='host',
database=main()
)
if __name__ == '__main__':
main()
and when i try to run
py.test --db test1
I got this error
ERROR: usage: py.test [options] [file_or_dir] [file_or_dir] [...]
py.test: error: unrecognized arguments: --db
inifile: None
but when i run
py.test
i got
usage: py.test [-h] --db DB
py.test: error: the following arguments are required: --db
argument is required but when i pass it is unrecognized. How to handle it?
Welcome!
Specifically to "override" variables, modules and objects you should mock them. Mocking in testing refers to creating a fake object with similar behavior to the original one when creating the real object is expensive. Such as database connections. But, naturally, it isn't restricted to just databases. You can mock any object, as well as sys.argv.
You can read more extensively about mocking in the pytest docs but here's a short example
import module_to_test
def mytest(monkeypatch):
"""
Mocks the configuration parameters values.
"""
monkeypatch.setattr(module_to_test.sys, 'argv', ['somescript.py', '--db'])
That being said, I strongly recommend you do not use getopt. That is a deprecated method to parse arguments from the world of bash. There is a strong package called argparse that entirely replaces any such argument boilerplate code.
import argpase
def parse_args():
"""
Parse arguments given in the command line. Expects just "--db"
"""
parser = argparse.ArgumentParser()
parser.add_argument('--db', required=True, type=str, help="Your DB name")
return parser.parse_args()
def main():
args = parse_args()
db = args.db
print(f"Wrap 10 to {db}. Engage!")
if __name__ == '__main__':
main()
argparse docs
edit 1
Great work on that argparse!
Now, you can simply mock it. You don't need it parsing the command line, anymore. You want to control what it returns. So, this time, when you use monkeypatch to mock argparse.ArgumentParser, you'll pass in your own "dummy class" that does nothing but return fixed arguments when parser.parse_args() is called. Here's an example of such a class (you'll probably want to tweak it)
from collections import namedtuple
class DummyParser:
def add_argument(self, *_, **__):
"""
We know what arguments we want, we don't need to implement this.
"""
pass
def parse_args():
"""
Money time!
"""
fake_return_class = namedtuple('Namespace',
['db', 'the value we want for db'])
args = fake_return_class(db="the value we want")
return args
fake_parser = DummyParser()
fake_args = fake_parser.parse_args()
print(fake_args.db)
One tweak could be to make it a little more reusable and add your own constructor of what'll db be equal to.
I have a flask application, in one of its script commands I want to know what's the args passed to the Manager (not the command itself), how can I do that?
$ cat manage.py
#!/usr/bin/env python
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
manager.add_option("-d", "--debug", dest="debug", action="store_true")
#manager.option('-n', '--name', dest='name', default='joe')
def hello(name):
# how can I know whether "-d|--debug" is passed in command line
print("hello", name)
if __name__ == "__main__":
manager.run()
If I run:
$ python manage.py --debug hello
I want to detect whether '--debug' is passed via command line args within the func of hello. I can't just change
manager.add_option("-d", "--debug", dest="debug", action="store_true")
to the decorator verion of:
#manager.option('-d', '--debug', action='store_true', dest='debug')
#manager.option('-n', '--name', dest='name', default='joe')
def hello(name, debug=False):
because '-d|--debug' is shared by many commands.
Global options are passed not to command, but to app-creating function.
See add-option docs.
For this to work, the manager must be initialized with a factory function rather than a Flask instance. Otherwise any options you set will be ignored.
So you need to do something like
app = Flask(__name__)
def init_manager(debug):
app.debug = debug
return app
manager = Manager(init_manager)
And then access app.debug
I'm trying to use the Python argparse module to check argument parameters:
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Example with non-optional arguments')
parser.add_argument('count', action="store", type=int)
parser.add_argument('units', action="store")
print 'test'
When I run the script (python test.py some inches), it just prints the output 'test' but the argparse module is not being triggered.
You need to actually call it!
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Example with non-optional arguments')
parser.add_argument('count', action="store", type=int)
parser.add_argument('units', action="store")
args = parser.parse_args()
print args
You have to parse the args for this to work. You either need to call parser.parse_args() or parser.parse_known_args(). More info can be found here:
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.parse_args
I would like to use web.py to build an http interface for some larger library, which also provides a command line script that takes optional parameters.
When I tried the simple web.py tutorial example in combination with optparse, I have the problem that web.py always takes the first cmd argument as port, which is not what I want. Is there a way to tell web-py not to check the command line args. Here is an example:
#!/usr/bin/env python
# encoding: utf-8
"""
web_interface.py: A simple Web interface
"""
import optparse
import web
urls = ("/.*", "hello")
app = web.application(urls, globals())
class hello:
def GET(self):
return 'Hello, world!\n'
if __name__ == "__main__":
p = optparse.OptionParser()
p.add_option('--test', '-t', help="the number of seed resources")
options, arguments = p.parse_args()
print options.test
app.run()
...which I want to run as follows:
python web_interface.py -t 10
It's a bit of a hack, but I guess you could do:
import sys
...
if __name__ == "__main__":
p = optparse.OptionParser()
p.add_option('--test', '-t', help="the number of seed resources")
options, arguments = p.parse_args()
print options.test
# set sys.argv to the remaining arguments after
# everything consumed by optparse
sys.argv = arguments
app.run()