uvicorn supports starting a specific ASGI application like this:
uvicorn app:App --port=5000
This pattern is also documented as the way to start gunicorn with the uvicorn worker class.
It's not obvious how one would build an ASGI app that takes different arguments but can still be launched in this way.
My datasette app needs exactly this. Datasette is traditionally launched using its own CLI tool - for example:
datasette trends.db flights.db --metadata=metadata.json -p 5000
For passing these arguments to uvicorn/gunicorn the best option I've come up with so far is to bundle them into an environment variable:
DATASETTE_OPTION="trends.db flights.db --metadata=metadata.json" \
uvicorn datasette:DatasetteApp --port=5000
Is this the best pattern here or is there another path that could be supported?
It's not obvious how one would build an ASGI app that takes different arguments but can still be launched in this way.
As with WSGI, I think that "passing arguments to the app" is out of scope to the ASGI protocol.
However, I think there's a strong case to make for the uvicorn cli to accept an env file, that it'll read into os.environ
Datasette is traditionally launched using its own CLI tool - for example...
At a first pass I would probably suggest that you keep doing that, then.
Use your own argument parsing, and call uvicorn.run(...).
That'll give you essentially the same thing that you currently have with sanic.
Here's what you won't get if you do that.
debug=True. Our autoreload relies on restarting a new process, rather than re-importing python modules. It's far simpler, and less subject to corner cases. However it does require that the app isn't imported by the parent process. Using the uvicorn cli, that's easy to ensure, we don't load the import string, except in the child process. Calling uvicorn.run(...) you're already typically in the application module. (We could draw up guidelines on how to use uvicorn.run with an import string, rather than the app reference itself, but there'd still be lots of scope for an import chain that's pulled in bits of code that then won't get reloaded.)uvicorn.run(), but I'd probably prefer to wait until other stuff is bedded down. (Alternatively we could go one step smaller than that and add in multi-process support, with no process management.)
Most helpful comment
As with WSGI, I think that "passing arguments to the app" is out of scope to the ASGI protocol.
However, I think there's a strong case to make for the uvicorn
clito accept an env file, that it'll read intoos.environAt a first pass I would probably suggest that you keep doing that, then.
Use your own argument parsing, and call
uvicorn.run(...).That'll give you essentially the same thing that you currently have with sanic.
Here's what you won't get if you do that.
debug=True. Our autoreload relies on restarting a new process, rather than re-importing python modules. It's far simpler, and less subject to corner cases. However it does require that the app isn't imported by the parent process. Using theuvicorncli, that's easy to ensure, we don't load the import string, except in the child process. Callinguvicorn.run(...)you're already typically in the application module. (We could draw up guidelines on how to useuvicorn.runwith an import string, rather than the app reference itself, but there'd still be lots of scope for an import chain that's pulled in bits of code that then won't get reloaded.)uvicorn.run(), but I'd probably prefer to wait until other stuff is bedded down. (Alternatively we could go one step smaller than that and add in multi-process support, with no process management.)