Skip to content

Commit

Permalink
[Feat] Make Vizro app itself a WSGI callable (#580)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
antonymilne and pre-commit-ci[bot] authored Jul 12, 2024
1 parent f95833c commit de1ab07
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!--
A new scriv changelog fragment.
Uncomment the section that is right (remove the HTML comment wrapper).
-->

<!--
### Highlights ✨
- A bullet item for the Highlights ✨ category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Removed
- A bullet item for the Removed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->

### Added

- Vizro app itself implements WSGI interface as a shortcut to `app.dash.server`. ([#580](https://github.com/mckinsey/vizro/pull/580))

<!--
### Changed
- A bullet item for the Changed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Deprecated
- A bullet item for the Deprecated category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Fixed
- A bullet item for the Fixed category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
<!--
### Security
- A bullet item for the Security category with a link to the relevant PR at the end of your entry, e.g. Enable feature XXX ([#1](https://github.com/mckinsey/vizro/pull/1))
-->
9 changes: 4 additions & 5 deletions vizro-core/docs/pages/user-guides/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,18 @@ The dashboard application can be launched in a Jupyter environment in `inline`,
)

dashboard = vm.Dashboard(pages=[page])
app = Vizro().build(dashboard)
server = app.dash.server # (1)!
app = Vizro().build(dashboard) # (1)!

if __name__ == "__main__": # (2)!
app.run()
```

1. Expose the underlying Flask app through `app.dash.server`; this will be used by Gunicorn.
1. The Vizro `app` object is a WSGI application that exposes the underlying Flask app; this will be used by Gunicorn.
2. Enable the same app to still be run using the built-in Flask server with `python app.py` for development purposes.

To run using Gunicorn with four worker processes, execute
```bash
gunicorn app:server --workers 4
gunicorn app:app --workers 4
```
in the command line. For more Gunicorn configuration options, refer to [Gunicorn documentation](https://docs.gunicorn.org/).

Expand All @@ -132,6 +131,6 @@ A Vizro app wraps a Dash app, which itself wraps a Flask app. Hence to deploy a
- [Flask deployment documentation](https://flask.palletsprojects.com/en/2.0.x/deploying/)
- [Dash deployment documentation](https://dash.plotly.com/deployment)

In particular, `app = Vizro()` exposes the Flask app through `app.dash.server`. As in the [above example with Gunicorn](#gunicorn), this provides the application instance to a [WSGI](https://werkzeug.palletsprojects.com/en/3.0.x/terms/#wsgi) server.
Internally, `app = Vizro()` contains a Flask app in `app.dash.server`. However, as a convenience, the Vizro `app` itself implements the [WSGI application interface](https://werkzeug.palletsprojects.com/en/3.0.x/terms/#wsgi) as a shortcut to the underlying Flask app. This means that, as in the [above example with Gunicorn](#gunicorn), the Vizro `app` object can be directly supplied to the WSGI server.

[`Vizro`][vizro.Vizro] accepts `**kwargs` that are passed through to `Dash`. This enables you to configure the underlying Dash app using the same [arguments that are available](https://dash.plotly.com/reference#dash.dash) in `Dash`. For example, in a deployment context, you might like to specify a custom `url_base_pathname` to serve your Vizro app at a specific URL rather than at your domain root.
15 changes: 14 additions & 1 deletion vizro-core/src/vizro/_vizro.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import annotations

import logging
import warnings
from pathlib import Path
from typing import List
from typing import TYPE_CHECKING, Iterable, List

import dash
import flask
Expand All @@ -13,6 +15,10 @@

logger = logging.getLogger(__name__)

if TYPE_CHECKING:
# These are built into wsgiref.types for Python 3.11 onwards.
from _typeshed.wsgi import StartResponse, WSGIEnvironment


class Vizro:
"""The main class of the `vizro` package."""
Expand Down Expand Up @@ -118,6 +124,13 @@ def _pre_build():
if hasattr(model, "pre_build"):
model.pre_build()

def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]:
"""Implements WSGI application interface.
This means you can do e.g. gunicorn app:app without needing to manually define server = app.dash.server.
"""
return self.dash.server(environ, start_response)

@staticmethod
def _reset():
"""Private method that clears all state in the `Vizro` app.
Expand Down

0 comments on commit de1ab07

Please sign in to comment.