Home > Net >  How to run Uvicorn FastAPI server as a module from another Python file?
How to run Uvicorn FastAPI server as a module from another Python file?

Time:09-30

I want to run FastAPI server using Uvicorn from A different Python file.

uvicornmodule/main.py

import uvicorn
import webbrowser
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI()

import os
script_dir = os.path.dirname(__file__)
st_abs_file_path = os.path.join(script_dir, "static/")
app.mount("/static", StaticFiles(directory=st_abs_file_path), name="static")

@app.get("/")
async def index():
    return FileResponse('static/index.html', media_type='text/html')

def start_server():
    # print('Starting Server...')       

    uvicorn.run(
        "app",
        host="0.0.0.0",
        port=8765,
        log_level="debug",
        reload=True,
    )
    # webbrowser.open("http://127.0.0.1:8765")

if __name__ == "__main__":
    start_server()

So, I want to run the FastAPI server from the below test.py file:

from uvicornmodule import main
main.start_server()

Then, I run python test.py.

But I am getting the below error:

RuntimeError:
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

What I am doing wrong? I need to run this module as package.

CodePudding user response:

When spawning new processes from the main process (as this is what happens when uvicorn.run() is called), it is important to protect the entry point to avoid recursive spawning of subprocesses, etc. As described in this article:

If the entry point was not protected with an if-statement idiom checking for the top-level environment, then the script would execute again directly, rather than run a new child process as expected.

Protecting the entry point ensures that the program is only started once, that the tasks of the main process are only executed by the main process and not the child processes.

Basically, your code that creates the new process must be under if __name__ == '__main__':. Hence:

from uvicornmodule import main

if __name__ == "__main__":
    main.start_server()

Additionally, running uvicorn programmatically and having reload and/or workers flag(s) enabled, you must pass the application as an import string in the format of "<module>:<attribute>". For example:

uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

As per FastAPI documentation as well:

The command uvicorn main:app refers to:

  • main: the file main.py (the Python "module").
  • app: the object created inside of main.py with the line app = FastAPI().
  • --reload: make the server restart after code changes. Only use for development.
  • Related