miguelgrinberg/microdot

render_template hangs when using microdot_asyncio

Odud opened this issue · 5 comments

Odud commented

Describe the bug
render_template hangs when using microdot_asyncio but works fine with microdot. If I remove the render template call and just return some text then this works fine as expected.

To Reproduce

from microdot_asyncio import Microdot, Response
from microdot_utemplate import render_template

app = Microdot()
Response.default_content_type = 'text/html'

@app.route('/')
def index(req):
    return render_template(
        "test.html",
        Test="This Test",
    )

app.run(debug=True)

Expected behavior
Browser should return the web page, but instead it hangs, there is no debug output from the server other than Starting async server on 0.0.0.0:5000...

Additional context
MicroPython v1.20.0 on 2023-04-26; Raspberry Pi Pico W with RP2040

If I replace from microdot_asyncio... by from microdot... then everything works fine, the template displays in the browser and I see debug output Starting sync server on 0.0.0.0:5000... GET / 200. The template is as follows:

{% args Test %}
 <!DOCTYPE html>
 <html>
 <head>
 </head>
 <body>
 <p>{{ Test }} </p>
 </body>
 </html>
Odud commented

BTW I'm relatively new to asyncio but have used microdot successfully before

Odud commented

Apologies, it isn't render_template that is hanging it is the return of the template. I put some print statements around the render_template and it is working fine. I needed to make the function after the @route an async.

@app.route('/')
async def index(req):

I don't really uderstand why, but suspect this is my lack of understanding of async. Happy to close if my thought is correct

@Odud: Ah, okay, I do see what the problem is now. In MicroPython async functions are really generators. The render_template() function returns a generator as well. Microdot is confused because a non-async function is returning something that looks like what an async function would return. I need to find a way to distinguish the return value of calling an async function from a generator returned by a non-async function, which actually look the same.

In the meantime your solution is fine, just make sure any functions that use render_template() are defined as async functions. I'll investigate to see if I can figure out how to make non-async functions work as well.

Odud commented

Microdot 2 has been redesigned to work asynchronously, and the template extensions can also be used asynchronously, which should address this problem.