7

I am learning FastAPI and I have this example.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

I saved the script as main.ipynb

The tutorial says to run this line of code in the command line: uvicorn main:app --reload

I am getting this error:

(venv) PS C:\Users\xxx\Desktop\Python Yamed\SaadAPI> uvicorn main:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [21304] using WatchFiles
ERROR:    Error loadinimport module "main".INFO:     Stopping reloader process [21304]

The reason is because I am using .ipynb as opposed to .py.

How can i fix this error while using .ipynb.

Thanks so much

Chris
  • 18,724
  • 6
  • 46
  • 80
bravopapa
  • 309
  • 1
  • 10
  • Does this answer your question? [How to run FastAPI / Uvicorn in Google Colab?](https://stackoverflow.com/questions/63833593/how-to-run-fastapi-uvicorn-in-google-colab) – Gino Mempin Oct 23 '22 at 10:01

1 Answers1

10

If you attempted to start the server as usual inside Jupyter, for example:

import uvicorn

if __name__ == "__main__":
    uvicorn.run(app)

you would get the following error:

RuntimeError: asyncio.run() cannot be called from a running event loop

This is due to Jupyter already running an event loop, and once Uvicorn calls asyncio.run() internally, the above error is raised.

As per asyncio.run() documentation:

This function cannot be called when another asyncio event loop is running in the same thread (see relevant asyncio implementation, where the error is raised).

[...]

This function always creates a new event loop and closes it at the end. It should be used as a main entry point for asyncio programs, and should ideally only be called once.

Solution 1

If you wouldd like to run uvicorn from an already running async environment, use uvicorn.Server.serve() instead (you could add the below to a new code cell in your Jupyter notebook, and then run it):

import asyncio
import uvicorn

if __name__ == "__main__":
    config = uvicorn.Config(app)
    server = uvicorn.Server(config)
    await server.serve()

or, get the current (running) event loop, using asyncio.get_running_loop(), and then call loop.create_task() for creating a task to run inside the event loop for the current thread:

import asyncio
import uvicorn

if __name__ == "__main__":
    config = uvicorn.Config(app)
    server = uvicorn.Server(config)
    loop = asyncio.get_running_loop()
    loop.create_task(server.serve())

Solution 2

Alternatively, you can use nest_asyncio, which allows nested use of asyncio.run() and loop.run_until_complete():

import nest_asyncio
import uvicorn

if __name__ == "__main__":
    nest_asyncio.apply()
    uvicorn.run(app)
Chris
  • 18,724
  • 6
  • 46
  • 80
  • Thanks a lot. The code is taking a while to run. is it normal? What does the code do? – bravopapa Oct 14 '22 at 15:56
  • 1
    It should normally start the server right away. Try restarting the Jupyter kernel and see if it fixes it. I have also updated the answer above with more details and solutions on the issue. – Chris Oct 14 '22 at 17:43
  • Thanks it still taking a while ...very strange I have a 16 RAM of memory. Maybe I should just stick to .py – bravopapa Oct 14 '22 at 19:57
  • The URL is running fine now ...I get HTTP response 200 OK. – bravopapa Oct 14 '22 at 20:12