Flask-Sijax callbacks are "working outside of request context" - python

While inside a callback function, I lose the ability to access flask.session, flask.g, or functions such as url_for(). They all throw an error saying that I'm "working outside of request context".
Debugging middleware caught exception in streamed response at a point where response headers were already sent.
Traceback (most recent call last):
File "C:\Python27\site-packages\sijax\response\streaming.py", line 136, in _process_call_chain
for string in generator:
File "C:\Python27\site-packages\sijax\response\streaming.py", line 109, in _process_callback
response = self._perform_handler_call(callback, args)
File "C:\Python27\site-packages\sijax\response\base.py", line 258, in _perform_handler_call
return callback(self, *args)
File "C:\Dropbox\Code\Python 2.7\FlaskTesting\testpage.py", line 18, in myformhandler
sql_session = flask.g.sql_session
File "C:\Python27\lib\site-packages\werkzeug\local.py", line 336, in __getattr__
return getattr(self._get_current_object(), name)
File "C:\Python27\lib\site-packages\werkzeug\local.py", line 295, in _get_current_object
return self.__local()
File "C:\Python27\lib\site-packages\flask\globals.py", line 19, in _lookup_object
raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context
192.168.1.141 - - [20/Jun/2012 16:33:04] "POST /testpage HTTP/1.1" 200 -
I've been unable to find out how to get around this problem. Any help would be appreciated.
Python v2.7
Flask v0.8
Flask-Sijax v0.3

You may have a try with stream_with_context. The code example copied from http://flask.pocoo.org/docs/0.12/patterns/streaming/#streaming-with-context
from flask import stream_with_context, request, Response
#app.route('/stream')
def streamed_response():
def generate():
yield 'Hello '
yield request.args['name']
yield '!'
return Response(stream_with_context(generate()))

It would be helpful if you posted your code, but try wrapping your code like this:
with app.app_context():
# do stuff...
or maybe this:
with app.test_request_context():
# do stuff...

Related

How to debug patched method with unittest.mock

