I'm trying to run Flask from an imported module (creating a wrapper using decorators).
Basically I have:
app.py:
import mywrapper
#mywrapper.entrypoint
def test():
print("HEYO!")
mywrapper.py
from flask import Flask
ENTRYPOINT = None
app = Flask(__name__)
#app.route("/")
def listen():
"""Start the model API service"""
ENTRYPOINT()
def entrypoint(f):
global ENTRYPOINT
ENTRYPOINT = f
return f
FLASK_APP=app
Running python -m flask, however, results in:
flask.cli.NoAppException: Failed to find Flask application or factory in module "app". Use "FLASK_APP=app:name to specify one.
Is there any trick to getting Flask to run like this? Or is it just not possible? The purpose of this is to abstract Flask away in this situation.
In my head flask should try to import mywrapper.py, which imports app.py which should generate the app and route, yet this doesn't seem to be what occurs.
Any help would be appreciated.
So I've since learnt that Flask searches only in the chosen module's namespace for a variable containing a Flask object.
There may be a smart way to avoid this limitation, but I instead decided that it was more sensible to instead just wrap the Flask class itself. If people want direct Flask functionality, I don't really care in this situation, so the only real limitation I have from this is some function names are off limits.
Basically:
wrapper.py:
class Wrapper(Flask):
def __init__(self, name):
super().__init__(name)
self.entrypoint_func = None
#self.route("/")
def listen():
return self.entrypoint_func()
def entrypoint(self, f):
assert self.entrypoint_func is None, "Entrypoint can only be set once"
self.entrypoint_func = f
return f
and app.py:
from mywrapper import Wrapper
app = Wrapper(__name__)
#app.entrypoint
def test():
print("HEYO!")
return "SUCCESS"
This is still abstracted enough that I am happy with the results.
Related
I would like to use flask to run some functions. Assume you have a file called myapp.py with a function run
def run():
return 'special routed hello world'
and this main flask file, something like this
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'hello world'
#app.route('/<myapp>')
def open_app(myapp):
from myapp import run
return run()
So obvisouly that doesn't work, but how can I dynamically call these run functions when flask is already running. Is this even possible?
In other words: when someone opens for example .../foobar, the function open_app with parameter foobar is begin called. In that function, from the file foobar.py (let's assume that file exists) import function run, run it and return the result from that function.
In fact, it is possible to use importlib, especially import_modulein combination with getattr, to dynamically call up functions of a module. And I have security concerns too.
The following two examples show a kind of simple RPC implementation.
The first example uses a dictionary for modules. If a module with the name is available, the run function is called. It allows a strong restriction. Optimization is certainly possible and probably necessary.
The second example shows a possibility of calling different functions within different modules with parameters. In spite of everything, as with the previous version, all modules are in one package called "actions" to ensure that calls can be limited. I also think a variant with POST is more suitable for this purpose than using variable rules.
Remember these are strong simplifications. Protocols such as JSON-RPC will certainly help as a guide during implementation.
from flask import Flask
from flask import jsonify, request, jsonify
from importlib import import_module
from actions import *
app = Flask(__name__)
app.secret_key = 'your secret here'
#app.route('/exec/<string:action>', methods=['POST'])
def exec(action):
result = cmddict[action].run()
return jsonify(result=result)
#app.route('/call', methods=['POST'])
def call():
data = request.get_json()
module = data.get('module')
method = data.get('method')
params = data.get('params')
try:
# import module by name
m = import_module(f'actions.{module}', __name__)
# get function by name
f = getattr(m, method)
# call function with params
result = f(**params) if isinstance(params, dict) else f(*params)
return jsonify(result=result, error=None)
except Exception as err:
return jsonify(result=None, error=f'{err}')
# ./actions/__init__py
__all__ = ['demo']
from importlib import import_module
cmddict = {}
for _ in __all__:
cmddict[_] = import_module(f'actions.{_}', __name__)
__all__.append('cmddict')
# ./actions/demo.py
def run():
return f'hello world'
def func(*args, **kwargs):
print('func', args, kwargs)
``
I’m relatively new to python and am looking for a pythonic way to handle this practice.
I’ve inherited a fairly trivial Python 2.7 Flask app that runs under uwsgi that I want to add some unit tests to. It does some initialization at indentation level 0 that is required when it’s running in uwsgi but needs to be skipped when under test.
I’m given to understand that often python apps use the
if __name__ == '__main__':
pattern to isolate code that should run when the script is run on its own and should not run when it’s imported. In this case, however, both when the script is run under uwsgi and when the script is imported into the unit tests, __name__ is the same; the name of the script, so I can’t use that to differentiate between uwsgi and unit-testing environments.
This sample code illustrates what I'm working with.
In the Flask application (flask_app.py):
import logging
import bcrypt
from flask import Flask, jsonify, abort, make_response, request
from ConfigParser import SafeConfigParser
# some initialization that only makes sense when running from the uwsgi context on the server
PARSER = SafeConfigParser()
PARSER.read('config.ini')
LOG_FILE = PARSER.get('General', 'logfile')
APP = Flask(__name__)
#APP.route('/', methods=['GET'])
def index
...
#APP.route('/<p1>/<p2>', methods=['PUT'])
def put(p1, p2):
...
if __name__ == '__main__':
APP.run(debug = True, host='0.0.0.0')
In the unit tests (tests.py):
import os
import unittest
from flask import json
from flask_app import APP
class FlaskAppTestCase(unittest.TestCase):
def setUp(self):
self.APP = APP.test_client()
def test_GET(self):
resp = self.APP.get('/')
assert 'Some Html' in resp.data
def test_PUT(self):
resp = self.APP.put('/1/2')
assert 'Got 1, 2' in resp.data
if __name__ == '__main__':
unittest.main()
What I was thinking of doing was to move the initialization so that it only runs when flask_app is being executed by uwsgi and not when it's running via tests.py, perhaps by checking name and determining which path to execute based on that, but when I examine the output of print(name) either when running flask_app under uwsgi or by executing tests.py the output is "flask_app", so I can't seem to use that as a discriminator.
Is there an idiomatic way in python to handle this?
As it turns out the Python module for uWSGI actually offers a mechanism to determine if the app is being run under uWSGI. The uwsgi module is available for import if you are in a uWSGI context, so I ended up checking whether i could import that module and only executing the initialization code if I could.
# detect if we're running under uWSGI; only init if we are, not if we're testing
try:
import uwsgi
IN_UWSGI = True
except ImportError:
IN_UWSGI = False
Then wrap the init code with
if IN_UWSGI:
This seems much more reliable then checking the module name of the module that's doing the import, which was the only other thing I could think of to do.
Is there any way of a 'global GET management' in Flask?
For example:
I want to show an error message, via popover, on any page of my flask application. If the user clicks on the 'close' button, the application will make a reload of the page with a new get parameter 'message_read=1'.
I want to catch this GET parameter. I am quite sure there is a better way then writing a check in every single app.route (which are a lot). Could you give me a hint please.
Thank you.
Add a before request function and handle it there. http://flask.pocoo.org/docs/0.12/api/#flask.Flask.before_request
#app.before_request
def do_stuff():
arg = request.args.get('message_read')
You may use decrators . Read about python decorators here
Here is a demonstration of custom decorator with flask.The code below shows a decorator definition and usage for your use case
Code
from flask import Flask,request
from functools import wraps
def popup_message(f):
#wraps(f)
def f_(*args,**argv):
message_read = request.args.get('message_read', None)
if message_read is not None:
return message_read
else:
return f(*args,**argv)
return f_
app = Flask(__name__)
#app.route('/earth')
#popup_message
def hello_earth():
return 'Hello,earth'
#app.route('/world')
#popup_message
def hello_world():
return 'Hello, World!'
app.run()
Usage
Run the app as
python main.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
and try making request to /earth and /world with and without message_read
What is the best way handle unit tests that rely on calling code that in turn relies on the current app's configuration?
eg
code.py
from flask import current_app
def some_method():
app = current_app._get_current_object()
value = (app.config['APP_STATIC_VAR'])*10
return value
test_code.py
class TestCode(unittest.TestCase):
def test_some_method(self):
app = create_app('app.settings.TestConfig')
value = some_method()
self.assertEqual(10, value)
Running the test above I get an 'RuntimeError: working outside of application context' error when the app = create_app('app.settings.TestConfig') line is executed.
Calling app = create_app during the test doesn't do the trick. What is the best way to unit test in this case where I am needing the config to be read in the the application?
You are using accessing the app within an app context when you call some_method() to fix it replace your call with:
with app.app_context():
value = some_method()
I am trying to load a module according to some settings. I have found a working solution but I need a confirmation from an advanced python developer that this solution is the best performance wise as the API endpoint which will use it will be under heavy load.
The idea is to change the working of an endpoint based on parameters from the user and other systems configuration. I am loading the correct handler class based on these settings. The goal is to be able to easily create new handlers without having to modify the code calling the handlers.
This is a working example :
./run.py :
from flask import Flask, abort
import importlib
import handlers
app = Flask(__name__)
#app.route('/')
def api_endpoint():
try:
endpoint = "simple" # Custom logic to choose the right handler
handlerClass = getattr(importlib.import_module('.'+str(endpoint), 'handlers'), 'Handler')
handler = handlerClass()
except Exception as e:
print(e)
abort(404)
print(handlerClass, handler, handler.value, handler.name())
# Handler processing. Not yet implemented
return "Hello World"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080, debug=True)
One "simple" handler example. A handler is a module which needs to define an Handler class :
./handlers/simple.py :
import os
class Handler:
def __init__(self):
self.value = os.urandom(5)
def name(self):
return "simple"
If I understand correctly, the import is done on each query to the endpoint. It means IO in the filesystem with lookup for the modules, ...
Is it the correct/"pythonic" way to implement this strategy ?
Question moved to codereview. Thanks all for your help : https://codereview.stackexchange.com/questions/96533/extension-pattern-in-a-flask-controller-using-importlib
I am closing this thread.