I am using application factory pattern in which I have initialized my cache
from xyz.caching import cache # this is the cache object
def create_app():
app = Flask(__name__)
cache.init_app(app)
# other relevant variables.
return app
My caching.py
from flask_caching import Cache
cache = Cache(config={....})
When I import this in any file xyz.caching import cache, this works totally fine. However, in my application I have a entry point script, run.py
run.py
from xyz.caching import cache
def run_this():
cache.get('XXX')
if __name__ == "__main__":
run_this()
After running python run.py, I get the following error
'AttributeError: 'Cache' object has no attribute 'app''
Pls. guide me what is wrong in this, why I am getting this error and what is the way to solve this ?
I got this message because I forgot to initialize the app
cache.init_app(app)
I would try to debug if this method call is reached before cache.get('XXX') is called.
Related
I am attempting to create a Flask middleware in order to make py2neo transactions atomic. First I got a working outside of application context error, and I tried to apply this solution, as seen in the following code:
from flask import g
from py2neo import Graph
def get_db():
return Graph(password="secret")
class TransactionMiddleware(object):
def __init__(self, app):
self.app = app
with app.app_context(): # Error raises here.
g.graph = get_db()
g.transaction = g.graph.begin()
def __call__(self, environ, start_response):
try:
app_status = self.app(environ, start_response)
# some code
return app_status
except BaseException:
g.transaction.rollback()
raise
else:
g.transaction.commit()
But I got this error: AttributeError: 'function' object has no attribute 'app_context'.
I don't know if the solution I'm trying is not suitable for my case, or what is the problem.
You are in a WSGI middleware, so what gets passed in as an app is actually a method called Flask.wsgi_app the results of which you a later supposed to return from your __call__ handler.
Perhaps you can simply import your actual flask app and use app_context on that, as in:
from app import app # or whatever module it's in
# and then
class TransactionMiddleware(object):
...
def __call__(self, environ, start_response):
with app.app_context():
...
I would also consider just instantiating your Graph somehere on a module level. Perhaps next to your flask app instantiation and not attaching it to g. This way you can use it without application context:
# app.py
flask = Flask(__main__)
db = Graph(password="secret")
You can use it by directly importing:
# middleware.py
from app import db
I have the following three files.
app.py
from flask_restful import Api
from lib import globals
from flask import Flask
from flask.ext.cache import Cache
globals.algos_app = Flask(__name__)
#cache in file system
globals.cache = Cache(globals.algos_app, config={'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '/tmp'})
api = Api(globals.algos_app)
api.add_resource(Test, '/test')
if __name__ == '__main__':
globals.algos_app.run(host='0.0.0.0', debug=True)
globals.py
global algos_app
global cache
Test.py
from flask_restful import Resource
from lib import globals
from flask_restful import Resource
import time
class Test(Resource):
def get(self):
return self.someMethod()
def post(self):
globals.cache.clear()
return self.someMethod()
#globals.cache.cached()
def someMethod(self):
return str(time.ctime())
I have a GET method which needs to the value from the cache and a POST method which updates the cache by first clearing the cache.
However, no matter I call the GET or the POST method, it always gives me the value from the cache.
PS: At the moment I am simply testing on the development server however I do need to deploy it using WSGI later.
I am not sure if it is the best way, but I did it using the following way.
class Test(Resource):
def get(self):
return globals.cache.get('curr_time')
def post(self):
result = self.someMethod()
globals.cache.set('curr_time', result, timeout=3600)
def someMethod(self):
return str(time.ctime())
I am trying to use mod-wsgi with Apache 2.2
I have the following directory structure:
scheduling-algos
-lib
-common
-config
-config.json
resources
-Optimization.py
optimization.wsgi
optimization_app.py
My optimization_app.py is the following:
from flask import Flask
from flask_restful import Api
from resources.Optimization import OptimizationAlgo
def optimizeInstances():
optimization_app = Flask(__name__)
api = Api(optimization_app)
api.add_resource(OptimizationAlgo, '/instances')
if __name__ == '__main__':
optimizeInstances()
optimization_app.run(host='0.0.0.0', debug=True)
My Optimization.py code looks like the following:
class OptimizationAlgo(Resource):
def post(self):
return "success"
When I make a POST request to the url http://<host>:5000/instances, it works just as expected. I want make this work using WSGI. I have mod-wsgi installed with Apache 2.2.
My optimization.wsgi file looks like the following
import sys
sys.path.insert(0, '<path to app>')
from optimization_app import optimizeInstances as application
I get the following error: TypeError: optimizeInstances() takes no arguments (2 given) . Apparently this is not the correct way to use WSGI. What is the correct way to use WSGI?
Apparently, this is not the correct way to use WSGI.
As I told you in your other question, you should perhaps go back and read the Flask documentation again. That way you will learn and understand properly. By ignoring advice and expecting others to tell you, it only annoys people and they will stop helping you. Would suggest you take heed of that rather than leave a trail of separate questions hoping someone will solve your problems for you.
That said, I can't see how the code you give can even work with the Flask development server as you claim. The problem is that optimization_app = Flask(__name__) is setting a local variable within function scope. It isn't setting a global variable. As a result the call of optimization_app.run(host='0.0.0.0', debug=True) should fail with a LookupError as it will not see a variable called optimization_app. Not even sure why you are bothering with the function.
If you go look at the Flask documentation, the pattern it would likely use is:
# optimisation.wsgi
import sys
sys.path.insert(0, '<path to app>')
# We alias 'app' to 'application' here as mod_wsgi expects it to be called 'application'.
from optimization_app import app as application
# optimization_app.py
from flask import Flask
from flask_restful import Api
from resources.Optimization import OptimizationAlgo
app = Flask(__name__)
api = Api(app)
api.add_resource(OptimizationAlgo, '/instances')
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
I can't figure out what can be the reason.
On my dev machine the exactly same django project runs properly, while on production in the custom middleware code app_cache_ready() method always returns False. If I ignore and bypass it cache.set does not cache the object.
My dev environment uses runserver to launch the server, while the production uses Apache and mod_wsgi with virtualhost directives.
Does anyone have a clue what might be the problem? I have already spent couple of hours with no success.
Thanks in advance
Below is the simplified code that fails to cache again:
from django.conf import settings
from django.contrib.sites.models import Site
from django.http import HttpResponseRedirect, Http404
from django.core.cache import cache
from django.db.models.loading import app_cache_ready
from django.utils.cache import patch_vary_headers
class MyMiddleware(object):
def process_request(self, request):
key='kuku'
val=cache.get(key)
if not val:
logger.warn('Cached key is not available')
cache.set(key,5)
else:
logger.warn('Cached key is %s' % str(val))
With subsequent calls I see always Cached key is not available.
I'm currently running some Django tests and it looks that DEBUG=False by default. Is there a way to run a specific test where I can set DEBUG=True at the command line or in code?
For a specific test inside a test case, you can use the override_settings decorator:
from django.test.utils import override_settings
from django.conf import settings
class TestSomething(TestCase):
#override_settings(DEBUG=True)
def test_debug(self):
assert settings.DEBUG
Starting with Django 1.11 you can use --debug-mode to set the DEBUG setting to True prior to running tests.
The accepted answer didn't work for me. I use Selenium for testing, and setting #override_settings(DEBUG=True) makes the test browser always display 404 error on every page. And DEBUG=False does not show exception tracebacks. So I found a workaround.
The idea is to emulate DEBUG=True behaviour, using custom 500 handler and built-in django 500 error handler.
Add this to myapp.views:
import sys
from django import http
from django.views.debug import ExceptionReporter
def show_server_error(request):
"""
500 error handler to show Django default 500 template
with nice error information and traceback.
Useful in testing, if you can't set DEBUG=True.
Templates: `500.html`
Context: sys.exc_info() results
"""
exc_type, exc_value, exc_traceback = sys.exc_info()
error = ExceptionReporter(request, exc_type, exc_value, exc_traceback)
return http.HttpResponseServerError(error.get_traceback_html())
urls.py:
from django.conf import settings
if settings.TESTING_MODE:
# enable this handler only for testing,
# so that if DEBUG=False and we're not testing,
# the default handler is used
handler500 = 'myapp.views.show_server_error'
settings.py:
# detect testing mode
import sys
TESTING_MODE = 'test' in sys.argv
Now if any of your Selenium tests encounters 500 error, you'll see a nice error page with traceback and everything. If you run a normal non-testing environment, default 500 handler is used.
Inspired by:
Where in django is the default 500 traceback rendered so that I can use it to create my own logs?
django - how to detect test environment
Okay let's say you want to write tests for error testcase for which the urls are :-
urls.py
if settings.DEBUG:
urlpatterns += [
url(r'^404/$', page_not_found_view),
url(r'^500/$', my_custom_error_view),
url(r'^400/$', bad_request_view),
url(r'^403/$', permission_denied_view),
]
test_urls.py:-
from django.conf import settings
class ErroCodeUrl(TestCase):
def setUp(self):
settings.DEBUG = True
def test_400_error(self):
response = self.client.get('/400/')
self.assertEqual(response.status_code, 500)
Hope you got some idea!
Nothing worked for me except https://stackoverflow.com/a/1118271/5750078
Use Python 3.7
breakpoint()
method.
Works fine on pycharm
You can't see the results of DEBUG=True when running a unit test. The pages don't display anywhere. No browser.
Changing DEBUG has no effect, since the web pages (with the debugging output) are not visible anywhere.
If you want to see a debugging web page related to a failing unit test, then do this.
Drop your development database.
Rerun syncdb to build an empty development database.
Run the various loaddata scripts to rebuild the fixtures for that test in your development database.
Run the server and browse the page.
Now you can see the debug output.