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
Related
main.py
#app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
verify(username, password)
def verify(name, psw):
data = User.query.filter_by(username=name, password=psw).first()
if data is not None:
session['logged_in'] = True
else:
session['logged_in'] = False
return redirect(url_for('home', num=None))
test.py
class UnitTest(unittest.TestCase):
def setUp(self):
self.app = Flask(__name__)
app.config['SECRET_KEY'] = '123'
self.client = self.app.test_client()
self.app = app.test_client()
def test_login(self):
with app.test_client() as client:
client.post('/login', data=dict(username='s', password='s'))
with client.session_transaction() as sess:
assert sess['logged_in']
It passes test but there is some error.
[2020-05-25 05:48:58,606] ERROR in app: Exception on /login [POST]
Traceback (most recent call last):
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 1953, in full_dispatch_request
return self.finalize_request(rv)
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 1968, in finalize_request
response = self.make_response(rv)
File "C:\Users\queen\AppData\Local\Programs\Python\Python38-32\lib\site-packages\flask\app.py", line 2097, in make_response
raise TypeError(
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
How can I fix this?
I am trying to implement the Amazon Web Scraper mentioned here. However, I get the output mentioned below. The output repeats until it stops with RecursionError: maximum recursion depth exceeded.
I have already tried downgrading eventlet to version 0.17.4 as mentioned here.
Also, the requestsmodule is getting patched as you can see in helpers.py.
helpers.py
import os
import random
from datetime import datetime
from urllib.parse import urlparse
import eventlet
requests = eventlet.import_patched('requests.__init__')
time = eventlet.import_patched('time')
import redis
from bs4 import BeautifulSoup
from requests.exceptions import RequestException
import settings
num_requests = 0
redis = redis.StrictRedis(host=settings.redis_host, port=settings.redis_port, db=settings.redis_db)
def make_request(url, return_soup=True):
# global request building and response handling
url = format_url(url)
if "picassoRedirect" in url:
return None # skip the redirect URLs
global num_requests
if num_requests >= settings.max_requests:
raise Exception("Reached the max number of requests: {}".format(settings.max_requests))
proxies = get_proxy()
try:
r = requests.get(url, headers=settings.headers, proxies=proxies)
except RequestException as e:
log("WARNING: Request for {} failed, trying again.".format(url))
num_requests += 1
if r.status_code != 200:
os.system('say "Got non-200 Response"')
log("WARNING: Got a {} status code for URL: {}".format(r.status_code, url))
return None
if return_soup:
return BeautifulSoup(r.text), r.text
return r
def format_url(url):
# make sure URLs aren't relative, and strip unnecssary query args
u = urlparse(url)
scheme = u.scheme or "https"
host = u.netloc or "www.amazon.de"
path = u.path
if not u.query:
query = ""
else:
query = "?"
for piece in u.query.split("&"):
k, v = piece.split("=")
if k in settings.allowed_params:
query += "{k}={v}&".format(**locals())
query = query[:-1]
return "{scheme}://{host}{path}{query}".format(**locals())
def log(msg):
# global logging function
if settings.log_stdout:
try:
print("{}: {}".format(datetime.now(), msg))
except UnicodeEncodeError:
pass # squash logging errors in case of non-ascii text
def get_proxy():
# choose a proxy server to use for this request, if we need one
if not settings.proxies or len(settings.proxies) == 0:
return None
proxy = random.choice(settings.proxies)
proxy_url = "socks5://{user}:{passwd}#{ip}:{port}/".format(
user=settings.proxy_user,
passwd=settings.proxy_pass,
ip=proxy,
port=settings.proxy_port,
)
return {
"http": proxy_url,
"https": proxy_url
}
if __name__ == '__main__':
# test proxy server IP masking
r = make_request('https://api.ipify.org?format=json', return_soup=False)
print(r.text)
output
Traceback (most recent call last):
File "helpers.py", line 112, in <module>
r = make_request('https://api.ipify.org?format=json', return_soup=False)
File "helpers.py", line 36, in make_request
r = requests.get(url, headers=settings.headers, proxies=proxies)
File "/home/ec2-user/env/lib64/python3.7/site-packages/requests/api.py", line 76, in get
return request('get', url, params=params, **kwargs)
File "/home/ec2-user/env/lib64/python3.7/site-packages/requests/api.py", line 61, in request
return session.request(method=method, url=url, **kwargs)
File "/home/ec2-user/env/lib64/python3.7/site-packages/requests/sessions.py", line 530, in request
resp = self.send(prep, **send_kwargs)
File "/home/ec2-user/env/lib64/python3.7/site-packages/requests/sessions.py", line 643, in send
r = adapter.send(request, **kwargs)
File "/home/ec2-user/env/lib64/python3.7/site-packages/requests/adapters.py", line 449, in send
timeout=timeout
File "/home/ec2-user/env/lib64/python3.7/site-packages/urllib3/connectionpool.py", line 672, in urlopen
chunked=chunked,
File "/home/ec2-user/env/lib64/python3.7/site-packages/urllib3/connectionpool.py", line 376, in _make_request
self._validate_conn(conn)
File "/home/ec2-user/env/lib64/python3.7/site-packages/urllib3/connectionpool.py", line 994, in _validate_conn
conn.connect()
File "/home/ec2-user/env/lib64/python3.7/site-packages/urllib3/connection.py", line 300, in connect
conn = self._new_conn()
File "/home/ec2-user/env/lib64/python3.7/site-packages/urllib3/contrib/socks.py", line 99, in _new_conn
**extra_kw
File "/home/ec2-user/env/lib64/python3.7/site-packages/socks.py", line 199, in create_connection
sock.connect((remote_host, remote_port))
File "/home/ec2-user/env/lib64/python3.7/site-packages/socks.py", line 47, in wrapper
return function(*args, **kwargs)
File "/home/ec2-user/env/lib64/python3.7/site-packages/socks.py", line 774, in connect
super(socksocket, self).settimeout(self._timeout)
File "/home/ec2-user/env/lib64/python3.7/site-packages/eventlet/greenio/base.py", line 395, in settimeout
self.setblocking(True)
What might be the problem here?
Turns out removing eventlet.monkey_patch() and import eventlet solved the problem.
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 have a problem with Python Flask Restful API and data goes to Elasticsearch, when i post a new data with Postman, problem is:
TypeError: Object of type 'Response' is not JSON serializable
Can you help me?
Model:
from marshmallow import Schema, fields, validate
class Person(object):
def __init__(self,tcno=None,firstname=None,lastname=None,email=None,birthday=None,country=None,gender=None):
self.__tcno = tcno
self.__firstname = firstname
self.__lastname = lastname
self.__email = email
self.__birthday = birthday
self.__country = country
self.__gender = gender
def __repr__(self):
return '<Person(firstname={self.__firstname!r})>'.format(self=self)
class PersonSchema(Schema):
tcno = fields.Str(required=True,validate=[validate.Length(min=11, max=11)])
firstname = fields.Str(required=True)
lastname = fields.Str(required=True)
email = fields.Email(required=True,validate=validate.Email(error="Not a valid email"))
birthday = fields.Date(required=True)
country = fields.Str()
gender = fields.Str()
View:
from flask import Response, json, request, jsonify, Flask
import requests
from flask_marshmallow import Marshmallow
from flask_restful import Api, Resource
from Person import Person, PersonSchema
app = Flask(__name__)
api = Api(app)
ma = Marshmallow(app)
class Apici(Resource):
def __init__(self):
pass
def get(self,people_id):
url = "http://localhost:9200/people/person/{}".format(people_id)
headers = {"Content-type": "application/json"}
r = requests.get(url=url, headers=headers)
json_data = json.loads(r.text)
if json_data['found'] is False:
mesaj = json.dumps({"found": "False"})
resp = Response(mesaj, status=201, mimetype='application/json')
return resp
return json_data["_source"]
def post(self,people_id):
json_input = request.get_json()
person_schema = PersonSchema()
person, errors = person_schema.load(json_input)
if errors:
return jsonify({'errors': errors}), 422
#result = person_schema(person)
url = "http://localhost:9200/people/person/{}".format(people_id)
headers = {"Content-type": "application/json"}
print(url)
r = requests.post(url=url, json=json_input, headers=headers)
print(r)
json_data = json.loads(r.text)
if json_data["result"] is "Updated":
message = json.loads({"result": "updated"})
resp = Response(message, status=201, mimetype='application/json')
return resp
message = json.loads({"result": "created"})
resp = Response(message, status=201, mimetype='application/json')
return resp #jsonify(result.data)
def put(self):
json_input = request.get_json()
person_schema = PersonSchema()
person, errors = person_schema.load(json_input)
if errors:
return jsonify({'errors': errors}), 422
result = person_schema(person)
url = "http://localhost:9200/people/person/{}".format(request.url[-1])
headers = {"Content-type": "application/json"}
r = requests.post(url=url, json=json_input, headers=headers)
json_data = json.loads(r.text)
if json_data["result"] is "Updated":
message = json.dumps({"result": "updated"})
resp = Response(message, status=201, mimetype='application/json')
return resp
message = json.dumps({"result": "created"})
resp = Response(message, status=201, mimetype='application/json')
return resp #jsonify(result.data)
def delete(self):
url = "http://localhost:9200/people/person/{}".format(request.url[-1])
headers = {"Content-type": "application/json"}
r = requests.delete(url=url,headers=headers)
json_data = json.loads(r.text)
if json_data["result"] == "not_found":
message = json.dumps({"result": "not_found"})
return Response(message, status=201, mimetype='application/json')
message = json.dumps({"result": "deleted"})
resp = Response(message, status=201, mimetype='application/json')
return resp
class ApiciList(Resource):
def __init__(self):
pass
def get(self):
url = "http://localhost:9200/people/person/_search"
body = {"query": {"match_all": {}}}
headers = {"Content-type": "application/json"}
r = requests.get(url=url, json=body, headers=headers)
json_data = json.loads(r.text)
return json_data["hits"]["hits"]
api.add_resource(ApiciList, '/person')
api.add_resource(Apici, '/person/<string:people_id>')
if __name__ == '__main__':
app.run(port=5010,debug=True)
Error:
127.0.0.1 - - [08/Jun/2017 11:37:18] "POST /person/1 HTTP/1.1" 500 -
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.6/dist-packages/flask_restful/__init__.py", line 271, in error_router
return original_handler(e)
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.6/dist-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.6/dist-packages/flask_restful/__init__.py", line 271, in error_router
return original_handler(e)
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.6/dist-packages/flask/_compat.py", line 32, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.6/dist-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python3.6/dist-packages/flask_restful/__init__.py", line 481, in wrapper
return self.make_response(data, code, headers=headers)
File "/usr/local/lib/python3.6/dist-packages/flask_restful/__init__.py", line 510, in make_response
resp = self.representations[mediatype](data, *args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/flask_restful/representations/json.py", line 20, in output_json
dumped = dumps(data, **settings) + "\n"
File "/usr/lib/python3.6/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/usr/lib/python3.6/json/encoder.py", line 201, in encode
chunks = list(chunks)
File "/usr/lib/python3.6/json/encoder.py", line 437, in _iterencode
o = _default(o)
File "/usr/lib/python3.6/json/encoder.py", line 180, in default
o.__class__.__name__)
TypeError: Object of type 'Response' is not JSON serializable
EDIT:
I found problem. It was in def post(self,people_id) method:
if errors:
return jsonify({'errors': errors}), 422
new line:
if errors:
message = json.dumps({'errors': errors})
return Response(message, status=422, mimetype='application/json')
Inspired from this bug, here is a shorter way of doing it:
from flask import jsonify, make_response
def myMethod():
....
return make_response(jsonify(data), 200)
This can be simply done by:
from flask import jsonify
def myMethod():
....
response = jsonify(data)
response.status_code = 200 # or 400 or whatever
return response
I had a similar problem, the problem is that i was using jsonify twice (jsonify(jsonify({abc:123})))
def post(self):
some_json=request.get_json()
return jsonify({'you sent ':some_json})
enough to solve this issue
For this we can try
response=response.json()
response=json.dumps(response)
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')]