Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Dario
    @91DarioDev
    Adding a file watcher for certificates would be geat 🤩 I just deployed in production yesterday and used nginx as reverse proxy to handle this, but it was unnecessary
    Phil Jones
    @pgjones
    @augustozanellato I think Hypercorn needs to accept a signal to reload like Gunicorn does (HUP)
    luna
    @lun-4
    I'm trying out the new APIs for files cited in pgjones/quart#375 on my test suite, and even though I'm sending a file via make_test_body_with_headers (I get a non-empty body), await request.files returns an empty dict inside my webapp code. I think this is related with the multipart header value not containing the boundary?
    luna
    @lun-4
    Yeah, I patched it with the correct boundary and my tests now fail for a different reason (need to learn how to fetch the files now), making an MR now
    Phil Jones
    @pgjones
    :+1:
    Phil Jones
    @pgjones
    Merged the MR - thanks for testing
    luna
    @lun-4

    Was able to make the new API work somewhat (there's some missing refactors on my side to make full use of it), but I'm hitting a different kind of error.

    Are there any Quart rules regarding routes such as /a/b returning a HTTP 308 redirection to /a/b/? Maybe I'm missing something...

    luna
    @lun-4
    One of my blueprints has an url_prefix of /api/shorten, and one of the routes is just declared as @bp.route("", methods=["POST"]) since I want to just expose POST /api/shorten, but that gives a redirection to /api/shorten/...
    Phil Jones
    @pgjones
    luna
    @lun-4
    Oh! Thank you!
    Phil Jones
    @pgjones

    I've written about how to use postgres with Quart, specifying my preferred libraries (Databases & asyncpg) and how to convert types automatically,
    https://pgjones.dev/blog/quart-postgres-2021/

    Would be good to know if you think this is better as an extension

    Jorge Escobar
    @esfoobar

    Hi @pgjones I am stumped with the following. I'm trying to pass a cursor_id to a websocket view, like so:

    @home_app.websocket("/ws")
    @login_required
    async def ws():
        dbc = current_app.dbc
        cursor_id = int(request.args.get("cursor_id"))

    But when I try to read the argument I get the error: "Attempt to access request outside of a relevant context". How can I pass that value from the template to the websocket endpoint?

    Phil Jones
    @pgjones
    If you switch request to websocket it should work (given this runs in a websocket context).
    You can also do,
    cursor_id = websocket.args.get("cursor_id", type=int)
    luna
    @lun-4
    Is there something planned to account for FileStorage.stream not being an asyncio object, or would we be locked waiting for the (currently) 16KB chunks of data on every iteration? I think those would probably be fine considering the kernel can cache possible future file reads, but I'm not sure.
    Phil Jones
    @pgjones
    It is something I've been wondering as well (along with the intermediate stream when parsing the form request body). I'm not sure what is best - do you have a suggestion?
    luna
    @lun-4
    I was thinking that an async for file in request.files:-like API to fetch files (instead of await request.files) would enable us to provide async reading of them, but I don't know how possible that is, considering werkzeug
    Jorge Escobar
    @esfoobar

    If you switch request to websocket it should work (given this runs in a websocket context).
    You can also do,

    cursor_id = websocket.args.get("cursor_id", type=int)

    That worked @pgjones, thanks!

    Penguin Master
    @PenguinMaster0226
    Hello, @pgjones, I need some help with Quart's websockets.
    How do I recieve multiple websocket client connections?
    Penguin Master
    @PenguinMaster0226
    I tried using the broadcast function shown on the docs, but when I ran queue.put(), it didn't send.
    I'm not sure why though
    queue.get() also never worked
    Ernesto Ruge
    @the-infinity
    @PenguinMaster0226 usually this happens if something at your code blocks the loop. put would be a good candidat because it awaits the get, so usually put_nowait is the way to go.
    Penguin Master
    @PenguinMaster0226
    @the-infinity I tried that, and then I figured out the issue. I believe it's because the queues are empty. When I used queue.get_nowait, it raised an asyncio.QueueEmpty error. How do I add the websocket to the queue?
    Penguin Master
    @PenguinMaster0226

    This is the code on the docs

    connected_websockets = set()
    
    def collect_websocket(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            global connected_websockets
            queue = asyncio.Queue()
            connected_websockets.add(queue)
            try:
                return await func(queue, *args, **kwargs)
            finally:
                connected_websockets.remove(queue)
        return wrapper

    This creates an empty queue, and then adds it to the set, but the queue is completely empty.

    Phil Jones
    @pgjones
    @PenguinMaster0226 Could you provide a snippet that doesn't work - it is hard to say what is going on otherwise
    Penguin Master
    @PenguinMaster0226
    @pgjones the code I used was from the docs (https://pgjones.gitlab.io/quart/tutorials/websocket_tutorial.html#websocket-tutorial). Just to make sure I wasn't doing it wrong, I used the exact code, but it still didn't work. Like I said above, the queues are empty and I'm not sure how to fix that.
    Phil Jones
    @pgjones
    Ideally the queues are always empty, as this means the message passed through them has been broadcast. What is it that you are expecting to happen?
    Penguin Master
    @PenguinMaster0226
    @pgjones I'm trying to store multiple websocket connections so I can send to them later. Is this the wrong way to do it?
    Is there another way?
    Phil Jones
    @pgjones
    So the example stores a queue for each connection, allowing messages to be sent to that connection via the queue.
    I think this is the clearest way, and the len(connected_websockets) would indicate how many connected websockets you have
    Penguin Master
    @PenguinMaster0226
    OK, so I tried using await websocket.receive() instead of await queue.get(), but then when I try to use await queue.put_nowait, it says TypeError: object NoneType can't be used in 'await' expression. How should I fix this?
    Phil Jones
    @pgjones
    put_nowait is a synchronous function (no need to await it)
    Penguin Master
    @PenguinMaster0226
    @pgjones now it doesn't raise an error, but nothing happens. Will it send to the websockets as a normal message?
    Phil Jones
    @pgjones
    It is really hard for me to know without seeing your code
    tibs
    @7185
    Hello, is there a better way to use quart_auth with websockets? So far I'm doing:
     token = websocket.cookies['QUART_AUTH']
     serializer = _AuthSerializer('**changeme**', 'quart auth salt')
     user_id = serializer.loads(token)
    Basically I'm looking for a current_user in a websocket context
    Phil Jones
    @pgjones
    Not yet, see pgjones/quart-auth#9
    tibs
    @7185
    thank you!
    Penguin Master
    @PenguinMaster0226

    @pgjones sorry for the late reply, but here's my code:

    from quart import Quart, websocket
    from functools import wraps
    import asyncio
    
    app = Quart(__name__)
    
    connected_websockets = set()
    
    def collect_websocket(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            global connected_websockets
            queue = asyncio.Queue()
            connected_websockets.add(queue)
            print(connected_websockets)
            try:
                return await func(queue, *args, **kwargs)
            finally:
                connected_websockets.remove(queue)
        return wrapper
    
    
    async def broadcast(message):
        for queue in connected_websockets:
            queue.put_nowait("New connection")
    
    
    @app.websocket('/')
    @collect_websocket
    async def ws(queue):
        while True:
            data = await websocket.receive()
            print(data)
            await broadcast(data)
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8080)

    You can ignore the host="0.0.0.0", that's just there because it's on replit

    Phil Jones
    @pgjones
    In this code you receive data from the websocket connections and place "New connection" (ignoring the data) on a queue, but you never read the data from the queue. The connected_websockets set will contain a queue for each websocket connection though. What are you hoping will happen?
    Phil Jones
    @pgjones
    @7185 see pgjones/quart-auth@68b6786 - could you say if this solves your need?
    tibs
    @7185
    @pgjones yes, this is exactly what I wanted, thank you!
    povar81
    @povar81

    Hi, everyone.
    I've just started using quart for my tests, I'm using this simple code :

    def start_app():
        from keyboard import press
        import quart
        app = quart.Quart(__name__)
        @app.route("/api", methods=["POST"])
        async def json():
            return {"hello": "quart world"}
        app.run(host='myip',port=5000)
    start_app()

    and it's working fine, except that I always get these unwanted messages when it starts:

    • Serving Quart app 'main'
    • Environment: production
    • Please use an ASGI server (e.g. Hypercorn) directly in production
    • Debug mode: False
    • Running on http://myhost:5000 (CTRL + C to quit)
      [2021-04-05 18:19:07,784] Running on http://myhost:5000 (CTRL + C to quit).

    Can anyone please tell me how to disable them?
    I've tried

    logging.getLogger('werkzeug').setLevel(logging.CRITICAL)
    logging.getLogger('app.serving').setLevel(logging.CRITICAL)
    logging.getLogger('quart.serving').setLevel(logging.CRITICAL)
    
    logging.getLogger('app.serving').disabled = True
    logging.getLogger('quart.serving').disabled = True
    
    logging.getLogger('app.serving').propagate = False
    logging.getLogger('quart.serving').propagate = False

    nothing helps

    Phil Jones
    @pgjones
    Probably best for you to make use of the run_task method to fully control how quart runs
    povar81
    @povar81
    Thank you, I see there are some options for changing the look of the logging:
    config = HyperConfig()
    config.access_log_format = "%(h)s %(r)s %(s)s %(b)s %(D)s"
    config.accesslog = create_serving_logger()
    but how can I disable the logging entirely (temporarily)?
    Phil Jones
    @pgjones
    I think if you remove the accesslog line it will disable all loggers
    povar81
    @povar81

    thank you, it worked in combination with
    sys.stdout = open(os.devnull, 'w')
    sys.stderr = open(os.devnull, "w")

    but I actually wanted to start this function in background via this code:

    import multiprocess as mp
    proc = mp.Process(target=start_app, args=())
    proc.start()

    and that still doesn't work because besides those lines I'm also getting an empty line in console (the app waiting for the requests I guess).

    Is there a way to start/stop the quart app in background?