I can't seem to generate responses from exceptions anymore in Flask 0.10.1 (the same happened with 0.9). This code:
from flask import Flask, jsonify
from werkzeug.exceptions import HTTPException
import flask, werkzeug
print 'Flask version: %s' % flask.__version__
print 'Werkzeug version: %s' % werkzeug.__version__
app = Flask(__name__)
app.config['PROPAGATE_EXCEPTIONS'] = True
class JSONException(HTTPException):
response = None
def get_body(self, environ):
return jsonify(a=1)
def get_headers(self, environ):
return [('Content-Type', 'application/json')]
#app.route('/x')
def x():
return jsonify(a=1)
#app.route('/y')
def y():
raise JSONException()
c = app.test_client()
r = c.get('x')
print r.data
r = c.get('y')
print r.data
prints
Flask version: 0.10.1
Werkzeug version: 0.9.4
{
"a": 1
}
Traceback (most recent call last):
File "flask_error.py", line 33, in <module>
print r.data
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 881, in get_data
self._ensure_sequence()
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 938, in _ensure_sequence
self.make_sequence()
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 953, in make_sequence
self.response = list(self.iter_encoded())
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 81, in _iter_encoded
for item in iterable:
File "/home/path/lib/python2.7/site-packages/werkzeug/wsgi.py", line 682, in __next__
return self._next()
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 81, in _iter_encoded
for item in iterable:
File "/home/path/lib/python2.7/site-packages/werkzeug/wsgi.py", line 682, in __next__
return self._next()
File "/home/path/lib/python2.7/site-packages/werkzeug/wrappers.py", line 81, in _iter_encoded
for item in iterable:
TypeError: 'Response' object is not iterable
The traceback is unexpected.
jsonify() produces a full response object, not a response body, so use HTTPException.get_response(), not .get_body():
class JSONException(HTTPException):
def get_response(self, environ):
return jsonify(a=1)
The alternative is to just use json.dumps() to produce a body here:
class JSONException(HTTPException):
def get_body(self, environ):
return json.dumps({a: 1})
def get_headers(self, environ):
return [('Content-Type', 'application/json')]
Related
This is the logs I received from my unittest for my APIs flask application which is using flask-restful, it showed that I have an int object not iterable error.
Really appreciate if anyone tell me what is actually wrong in my unittest codes :(
.
======================================================================
ERROR: test_brand_create (test.brand.BrandTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/david/ITP-Team3/test/brand.py", line 37, in test_brand_create
response = tester.post('/api/brand/', data=json.dumps(payload), headers=headers)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1140, in post
return self.open(*args, **kw)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/flask/testing.py", line 217, in open
return super().open(
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1089, in open
response = self.run_wsgi_app(request.environ, buffered=buffered)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 956, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1255, in run_wsgi_app
for item in app_iter:
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/wsgi.py", line 462, in __next__
return self._next()
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/wrappers/response.py", line 50, in _iter_encoded
for item in iterable:
TypeError: 'int' object is not iterable
======================================================================
ERROR: test_brand_put (test.brand.BrandTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/david/ITP-Team3/test/brand.py", line 49, in test_brand_put
response = tester.put('/api/brand/'+id, data=json.dumps(payload), headers=headers)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1145, in put
return self.open(*args, **kw)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/flask/testing.py", line 217, in open
return super().open(
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1089, in open
response = self.run_wsgi_app(request.environ, buffered=buffered)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 956, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/test.py", line 1255, in run_wsgi_app
for item in app_iter:
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/wsgi.py", line 462, in __next__
return self._next()
File "/Users/david/.local/share/virtualenvs/ITP-Team3-bpvJtb_C/lib/python3.10/site-packages/werkzeug/wrappers/response.py", line 50, in _iter_encoded
for item in iterable:
TypeError: 'int' object is not iterable
----------------------------------------------------------------------
Ran 11 tests in 2.370s
FAILED (errors=2)
Here's my test code that I had the error on:
# brand.py
def test_brand_create(self):
tester = app.test_client(self)
headers = login(tester)
payload = {'brandName': 'test1'}
response = tester.post('/api/brand/', data=json.dumps(payload), headers=headers)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
def test_brand_put(self):
tester = app.test_client(self)
headers = login(tester)
payload = {'brandName': 'test'}
print("TYPE", type(get_id(app, Brand, 'test1')))
print("VALUE", get_id(app, Brand, 'test1'))
id = get_id(app, Brand, 'test1')
response = tester.put('/api/brand/'+id, data=json.dumps(payload), headers=headers)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
and the utils code as well
# utils.py
def login(tester):
headers = {'Content-Type': 'application/json'}
# put user and password in .env file
payload = {'username': os.getenv("user"), 'password_hash': os.getenv("password")}
response = tester.post('/api/user/login/', data= json.dumps(payload), headers=headers)
jwt_str = response.data.decode('utf-8')
header_jwt= ast.literal_eval(jwt_str)
return {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + header_jwt['jwt_token']}
def get_id(app, model, brandName) -> None:
with app.app_context():
test_query = model.query.filter_by(brandName=brandName).first()
id_lookup = model.query.get(test_query.id)
return str(id_lookup.id)
I have been using django-channels, I had created a room for 2 users using single thread
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models import Q
from channels.db import SyncToAsync
# Create your models here.
model = get_user_model()
class threadmanager(models.Manager):
def get_or_create(self,firstuser,seconduser):
thread = self.get_queryset().filter(((Q(first=firstuser)and Q(second = seconduser ))) or ((Q(first=seconduser)and Q(second = firstuser ))))
if thread:
print(thread.first())
return thread
thread = self.model(first=firstuser,second=seconduser)
thread.save()
return(thread)
class thread(models.Model):
first = models.ForeignKey(model,on_delete=models.CASCADE,related_name="first")
second = models.ForeignKey(model,on_delete=models.CASCADE,related_name="second")
objects = threadmanager()
def __str__(self):
return self.first.username + "-" + self.second.username
My chatconsumer is
from channels.consumer import AsyncConsumer
import asyncio
from channels.db import database_sync_to_async
import json
from accounts.models import thread
from django.contrib.auth import get_user_model
model = get_user_model()
class ChatConsumer(AsyncConsumer):
async def websocket_connect(self,event):
await self.send(
{
'type':'websocket.accept',
}
)
print("connected",event)
async def websocket_receive(self,event):
print("received",event)
firstuser,seconduser = await self.get_socket_users(event)
currentthread = await self.get_current_thread(firstuser,seconduser)
print(currentthread)
async def websocket_disconnect(self,event):
print("disconnected",event)
#database_sync_to_async
def get_socket_users(self,event):
first = self.scope['user']
second = model.objects.get(username=event['text'])
return first,second
#database_sync_to_async
def get_current_thread(self,firstuser,seconduser):
return thread.objects.get_or_create(firstuser,seconduser)
Whenever i am trying to create a new thread between 2 users i am successfully getting it:
for example my first user is root and second user is rusker.
WebSocket HANDSHAKING /profile [127.0.0.1:35432]
WebSocket CONNECT /profile [127.0.0.1:35432]
connected {'type': 'websocket.connect'}
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
But whenever i am trying to get the same thread between the same 2 users , i am receiving the thread from the database but during returning the thread i am getting error like this:
WebSocket CONNECT /profile [127.0.0.1:35432]
connected {'type': 'websocket.connect'}
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
received {'type': 'websocket.receive', 'text': 'rusker'}
root-rusker
Exception inside application: You cannot call this from an async context - use a thread or sync_to_async.
Traceback (most recent call last):
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 173, in __get__
rel_obj = self.field.get_cached_value(instance)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/mixins.py", line 15, in get_cached_value
return instance._state.fields_cache[cache_name]
KeyError: 'first'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/consumer.py", line 62, in __call__
await await_many_dispatch([receive], self.dispatch)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/root/Desktop/pydjango/django-project/Game/Game/consumer.py", line 28, in websocket_receive
print(currentthread)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 266, in __repr__
return '<%s %r>' % (self.__class__.__name__, data)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/base.py", line 519, in __repr__
return '<%s: %s>' % (self.__class__.__name__, self)
File "/root/Desktop/pydjango/django-project/Game/accounts/models.py", line 42, in __str__
return self.first.username + "-" + self.second.username
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 187, in __get__
rel_obj = self.get_object(instance)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 154, in get_object
return qs.get(self.field.get_reverse_related_filter(instance))
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 425, in get
num = len(clone)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 269, in __len__
self._fetch_all()
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 1308, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/query.py", line 53, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1154, in execute_sql
cursor = self.connection.cursor()
File "/root/Desktop/pydjango/tenv/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
WebSocket DISCONNECT /profile [127.0.0.1:35432]
I have this function, it returns a result on console:
numbers_to_add = list(range(10000001))
try:
req = request.Request('http://127.0.0.1:5000/total'
, data=bytes(json.dumps(numbers_to_add), 'utf_8')
, headers={'Content-Type': 'application/json'}
, method='POST')
result = json.loads(request.urlopen(req).read(), encoding='utf_8')
print(json.dumps(result, indent=4))
except Exception as ex:
print(ex)
It returns a result on range 10000001
Now , I want to return this on browser request, in a Flask application, I've tried this:
def hardCoded():
numbers_to_add = list(range(10000001))
try:
req = request.Request('http://127.0.0.1:5000/total'
, data=bytes(json.dumps(numbers_to_add), 'utf_8')
, headers={'Content-Type': 'application/json'}
, method='POST')
result = json.loads(request.urlopen(req).read(), encoding='utf_8')
print(json.dumps(result, indent=4))
except Exception as ex:
print(ex)
class rangeNumbers(Resource):
def get(self, range):
return {'data': directSum.hardCoded(range)}
api.add_resource(rangeNumbers, '/range/<range>')
When I query this on my browser, it throws me this:
Traceback (most recent call last):
File "/home/user/.virtualenvs/test_sum/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/user/.virtualenvs/test_sum/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/user/.virtualenvs/test_sum/lib/python3.6/site-packages/flask_restful/__init__.py", line 480, in wrapper
resp = resource(*args, **kwargs)
File "/home/user/.virtualenvs/test_sum/lib/python3.6/site-packages/flask/views.py", line 84, in view
return self.dispatch_request(*args, **kwargs)
File "/home/user/.virtualenvs/test_sum/lib/python3.6/site-packages/flask_restful/__init__.py", line 595, in dispatch_request
resp = meth(*args, **kwargs)
File "app.py", line 16, in get
return {'data': directSum.hardCoded()}
TypeError: hardCoded() takes 0 positional arguments but 1 was given
Any ideas?
If range is meant to be the n number to return, in this case, 10000001, then you will want to do this instead:
In your directSum file:
def hardCoded(rng):
numbers_to_add = list(range(rng))
try:
# ... rest of code ...
In your main file:
class rangeNumbers(Resource):
def get(self, rng):
return {'data': directSum.hardCoded(rng)}
Where when you call rangeNumbers().get you do this:
rng_num = rangeNumbers()
rng_num.get(10000001)
Notice I changed your variable range to rng. It's in your best interest to not overshadow the builtin names even within a local scope. Otherwise calling range(range) is going to give you endless pain.
I'm doing a POST request to an API, the code looks like this:
#gen.coroutine
def call():
...
response = yield AsyncHTTPClient().fetch(
HTTPRequest(
url='https://api.mywebsite.com/v1/users',
headers=headers,
method='POST',
body=json.dumps(body),
validate_cert=False
)
)
print response, response.body
if __name__ == "__main__":
tornado.ioloop.IOLoop.current().run_sync(call)
The server responds first time with 201 Created and the second time with 200 OK.
But for that code I get this error for the first time. The second time works
Traceback (most recent call last):
File "t.py", line 49, in <module>
tornado.ioloop.IOLoop.current().run_sync(call)
File "/usr/lib/python2.7/dist-packages/tornado/ioloop.py", line 389, in run_sync
return future_cell[0].result()
File "/usr/lib/python2.7/dist-packages/tornado/concurrent.py", line 129, in result
raise_exc_info(self.__exc_info)
File "/usr/lib/python2.7/dist-packages/tornado/stack_context.py", line 302, in wrapped
ret = fn(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/tornado/gen.py", line 574, in inner
self.set_result(key, result)
File "/usr/lib/python2.7/dist-packages/tornado/gen.py", line 500, in set_result
self.run()
File "/usr/lib/python2.7/dist-packages/tornado/gen.py", line 529, in run
yielded = self.gen.throw(*exc_info)
File "t.py", line 43, in call
validate_cert=False
File "/usr/lib/python2.7/dist-packages/tornado/gen.py", line 520, in run
next = self.yield_point.get_result()
File "/usr/lib/python2.7/dist-packages/tornado/gen.py", line 409, in get_result
return self.runner.pop_result(self.key).result()
File "/usr/lib/python2.7/dist-packages/tornado/concurrent.py", line 131, in result
return super(TracebackFuture, self).result(timeout=timeout)
File "/usr/lib/python2.7/dist-packages/concurrent/futures/_base.py", line 401, in result
return self.__get_result()
File "/usr/lib/python2.7/dist-packages/concurrent/futures/_base.py", line 360, in __get_result
raise self._exception
AssertionError
Looks like you are using sync function HTTPRequest in future
from tornado.httpclient import AsyncHTTPClient
from tornado.httpclient import HTTPResponse
def call():
response = None
http_client = AsyncHTTPClient()
try:
body = json.dumps(body)
response: HTTPResponse = yield http_client.fetch('https://api.mywebsite.com/v1/users', method='POST', body=str(body), headers=headers, request_timeout=5)
except Exception as e:
print('get_request error:{0}'.format(e))
I have delete endpoint, returning HTTP 204
#blueprint.route('/foo', methods=['DELETE'])
def delete_tag(id):
# ....
return '', 204
and I want to test it
def test_delete_tag(self):
resp = self.client.delete(url_for('tags.delete_tag', id=1))
self.assertEqual(resp.status_code, 204)
but I got exception
Traceback (most recent call last):
File "tests/tags_test.py", line 31, in test_delete_tag
resp = self.client.delete(url_for('tags.delete_tag', id=1)})
File ".virtualenvs/...site-packages/werkzeug/test.py", line 799, in delete
return self.open(*args, **kw)
File ".virtualenvs/...site-packages/flask/testing.py", line 108, in open
follow_redirects=follow_redirects)
File ".virtualenvs/...site-packages/werkzeug/test.py", line 742, in open
response = self.run_wsgi_app(environ, buffered=buffered)
File ".virtualenvs/...site-packages/werkzeug/test.py", line 659, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
File ".virtualenvs/.../site-packages/werkzeug/test.py", line 885, in run_wsgi_app
buffer.append(next(app_iter))
StopIteration
with response status 200 it works all fine. Is there way how to fix the test?
The mining of 204 is "no content" at all, it's assume that you're not going to add any body in that response.
small flask app:
from flask import Flask, request
app = Flask(__name__)
#app.route('/foo', methods=['DELETE'])
def delete_tag():
print("i got", request.form['id'])
return '', 204
#app.route('/foo2/<id>', methods=['DELETE'])
def delete_tag2(id):
print("i got.. .", id)
return '', 204
if __name__ == '__main__':
app.run(debug=True)
and in ipython qtconsole; i did this:
In [3]: from app import app
In [4]: from flask import url_for
In [5]: c = app.test_client()
In [6]: with app.test_request_context():
...: rv = c.delete(url_for('delete_tag2', id=55))
...: print(rv.status_code)
...:
i got.. . 55
204
In [7]: rv = c.delete("/foo", data={"id": 555})
i got 555
In [8]: rv.status_code
Out[8]: 204