I have the following (simplified) FBV:
def check_existing_contacts(request):
if request.is_ajax and request.method == "GET":
print('Function called')
return mailgun_validate_email(request)
return JsonResponse({"error": "Incorrect AJAX / GET request."}, status=400)
I want to test that the mailgun_validate_email function is called:
class TestCheckExistingContacts(TestCase):
#patch('myapp.mailgun_validate_email')
def test_new_contact(self, mock):
client = Client()
client.get('/check/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertTrue(mock.called)
I am certain the test calls mailgun_validate_email as the print('Function called') displays in the console. However I get an assertion error that the mock.called is False.
Where am I going wrong / how can I debug this?
************ UPDATE *******************
When patching the function in the same module as the view, I get the following error:
class TestCheckExistingContacts(TestCase):
#patch('[path to views.py with check_existing_contacts].mailgun_validate_email')
def test_new_contact(self, mock):
client = Client()
client.get('/check/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertTrue(mock.called)
Results in:
Failure
Traceback (most recent call last):
File "\tests\test_utils.py", line 123, in test_new_contact
response = self.client.get('/validate/',
File "\.venv\lib\site-packages\django\test\client.py", line 518, in get
response = super().get(path, data=data, secure=secure, **extra)
File "\.venv\lib\site-packages\django\test\client.py", line 344, in get
return self.generic('GET', path, secure=secure, **{
File "\.venv\lib\site-packages\django\test\client.py", line 421, in generic
return self.request(**r)
File "\.venv\lib\site-packages\django\test\client.py", line 496, in request
raise exc_value
File "\.venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "\.venv\lib\site-packages\django\utils\deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "\.venv\lib\site-packages\django\contrib\sessions\middleware.py", line 45, in process_response
patch_vary_headers(response, ('Cookie',))
File "\.venv\lib\site-packages\django\utils\cache.py", line 267, in patch_vary_headers
vary_headers = cc_delim_re.split(response['Vary'])
TypeError: expected string or bytes-like object
If you did from myapp import mailgun_validate_email for check_existing_contacts, then you need to patch the reference in that module instead of myapp.
E.g. if the import is in myapp/views.py, then patch myapp.views.mailgun_validate_email.
The view needs to return an instance of HttpResponse or one of its subclasses, same for mailgun_validate_email since you directly return mailgun_validate_email(...).
# #patch('myapp.mailgun_validate_email') # Change this
#patch('myapp.views.mailgun_validate_email', return_value=JsonResponse({})) # to this

Internal Server Error, rather than raised AuthError response from Auth0

I have my flask-restful app.py which contains all of my main functions. I have created a server.py file as instructed from here: https://auth0.com/docs/quickstart/backend/python
In my app.py file from server i import AuthError and requires_auth. I have then put #requires_auth in front of my functions.
When I have a valid jwt, it works perfectly. When the jwt is not valid it fails. Failing is good, because the requests shouldn't work. But the response i get from my api is "Internal Server Error" rather than the detailed response in the raise AuthError section in the server.py file.
I get 2 errors:
Traceback (most recent call last):
File "C:\Users\ME\code\server.py", line 88, in decorated
issuer="https://"+AUTH0_DOMAIN+"/"
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 150, in decode
options=defaults)
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 457, in _validate_claims
_validate_exp(claims, leeway=leeway)
File "C:\Users\ME\lib\site-packages\jose\jwt.py", line 299, in _validate_exp
raise ExpiredSignatureError('Signature has expired.')
jose.exceptions.ExpiredSignatureError: Signature has expired.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\ME\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\ME\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\ME\lib\site-packages\flask_restful\__init__.py", line 480, in wrapper
resp = resource(*args, **kwargs)
File "C:\Users\ME\lib\site-packages\flask\views.py", line 88, in view
return self.dispatch_request(*args, **kwargs)
File "C:\Users\ME\lib\site-packages\flask_restful\__init__.py", line 595, in dispatch_request
resp = meth(*args, **kwargs)
File "C:\Users\ME\code\server.py", line 92, in decorated
"description": "token is expired"}, 401)
server.AuthError: ({'code': 'token_expired', 'description': 'token is expired'}, 401)
How do i get the AuthError as the response to the call, rather than just my Internal Server Error?
Thanks!
There is an issue with this specific tutorial in Auth0, it instructs you to include the error handler in auth.py:
#app.errorhandler(AuthError)
def handle_auth_error(ex):
response = jsonify(ex.error)
response.status_code = ex.status_code
return response
Instead, you have to include this handler in your app.py, where you actually use #requires_auth.
Notice that to do so, you need to add relevant imports:
from auth import AuthError
from flask import jsonify
Notice: To be able to import from auth.py you need to add an empty file __init__.py in the same directory.
Try setting app.config[“PROPAGATE_EXCEPTIONS”] = True
Uou could maybe use an errorhandler to explicitly catch those errors and return some explicit json based on them.

Bottle GET request is broken with certain strings when running with paste server

I have a problem similar to this one:
Python bottle: UTF8 path string invalid when using app.mount()
When I try to GET /languages/Inglês I receive the error below (notice the accent "ê"). When passing [az] strings it works fine.
Critical error while processing request: /languages/Inglês
I tried the fix mentioned on the link above without success.
Working example:
from bottle import route, run, debug
#route('/languages/<name>')
def hello(name):
return name
if __name__ == '__main__':
debug(False)
#run(reloader=False, port = 8080) # works
run(server='paste', port = 8080) # fails
Running with server='paste' causes the crash, but using the Bottle server it runs OK. The problem seems to happen at the bottle._handle() method, where a UnicodeError is thrown (bottle.py line 844):
def _handle(self, environ):
path = environ['bottle.raw_path'] = environ['PATH_INFO']
if py3k:
try:
environ['PATH_INFO'] = path.encode('latin1').decode('utf8')
except UnicodeError:
return HTTPError(400, 'Invalid path string. Expected UTF-8')
I'm using Python 3.6.2, Bottle v0.12.13 and Paste 2.0.3 on a Windows 10 machine. What's going on? Is that a problem with Bottle or Paste?
Note: I've already solved my problem by refactoring all the code to use integer IDs instead of names. But I still would like to learn more about this.
Stack trace:
Critical error while processing request: /hello/inglês
Error:
RuntimeError('Request context not initialized.',)
Traceback:
Traceback (most recent call last):
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 1661, in fget
try: return ls.var
AttributeError: '_thread._local' object has no attribute 'var'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 954, in wsgi
out = self._cast(self._handle(environ))
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 907, in _cast
out = self.error_handler.get(out.status_code, self.default_error_handler)(out)
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 842, in default_error_handler
return tob(template(ERROR_PAGE_TEMPLATE, e=res))
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 3619, in template
return TEMPLATES[tplid].render(kwargs)
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 3409, in render
self.execute(stdout, env)
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 3396, in execute
eval(self.co, env)
File "<string>", line 17, in <module>
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 1249, in url
return self.urlparts.geturl()
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 165, in __get__
key, storage = self.key, getattr(obj, self.attr)
File "C:\Users\fernando.filho\AppData\Local\Programs\Python\Python36\lib\site-packages\bottle.py", line 1663, in fget
raise RuntimeError("Request context not initialized.")
RuntimeError: Request context not initialized.
Answering my own question, quoting #GrahamDumpleton:
The Paste server is not tolerant of being sent non ASCII characters.
this is the bottle's problem!
In order to use paste server u can change this:
"""bottle.py"""
environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')
to:
environ['PATH_INFO'] = path.encode('utf8').decode('utf8', 'ignore') #utf-8 or else
it's work well.

Python requests hook returns a value to cause exception

The Documentation for python requests module says for hooks that "If the callback function returns a value, it is assumed that it is to replace the data that was passed in. If the function doesn’t return anything, nothing else is effected"
Now i am trying to return a value(int in my case) from my hook function and it throws an exception. This will be valid in all the cases when the return value is an object that DOESNOT have the raw() method defined for it.
Here is some code
def hook(resp,**kwargs):
print resp.url
return 1
def main()
s = requests.Session()
s.hooks = {"response":hook}
r = s.get("http://localhost/index.html")
And here is the exception:
http://localhost/index.html
Traceback (most recent call last):
File "/home/talha/ws/test.py", line 85, in <module>
main()
File "/home/talha/ws/test.py", line 72, in main
r = s.get("http://localhost/index.html")
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 347, in get
return self.request('GET', url, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 335, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 446, in send
extract_cookies_to_jar(self.cookies, request, r.raw)
AttributeError: 'int' object has no attribute 'raw'
The code in sessions.py #line 446 is trying to extract cookies after the dispatch_hook..From source
# Response manipulation hooks
r = dispatch_hook('response', hooks, r, **kwargs)
# Persist cookies
extract_cookies_to_jar(self.cookies, request, r.raw)
Either the documentation needs to change or the handling needs to be re-worked. What is the best way to handle this ?
[update]
Based on the comments I tried to return the base response object. Turns out it cannot be used in that manner also since some of its fields are initialized to None.
Newer code:
def hook(resp, **kwargs):
obj = requests.Response()
return obj
Exception thrown now:
Traceback (most recent call last):
File "/home/talha/ws/test.py", line 88, in <module>
main()
File "/home/talha/ws/test.py", line 75, in main
r = s.get("http://localhost/index.html")
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 347, in get
return self.request('GET', url, **kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 335, in request
resp = self.send(prep, **send_kwargs)
File "/usr/lib/python2.7/site-packages/requests/sessions.py", line 446, in send
extract_cookies_to_jar(self.cookies, request, r.raw)
File "/usr/lib/python2.7/site-packages/requests/cookies.py", line 108, in extract_cookies_to_jar
res = MockResponse(response._original_response.msg)
AttributeError: 'NoneType' object has no attribute '_original_response'
What seems is that i will have to implement a full pseudo response?
If the callback function returns a value, it is assumed that it is to replace the data that was passed in. If the function doesn’t return anything, nothing else is effected.
This means that whatever you return is expected to take the place of the response object you were passed.
Nothing in the documentation states that you can return just anything. What did you expect to happen instead?
If you wanted to return a response that has different data, return something that acts like a response still. This means that either you need to subclass the requests response object, or implement something that provides the same API:
from requests.models import Response
class MyIntResponse(Response):
def __init__(self, integer):
super(MyIntResponse, self).__init__()
self._content_consumed = True
self._content = integer
def hook(resp,**kwargs):
print resp.url
newresp = MyIntResponse(1)
newresp.raw = resp.raw # copy across original HTTP response object
You may want to copy over some of the other attributes from the original response; check the documentation on what attributes Response objects have.

AppEngine/Python: Why isn't the exception caught?

I'm trying to write a Google-Appengine app that will fail nicely when datastore writes are disabled
Currently my main() looks like this:
def main():
make_datastore_readonly()
try:
run_wsgi_app(application)
except CapabilityDisabledError:
run_wsgi_app(NoWrite)
If I set main to:
def main():
run_wsgi_app(application)
My app displays a traceback when the exception is raised.
If I set main to:
def main():
run_wsgi_app(NoWrite)
It will properly show my error message (although for every request).
Getting back to my modified version of main, this one:
def main():
make_datastore_readonly()
try:
run_wsgi_app(application)
except CapabilityDisabledError:
run_wsgi_app(NoWrite)
Instead of getting my error message, I still get a traceback that looks like this:
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/_webapp25.py", line 703, in __call__
handler.post(*groups)
File "/Users/kevin/Sche/main.py", line 232, in post
me.put();
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/db/__init__.py", line 1074, in put
return datastore.Put(self._entity, **kwargs)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/datastore.py", line 579, in Put
return PutAsync(entities, **kwargs).get_result()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/datastore.py", line 556, in PutAsync
return _GetConnection().async_put(config, entities, local_extra_hook)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1553, in async_put
return make_put_call(base_req, pbs, extra_hook)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1543, in make_put_call
self.__put_hook, user_data)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1188, in make_rpc_call
rpc.make_call(method, request, response, get_result_hook, user_data)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/apiproxy_stub_map.py", line 519, in make_call
self.__service, method, request, response, self.__rpc)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/apiproxy_stub_map.py", line 207, in Call
function(service, call, request, response)
File "/Users/kevin/Sche/main.py", line 18, in hook
raise CapabilityDisabledError('Datastore is in read-only mode')
CapabilityDisabledError: Datastore is in read-only mode
So, my question is, why isn't the exception caught?
Edit:
This function is from this StackOverflow answer
def make_datastore_readonly():
"""Throw ReadOnlyError on put and delete operations."""
def hook(service, call, request, response):
assert(service == 'datastore_v3')
if call in ('Put', 'Delete'):
raise CapabilityDisabledError('Datastore is in read-only mode') //Line 18
apiproxy_stub_map.apiproxy.GetPreCallHooks().Push('readonly_datastore', hook, 'datastore_v3')
the main function only register this application. Therefore, the exception will not raise in the main function. Therefore the try ... catch statement won't work.
The way to handle this exception is defining a new RequestHandler. Then, all requests which want to have this feature should inherent from the new RequestHandler.
for example:
Class MyRequestHandler(RequestHandler):
def get(self):
try:
self.get_handler()
except CapabilityDisabledError:
pass
class MyRequest(MyRequestHandler):
def get_handler(self):
# ....
pass

Categories