pallets / quart Goto Github PK
View Code? Open in Web Editor NEWAn async Python micro framework for building web applications.
Home Page: https://quart.palletsprojects.com
License: MIT License
An async Python micro framework for building web applications.
Home Page: https://quart.palletsprojects.com
License: MIT License
Hi I submitted a patch a while back that fixed problems with multi part form data for uploading files I needed to improve that patch to handle some different situations mostly the fact that sometimes the content length header is missing also sometimes Content-Length is a str not an int so to deal with these cases I have made the following patch which I use from my private pypi repo
diff --git a/quart/__about__.py b/quart/__about__.py
index ef72cc0..4ca39e7 100644
--- a/quart/__about__.py
+++ b/quart/__about__.py
@@ -1 +1 @@
-__version__ = '0.8.1'
+__version__ = '0.8.2'
diff --git a/quart/wrappers/request.py b/quart/wrappers/request.py
index 09eea94..4658097 100644
--- a/quart/wrappers/request.py
+++ b/quart/wrappers/request.py
@@ -220,10 +220,9 @@ class Request(BaseRequestWebsocket, JSONMixin):
for value in values:
self._form.add(key, value)
elif content_type == 'multipart/form-data':
- limit = self.headers['content-length']
field_storage = FieldStorage(
io.BytesIO(raw_data), headers=self.headers,
- environ={'REQUEST_METHOD': 'POST'}, limit=limit,
+ environ={'REQUEST_METHOD': 'POST'}, limit=len(raw_data),
)
for key in field_storage: # type: ignore
field_storage_key = field_storage[key]
diff --git a/setup.py b/setup.py
index bc81faf..f346097 100644
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@ INSTALL_REQUIRES = [
]
setup(
- name='Quart',
+ name='quart',
version=about['__version__'],
python_requires='>=3.7.0',
description="A Python ASGI web microframework with the same API as Flask",
The line
bytesmod(b"HTTP/1.1 %s %s\r\n", (status_bytes, response.reason))
returns a string like
b'HTTP/1.1 HTTPStatus.PARTIAL_CONTENT \r\n'
but should be
b'HTTP/1.1 206 \r\n'
Using
bytesmod(b"HTTP/1.1 %d %s\r\n", (response.status_code, response.reason))
returns the correct result allowing partial content to actually go across as a 206 vs 200.
Looking for some guidance or example on how to consume JWT token with Quart? is there a extension that works with quart?
I'm trying to change my flask project to a quart project.
The project uses Flask-Login. To begin simple, i'm trying to run the flask_ext example.
I'm doing this in my virtual env. (this already runs my to Quart converted project successfully without Flask-Login.
Running the flask_ext example gives this error:
Running commands:
set QUART_APP=flask_ext:app
quart run
import quart.flask_patch
File "c:\werk\modules uitproberen\quart\venv\lib\site-packages\quart\flask_patch\__init__.py", line 5, in <module>
patch_all()
File "c:\werk\modules uitproberen\quart\venv\lib\site-packages\quart\flask_patch\_patch.py", line 117, in patch_all
_patch_asyncio()
File "c:\werk\modules uitproberen\quart\venv\lib\site-packages\quart\flask_patch\_patch.py", line 26, in _patch_asyncio
if not isinstance(current_policy, target_policy):
TypeError: isinstance() arg 2 must be a type or tuple of types
Any ideas what could be wrong?
Kind regards,
Extra info:
Python version: 3.7.0
pip freeze:
aiofiles==0.4.0
asyncio==3.4.3
blinker==1.4
Click==7.0
Flask==1.0.2
Flask-Login==0.4.1
h11==0.8.1
h2==3.0.1
hpack==3.0.0
Hypercorn==0.4.3
hyperframe==5.1.0
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
multidict==4.5.2
numpy==1.15.4
pandas==0.23.4
passlib==1.7.1
python-dateutil==2.7.5
pytoml==0.1.20
pytz==2018.7
Quart==0.7.1
raven==6.10.0
six==1.12.0
sortedcontainers==2.1.0
typing-extensions==3.6.6
Werkzeug==0.14.1
wsproto==0.12.0
When I create a startup configuration and start the server with it, after changing the code, the server stops and does not start again.
Hi there,
I am trying to get started with Quart using a Docker container.
I created a simple Dockerfile called api.dockerfile
as follows:
FROM python:3.7-alpine
COPY requirements.txt /
RUN pip install -r /requirements.txt
COPY . /app
WORKDIR /app
EXPOSE 5000
Within my requirements.txt
I have a single entry called quart
.
I have a file called app.py
taken from the documentation's Getting Started section:
from quart import Quart
app = Quart(__name__)
@app.route('/')
async def hello():
return 'hello'
app.run()
I am running the Dockerfile
using docker-compose
. This is my docker-compose.yml
:
version: '3'
services:
api:
build:
context: .
dockerfile: api.dockerfile
image: my_docker_quart_compose:latest
volumes:
- .:/app
command: python app.py
ports:
- "5000:5000"
When I run docker-compose up
, the sequence gets stuck as follows (api-test
is my current directory):
Creating network "api-test_default" with the default driver
Creating api-test_api_1 ... done
Attaching to api-test_api_1
My machine is listening at port 5000, but I get an empty response from the server.
I've tried the following with no luck:
docker-compose
Quart works perfectly without problems locally.
I am not sure if I am missing something. Your input is much appreciated!
Hi,
I've written a simple shopping cart in session.
When i'm trying to remove items from the cart it goes wrong. With normal iteration through the dictionary, it doesn't delete all items when i ask it to.
Playing with it, i came to the solution below. It seems that the range of the cart items begins at a negative index.
Am i seeing this wrong ? Or am i doing something wrong? Or is it just a bug?
cart_items = session["cart"]
for index in range(-1*len(cart_items),0):
if remove_all:
session['cart'].remove(cart_items[index])
else:
if str(cart_items[index]) == identifier:
session['cart'].remove(cart_items[index])
break
cheers,
I got quart websocket example running on Python 3.6.4. Now I want to read data from a redis queue and send it to my webpage.
I also will receive data from the web page and call functions within a class or if easier, put it into an outgoing redis queue.
How can I best implement it in quart server?
I would very much appreciate your help in this matter
Please allow passing of array data to request.form.
As a quick fix i changed line 159 in wrappers/request.py to
self._form.add(key, value)
.
Cheers,
Omar
Specifically, the Map.iter_rules(endpoint)
method is missing. This is making frameworks that depend on it fail, in our case, sphinxcontrib.httpdomain.flask
.
Hi I have two asyncio consumer/producer queues that I need to clean up with an async function
I would like to be able to do this
@app.teardown_appcontext
async def teardown(response_or_exc):
try:
await vision_queue.stop()
await webhook_queue.stop()
while not vision_queue.stopped or not webhook_queue.stopped:
pass
except KeyboardInterrupt:
pass
so I have created a patch for quart
diff --git a/quart/__about__.py b/quart/__about__.py
index ef72cc0..4ca39e7 100644
--- a/quart/__about__.py
+++ b/quart/__about__.py
@@ -1 +1 @@
-__version__ = '0.8.1'
+__version__ = '0.8.2'
diff --git a/quart/app.py b/quart/app.py
index aeab04b..a067a61 100644
--- a/quart/app.py
+++ b/quart/app.py
@@ -1285,7 +1285,10 @@ class Quart(PackageStatic):
async def do_teardown_appcontext(self, exc: Optional[BaseException]) -> None:
"""Teardown the app (context), calling the teardown functions."""
for function in self.teardown_appcontext_funcs:
- function(exc)
+ if asyncio.iscoroutinefunction(function):
+ await function(exc)
+ else:
+ function(exc)
await appcontext_tearing_down.send(self, exc=exc)
def app_context(self) -> AppContext:
diff --git a/setup.py b/setup.py
index bc81faf..f346097 100644
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@ INSTALL_REQUIRES = [
]
setup(
- name='Quart',
+ name='quart',
version=about['__version__'],
python_requires='>=3.7.0',
description="A Python ASGI web microframework with the same API as Flask",
I tried quart in docker by alpine3.7 with python 3.6.5, and I added --with-ssl
when I install python.(seems no ssl in python3)
using the http2.py example, it's ok to run application:
/home/quart # python http2.py
Running on https://127.0.0.1:5000 (CTRL + C to quit)
but once I accessed it by curl, error occured:
$ curl --http2 -v "https://127.0.0.1:5000/"
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:5000
* Closing connection 0
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:5000
It seems that connection already setup, but it was closed by quart when client sent 'Client hello'.
Spending a lot of time, I still not fix it, so ask for a help :(
I don't understand why I'm still getting this error even after adding the proper context as per documentation
@app.route('/')
async def pdf():
asyncio.create_task(sendMail())
return 'Done'
async def sendMail():
async with app.app_context():
print('sending mail')
msg = Message(
'Message',
recipients=['[email protected]']
)
mail.send(msg)
Hi,
It may be a bit off topic, but i can't find an answer on the net... Sorry if this is a noob question.
Has anybody installed a certificate with certbot for a Quart/Hypercorn server?
I have a converted project from Flask to Quart. In Flask i used an Apache2 webserver. Installing the certificate was very easy.
I made a new server and i'm trying certbot with webroot right now. This is giving me an error.
sudo certbot certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.logHow would you like to authenticate with the ACME CA?
1: Apache Web Server plugin - Beta (apache)
2: Spin up a temporary webserver (standalone)
3: Place files in webroot directory (webroot)
Select the appropriate number [1-3] then [enter] (press 'c' to cancel): c
Could not choose appropriate plugin: authenticator could not be determined or is not installed
authenticator could not be determined or is not installed
ubuntu@ip-172-xx-31-4:$ sudo -s# sudo certbot certonly
root@ip-172-31-xx-4:
Saving debug log to /var/log/letsencrypt/letsencrypt.logHow would you like to authenticate with the ACME CA?
1: Apache Web Server plugin - Beta (apache)
2: Spin up a temporary webserver (standalone)
3: Place files in webroot directory (webroot)
Select the appropriate number [1-3] then [enter] (press 'c' to cancel): 3
Plugins selected: Authenticator webroot, Installer None
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): makemesmile.nl
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for xxxx.nl
Input the webroot for xxxxx.nl: (Enter 'c' to cancel): /var/www/
Waiting for verification...
Cleaning up challenges
Failed authorization procedure. makemesmile.nl (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from
Do i need to do something with a route for '/.well-known/'? Or is it something completely different?
I've got the echo websocket tutorial working fine with a javascript client, but I'm lost as to how to go forward
(Other than learning Twisted I'm pretty new to python web libraries and async programming, so I wouldn't be surprised if this is just a lack of knowledge on my part rather than lack of Quart documentation)
I want my browser client to provide some parameters to the server initially, to identify what types of data that client is subscribing to, and trigger the Quart application to begin fetching and caching that data from another server (paginated REST API). As that data becomes cached locally I want to forward it via the websocket to the client... and really to any other websocket clients subscribed for the same kind of data.
Any guidance via examples or references to learning materials would be appreciated!
Can we use the following extensions (Flask-OIDC and Flask-pyoidc) with quart? I want to use oidc provider for authentication and want to know if this extensions are supported with patching.
Hi,
I'm trying to generate an excel file in memory and then make it available to download in the browser.
I looked up how to do that in flask and came to the following code:
output = io.BytesIO()
writer = pd.ExcelWriter(output, engine='xlsxwriter')
s = pd.DataFrame(statistics.get_all_values_for_download(survey_id))
s.to_excel(writer, sheet_name='Sheet1')
writer.save()
output.seek(0)
survey = Survey.get(survey_id)
filename = survey.description + '-' + survey.title + datetime.datetime.now().strftime("%d-%b %H:%M")
return await send_file(output, attachment_filename='{}.xlsx'.format(filename), as_attachment=True)
This is giving the error:
TypeError expected str, bytes or os.PathLike object, not _io.BytesIO
Reducing it to a simpler form: save the file to disk and serving it (and maybe removing it with a cronjob) seems to work, but the filename isn't ok.
` filename = survey.description + '-' + survey.title +'.xlsx'
writer = pd.ExcelWriter('./static/xlsfiles/'+filename, engine='xlsxwriter')
all_votes = await statistics.get_all_values_for_download(survey_id)
s = pd.DataFrame(all_votes)
s.to_excel(writer, sheet_name='Sheet1')
writer.save()
return await send_from_directory('./static/xlsfiles/', file_name=filename)`
The result of this is almost ok, it gives a file named 'overview'. This is also the url of the page.
It should be 'description-title.xlsx', that is also the value of filename when i print it....
Trying
return await send_from_directory('./static/xlsfiles/', file_name=filename, attachment_filename=filename)
Gives an error that attachment_filename is unexpected....
Long story short:
Your help would be greatly appreciated again...
kind regards
In this exemple :
@app.websocket('/ws')
async def ws():
await websocket.accept(subprotocol="xxx")
while True:
data = await websocket.receive()
await websocket.send('hello')
When accepting websocket request, we must know the list of sub-protocols queried by the client in the header Sec-WebSocket-Protocol: xxx, yyy
Your code store this header in subprotocols variable, but not provided...
How get this list ?
$ QUART_APP=http2_push quart run
Running on https://127.0.0.1:5000 (CTRL + C to quit)
/tmp/quart-original/quart/asgi.py:76: RuntimeWarning: coroutine 'ASGIHTTPConnection._send_push_promise' was never awaited
self._send_push_promise(send, path)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
[2019-02-07 16:32:43,650] 127.0.0.1:60478 GET /push 2 200 4878 14579
Hi.
You're importing typing.AsyncGenerator here, and the docs claim python 3.6 compatibility, but AsyncGenerator doesn't seem to be included in Python 3.6.0.
I failed to find the changelogs, but I tested with Python images available in Dockerhub, and AsyncGenerator doesn't appear until 3.6.1.
I wonder if this is worth pointing out somewhere in the docs.
This is a relevant issue from the python/typing project.
Keep it up!
I want to create an asycio task in Blueprint, and add_done_callback for it, which is used to delay the task execution in another event loop without hanging the current work. But I can't get current_app in callbacks.
Is it designed for not run task like this on purpose?
Here is my code.
@app.route('/someurl, methods=['POST'])
@admin_required(const.Role_Admin)
def create_something_in_db():
# do something
task = asyncio.ensure_future(current_app.some_obj.really_time_consuming_task(args))
task.add_done_callback(functools.partial(current_app.db_operator.save_result, arg))
It always crash on current_app.db_operator.save_result
execution.
Hi,
I would like to report a vulnerability in quart HTTP Server when serving HTTP/2 clients.
In section 10.5 of the HTTP/2 RFC an attack is described where an attacker is sending large SETTINGS frames that includes many settings inside it.
We tested this scenario by opening many connections to the quart server and sending a SETTINGS frame with payload size of 14400 bytes and we were able to cause quart to consume all the machines memory and overload one CPU core with 100% usage by attacking from a single machine.
It is also important to note that quart never closes the connection so the attacker can keep sending those malformed SETTINGS frames, and when under the attack described above, quart responds after a long period to new legitimate requests:
You can find the script that we used for attacking it and the script that was used to start the server instance in the following link: https://galgoldshtein.co.il/HTTP2/62c31461558c9be64089145736d0d5bf/HTTP2%20Settings%20Frame%20DoS.zip
Thanks.
So i running Quart with gunicorn, but i facing this problem:
I thinking that workers will not solve my problem described above that sometimes the tasks freezing leaving without any response. So i think maybe if i start using Redis to manage this tasks will be more useful since i have scalability in mind. Is there any alternative to gunicorn? I configurating my app wrong?
I have 2 cpus cores:
gunicorn --worker-class quart.worker.GunicornWorker -w 2 server:app -b 0.0.0.0:8080 -t 600
Hi,
I'm using quart in our application and it works successfully. But if i run the quart application on docker , it returns the following error. I could not find anything about the error. How can i fix this error ?
seffaflik_1 | Traceback (most recent call last):
seffaflik_1 | File "run.py", line 2, in <module>
seffaflik_1 | from app import create_app
seffaflik_1 | File "/code/app/__init__.py", line 2, in <module>
seffaflik_1 | from .app import create_app
seffaflik_1 | File "/code/app/app.py", line 7, in <module>
seffaflik_1 | from quart import Quart,flask_patch
seffaflik_1 | File "/usr/local/lib/python3.6/site-packages/quart/flask_patch/__init__.py", line 5, in <module>
seffaflik_1 | patch_all()
seffaflik_1 | File "/usr/local/lib/python3.6/site-packages/quart/flask_patch/_patch.py", line 83, in patch_all
seffaflik_1 | _patch_modules()
seffaflik_1 | File "/usr/local/lib/python3.6/site-packages/quart/flask_patch/_patch.py", line 64, in _patch_modules
seffaflik_1 | for name, module in sys.modules.items():
seffaflik_1 | RuntimeError: dictionary changed size during iteration
seffaflik_seffaflik_1 exited with code 1
and code blocks :
from quart import Quart,flask_patch
from quart import (
Blueprint,
session,
request,
render_template,
jsonify
)
def create_app(config=None, app_name=None, blueprints=None):
if app_name is None:
app_name = Config.Config.PROJECT
if blueprints is None:
blueprints = DEFAULT_BLUEPRINTS
app = Quart(app_name)
configure_app(app, config)
configure_hook(app)
configure_logging(app)
configure_blueprints(app, blueprints)
configure_extensions(app)
configure_error_handlers(app)
configure_filters(app)
return app
Hello, @pgjones, it's me again.
Today's question is roadmap to major version of Quart 1.x.x
. Could you please give to community some plan or wishes. What does Quart framework want now and what do you want to implement in the future?
Thanks.
I see that there are profiler packages that can give performance metrics on views as they are used during the runtime of the app. I wanted to use such a tool to identify bottlenecks in the views. Is there something that works with Quart apps?
I am trying to create catch-all-url route similar to flask, but the route is not working in quart.
Flask:
from flask import Flask, request
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def index(path):
return 'Hello World'
Quart:
from quart import Quart, request
app = Quart(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
async def index(path):
return 'Hello World'
What is the best way to create catch all route in quart?
At line https://github.com/pgjones/quart/blob/master/quart/wrappers/request.py#L223
there is no way cgi.FieldStorage could possibly correctly parse multipart/form-data files upload without setting the limit to the content-length so the code should be
content_length = self.headers['content-length']
field_storage = FieldStorage(
io.BytesIO(raw_data), headers=self.headers,
environ={'REQUEST_METHOD': 'POST'}, limit=content_length
)
also at
https://github.com/pgjones/quart/blob/master/quart/wrappers/request.py#L240
sometimes the key is None and this code blows up because multidict only accepts str as key not None
so code should be
elif key:
self._form.add(key, field_storage_key.value)
With these two changes I get my unit test to pass which I have shown below
from http import HTTPStatus
from copy import deepcopy
from datetime import datetime
from io import BytesIO
from PIL import Image
from werkzeug.test import encode_multipart
from werkzeug.datastructures import FileMultiDict
import pytest
from models import Documents
def create_test_image(name):
buffered = BytesIO()
image = Image.new('RGBA', size=(50, 50), color=(155, 0, 0))
image.save(buffered, 'png')
file = BytesIO(buffered.getvalue())
file.name = name
file.seek(0)
return file
image_file = create_test_image('filename.png')
fmd = FileMultiDict()
fmd.add_file('file', image_file, filename='filename.png', content_type='image/png')
boundary = 'Test'
_, data = encode_multipart(fmd, boundary=boundary)
headers = {
'Link': 'https://www.notawebhook.com',
'Eai-Callback-Token': 'notAtoken',
'Content-Type': 'multipart/form-data; boundary={}'.format(boundary),
'Content-Length': len(data)
}
auth = 'Bearer {}'
@pytest.mark.asyncio
async def test_token_works(client, db, token):
auth_headers = deepcopy(headers)
auth_headers['Authorization'] = auth.format(token)
# print('data: {}'.format(data))
response = await client.post('/v0.0.1/files',
data=data, headers=auth_headers)
body = await response.json
print(body)
assert response.status_code == HTTPStatus.CREATED
task_id = body['taskId']
docs = Documents.query.filter_by(task_id=task_id).all()
assert len(docs) == 1
doc = docs[0]
assert doc.page == 1
assert doc.task_id == task_id
assert type(doc.time_stamp) is datetime
image_file.seek(0)
assert doc.data == image_file.read()
It is great to see a typed package, it sadly is still a rarity. Trying quart out for the first time and having mypy running in my vim and via a Makefile, I was surprised about it not wanting to use the quart's typing information.
According to the mypy documentation it only does that when there is a py.typed
file in the installed package. And sure enough, after creating that file (with touch "$VIRTUAL_ENV/lib/python3.7/site-packages/quart/py.typed"
) it works like a charm.
I don't really know if there is another way to achieve this, but I think adding this file to the distribution would be the easiest way to just make it work out of the box.
I was trying to verify the http2_push example by using nghttp. The example does seem to work fine from a browser (Chrome or Firefox).
Repro:
$ QUART_APP=http2_push:app quart run
Running on https://127.0.0.1:5000 (CTRL + C to quit)
[2018-12-19 14:44:13,507] ASGI Framework Lifespan error, continuing without Lifespan support$ nghttp -nvy https://localhost:5000/push
is it possible to have something like Flask-socket-io in quart? Would make migration to quart easier.
Hello.
I use Flask a lot, and Quart looks like good alternative, but I came across a little problem.
With Flask I used to do this:
`
from flask import Flask
from werkzeug.contrib.fixers import ProxyFix
app = Flask(name)
app.wsgi_app = ProxyFix(app.wsgi_app)
`
This was easy way to get "real" client address behind proxy. But i can't find a way to do something similar in Quart. Is there / Will there be any solution? Thnaks...
if __name__ == "__main__":
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_COMPRESSION
ssl_context.set_ciphers('ECDHE+AESGCM')
ssl_context.load_cert_chain(certfile='xxx.crt', keyfile='xxx.key')
ssl_context.set_alpn_protocols(['h2', 'http/1.1'])
app.run(host='0.0.0.0', port=443, ssl=ssl_context)
when i use the http2 and ssl my server is very slow and many 404 err response.
and.. when i upload img files i can only upload small than 20kb..
why this issue bring me?
maybe i think
await request.files <- this line is blocking all request.
my upload source
@app.route('/api/Cms/Shop/Content/Img', methods=['POST'], subdomain="cms")
async def CmsShopContentImg():
if 'UserGrade' in session:
Data = await request.files
if 'file' not in Data:
return '', 400
elif Data['file'].filename == '':
return '', 400
elif Data['file']:
filename = sha256(str(datetime.now()).encode('utf-8')).hexdigest() + '.png'
Data['file'].save(os.path.join(app.config['EDITOR_UPLOAD_FOLDER'], filename))
returnUrl = { 'url': 'https://xxx.com/shop/content/' + filename}
return dumps(returnUrl)
else:
return '', 401
Hi, @pgjones
I want to start this disqus because it's important to promotion and visual identity. Good Python framework need good visual stuff! So, I have some ideas about official Quart
logo and give you them for free :) Look please.
Font: Amarillo (this's a paid font, but I already bought it)
Color: RGB 214, 11, 82 (HEX #d60b52)
Font: Lifehack Basic (this's a paid font, but I already bought it) + Open Sans (or similar)
Color: RGB 45, 46, 131 (HEX #2d2e83) + similar dark color, like #333333
currently I am running a flask web server on the same raspi3 where I also read a lot of sensors (IOT) which are send to the web page. Now I want to split data collection and Webserver to run on two or more Raspis. The data collection Raspis should send data via websocket to the webserver and receive input from the webserver initiated on the webpage. Will quart be able to handle these additonal websockets within the webserver app and how would this be coded? I apprecaite very much your support and suggestions in this matter.
Please fix the formatting of the Readme file for
Hi, currently I'm migrating a small service from flask to quart and Im facing an issue related to request
from quart import request
It seems like request from quart doesn't have request.user_agent.platform nor request.user_agent.browser, however request from flask have them.
Are there any plan to add this? or there is any workaround ?
Hi, I started getting the following stack trace in the latest quart version:
[2018-11-12 09:33:04,391] ASGI Framework Lifespan error, continuing without Lifespan support
Traceback (most recent call last):
File "/home/nurettin/.local/share/virtualenvs/pylongrun-fEmL5R2s/lib/python3.6/site-packages/hypercorn/asyncio/lifespan.py", line 24, in handle_lifespan
asgi_instance = self.app(scope)
File "/home/nurettin/.local/share/virtualenvs/pylongrun-fEmL5R2s/lib/python3.6/site-packages/quart/app.py", line 1689, in call
raise RuntimeError('ASGI Scope type is unknown')
RuntimeError: ASGI Scope type is unknown
12-Nov-18 09:33:04: quart.serving ERROR: ASGI Framework Lifespan error, continuing without Lifespan support
Traceback (most recent call last):
File "/home/nurettin/.local/share/virtualenvs/pylongrun-fEmL5R2s/lib/python3.6/site-packages/hypercorn/asyncio/lifespan.py", line 24, in handle_lifespan
asgi_instance = self.app(scope)
File "/home/nurettin/.local/share/virtualenvs/pylongrun-fEmL5R2s/lib/python3.6/site-packages/quart/app.py", line 1689, in call
raise RuntimeError('ASGI Scope type is unknown')
RuntimeError: ASGI Scope type is unknown
These warning messages appear when starting a mp in forkserver.
I'm using python3.7 on a RaspBerryPi 3B running Debian Stretch.
/home/pi/.local/lib/python3.7/site-packages/jinja2/utils.py:485: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import MutableMapping
/home/pi/.local/lib/python3.7/site-packages/markupsafe/init.py:13: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import Mapping
/home/pi/.local/lib/python3.7/site-packages/jinja2/utils.py:485: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import MutableMapping
/home/pi/.local/lib/python3.7/site-packages/markupsafe/init.py:13: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import Mapping
/home/pi/.local/lib/python3.7/site-packages/jinja2/utils.py:485: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import MutableMapping
/home/pi/.local/lib/python3.7/site-packages/markupsafe/init.py:13: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
from collections import Mapping
/home/pi/.local/lib/python3.7/site-packages/hyperframe/flags.py:14: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
class Flags(collections.MutableSet):
/home/pi/.local/lib/python3.7/site-packages/hyperframe/flags.py:14: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
class Flags(collections.MutableSet):
/home/pi/.local/lib/python3.7/site-packages/hyperframe/flags.py:14: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
I built a Quart web server to serve some dynamic KML content. GoogleEarth supports two formats; KML and KMZ. I want to support returning a response in either of the supported formats.
My code looks something like this:
kml_mimetype = 'application/vnd.google-earth.kml+xml'
kmz_mimetype = 'application/vnd.google-earth.kmz'
SUPPORTED_MIMETYPES = (kmz_mimetype, kml_mimetype)
@app.route('kml_update', method=['GET'])
async def handle_kml_update():
''' Handle a request to the /kml_update route. '''
try:
mimetype = request.accept_mimetypes.best_match(
SUPPORTED_MIMETYPES, default=kml_mimetype)
except Exception:
logger.exception('Error generating KML')
When GoogleEarth attempts to fetch data from the Quart web server's /kml_update
route (which it is instructed to do via a KML file containing a NetworkLink tag) I observe an error in my handler function which is generated from Quart when it is processing the Accept headers.
Error generating KML
Traceback (most recent call last):
File "server.py", line 174, in handle_kml_update
mimetype = request.accept_mimetypes.best_match(
File "/Users/claws/.venvs/myenv/lib/python3.6/site-packages/quart/local.py", line 108, in __getattr__
return getattr(self._get_current_object(), name)
File "/Users/claws/.venvs/myenv/lib/python3.6/site-packages/quart/wrappers.py", line 291, in accept_mimetypes
return MIMEAccept(self.headers.get('Accept', ''))
File "/Users/claws/.venvs/myenv/lib/python3.6/site-packages/quart/datastructures.py", line 144, in __init__
quality = float(raw_quality.split('=', 1)[-1])
ValueError: could not convert string to float: 'context.kml'
The ACCEPT headers in the request that triggered the error were:
'Accept': 'application/vnd.google-earth.kml+xml;googleearth=context.kml,application/vnd.google-earth.kmz;googleearth=context.kmz'
The main culprit seems to be the ;googleearth=context.kml
inapplication/vnd.google-earth.kml+xml;googleearth=context.kml
and the googleearth=context.kmz
in application/vnd.google-earth.kmz;googleearth=context.kmz
.
Quart is only expecting a string of the form q=0.9
in scenarios where a ;
is found in an ACCEPT item.
I am not familiar with http ACCEPT specification. Perhaps Quart is correct in its processing of the accept headers against the specification and GoogleEarth is supplying malformed ACCEPT items. If this is the case then this issue can be closed. If not, then it would be nice if the Accept headers got returned without triggering an exception.
The function on_json_loading_failed
contains the line: from .exceptions import BadRequest
here. This needs to be changed to from ..exceptions import BadRequest
or from quart.exceptions import BadRequest
.
I'll make a PR.
cd examples/http2_push
#edit / route to accept POST
#@app.route('/', methods=['POST'])
QUART_APP=http2_push quart run
Now create a payload file:
dd if=/dev/urandom of=payload count=10000
Do POST to /:
curl -d @payload -vsk https://127.0.0.1:5000/
Server console shows this error and then connection hangs:
application protocol failed to receive SSL data
protocol: <asyncio.sslproto.SSLProtocol object at 0x7f1358bdeac8>
transport: <_SelectorSocketTransport fd=8 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "lib/python3.7/asyncio/sslproto.py", line 541, in data_received
self._app_protocol.data_received(chunk)
File "xyz/hypercorn/hypercorn/asyncio/run.py", line 59, in data_received
self._server.data_received(data)
File "xyz/hypercorn/hypercorn/asyncio/h2.py", line 100, in data_received
self.handle_events(events)
File "xyz/hypercorn/hypercorn/asyncio/h2.py", line 126, in handle_events
self.streams[event.stream_id].append(event.data)
KeyError: 1
On of the things that makes flask really powerful is the availability of extensions. Do you plan on supporting any? Or maybe have a guide for port existing flask ones to quart?
Hi!
I've been trying to use aiomysql with Quart. Opening a new connection for each request works fine, but isn't quite resource efficient. So I've decided to use a pool.
To create / destroy the pool correctly, I need access to the loop. I can use the signal before_first_request
to create the pool. However, I can't seem to find a way of running a method before the loop is closed.
So, I sub-classed the custom worker:
class CustomWorker(GunicornUVLoopWorker):
def run(self) -> None:
create_server = asyncio.ensure_future(self._run(), loop=self.loop)
try:
self.loop.run_until_complete(create_server)
self.loop.run_until_complete(self._check_alive())
finally:
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
self.loop.run_until_complete(self._cleanup())
self.loop.close()
async def _cleanup(self):
if not hasattr(app, 'pool'):
return
pool.close()
await pool.wait_closed()
del app.pool
I was wondering if there was a cleaner way to do this. Especially because now, I can't run the built in server, and have to add a special configuration to pytest
to make it run:
@pytest.yield_fixture(autouse=True)
async def run_around_tests():
# Before each test
yield
# After each test
Thanks!
Install
$ python -m venv venv
$ source venv/bin/activate
$ pip install quart
Edit app file
from quart import Quart
app = Quart(__name__)
@app.route('/')
async def hello():
return 'hello'
if __name__ == '__main__':
app.run()
Run
$ python app.py
Error
ImportError: cannot import name 'AsyncGenerator'
Python and PIP version
$ python -V
Python 3.6.0
$ pip -V
pip 10.0.1
Hi, I'm successfully using Quart's websocket, and I'm now wondering why websocket.receive()
returns str
is there a way to get bytes
instead? I'm working with a binary protocol, so it would be nice to have raw data access and it sounds weird to encode the input.
I tried both handlers:
@app.errorhandler(404)
def page_not_found(e):
return render_template('/error_handlers/404.html'), 404
and
def not_found():
return render_template('/error_handlers/404.html'), 404
app.register_error_handler(404, not_found)
None of these seem to work on Quart. I tried the same code on Flask, which seems to work. You can test this simple code here:
from quart import Quart
app = Quart(__name__)
@app.errorhandler(404)
def page_not_found(e):
return 'Not found lalala', 404
if __name__ == '__main__':
app.run()
from flask import Flask
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e):
return 'Not found lalala', 404
if __name__ == '__main__':
app.run()
$> python test.py
What am I doing wrong?
Thanks.
As documented here flask provides automatic reloading on code change when the debug mode is enabled.
This doesn't seem to be the case for quart (I tried the QUART_DEBUG
(cf here) environment variable, as well as manually setting the app config).
It is a really helpful feature during development and it would be great if quart could offer it too.
Hi, my name is Elielton Kremer and I use your project in my academic work.
I created a generic CDI based on the Symfony context manager for my work and would like to share
Hi, Im using current_app._get_current_object()
to pass the app object into a thread and execute app.app_context()
however im facing a run time error regarding: AttributeError: __enter__
, after some more investigation adding import quart.flask_patch
to the top of my main module didn't work for me nor defining my own Thread class with current_app
object attached to it.
class FlaskThread(Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.app = current_app._get_current_object()
def run(self):
with self.app.app_context():
super().run()
^ this didn't work for me
My code looks like this:
from threading import Thread
from quart import current_app
from flask_mail import Message
from app import mail
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body, attachments=None, sync=False):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
if attachments:
for attachment in attachments:
msg.attach(*attachment)
if sync:
mail.send(msg)
else:
Thread(
target=send_async_email,
args=(current_app._get_current_object(), msg),
).start()
The issue, as I understand, is happening once the execution reached with app.app_context():
after that line, the enter method for app will be called but it seems like that method is not implemented in from quart import current_app
Stacktrace:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/Users/leninarias/go/src/app.theia/account-recovery/venv/lib/python3.7/site-packages/sentry_sdk/integrations/threading.py", line 47, in run
reraise(*_capture_exception())
File "/Users/leninarias/go/src/app.theia/account-recovery/venv/lib/python3.7/site-packages/sentry_sdk/_compat.py", line 52, in reraise
raise value
File "/Users/leninarias/go/src/app.theia/account-recovery/venv/lib/python3.7/site-packages/sentry_sdk/integrations/threading.py", line 45, in run
return old_run(*a, **kw)
File "/usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/Users/leninarias/go/src/app.theia/account-recovery/app/email.py", line 7, in send_async_email
with app.app_context():
AttributeError: __enter__
I'll continue investigating the issue but I feel like this is an internal issue with Quart (if isn't pardon me, Im still a newbie on python)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.