✨ Add support for apps created by factory functions
This change adds support for using return-typed factory functions, as well as auto-detecting some function names.
I've identified factory functions by inspecting the return-type of the function (def create_app() -> FastAPI). This does require the function to be typed, but that seemed preferable to calling the function and booting the app.
I've added two default factory-function names to auto-detect: create_app() and create_api(). I've seen create_app in use in the GH issues, and added create_api to match the existing default names. These work in the same way as the other auto-detection. You can of course pass your own function name with fastapi run --app=build_app.
I decided not to copy the first-FastAPI-instance-found behaviour, as I've worked on a project before that had multiple app factories in a single file for different use-cases. One example could be a second factory that enables the debug option.
In order to pass the --factory argument to uvicorn, I changed the return signature of get_import_string() to return a tuple[str, bool] of import-string, and whether the object is a factory function or not. Unfortunately this is a breaking change if this function is used externally. We could import that object again and check it if that's an issue.
In keeping with the other tests, I opted not to use @pytest.mark.parametrize to fill in the package/factory dynamically - but if you're happy with that I'd like to refactor to use that (and reduce 1k lines 🙂).
FYI pre-commit was fighting with my local ruff from requirements-dev.lock - bumping the ruff hook version seemed to fix it (89ac14b).
Thanks again for FastAPI!
Find issues in this PR
/improve --pr_code_suggestions.num_code_suggestions_per_chunk="4" --pr_code_suggestions.commitable_code_suggestions=true
Closing due to inactivity, and conflicts.
For those that need this, the easiest workaround is to create a separate file that imports your factory function and instantiates it, and then use fastapi run myapp/run.py.