Packaging a Python Shiny app

After spending few years writing R Shiny apps with {golem}, the first thing I thought about when writing the Python Shiny demo was is it possible to convert it to a python package and if yes how to it.

I was surprised to learn that it is actually pretty simple to do that, especially when compared to the {golem} environment, which I feel has a learning curve to master.

The template app for Shiny for Python is generated with:

shiny create .

Which produces a really simple directory structure

shiny_app
├── app.py

To get to a python package we just need to move some things around and create this structure:

shiny_app/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── shiny_app/
│       ├── __init__.py
│       └── app.py
└── tests/

Top to bottom, most of the things are self-explanatory: a license file and a readme, and a directory for tests. The src folder is where the main code lives, which is the equivalent of the R directory in R packages and in {golem}.

__init__.py is a python specific file, required to import the directory as a package. It should be empty.

And, pyproject.toml is the equivalent of a DESCRIPTION file in R. A sample toml file is included in the Packaging Python Project tutorial.

An app though is rarely one file, so in the code folder additional py files may live, like files with functions (fct files in {golem}) or with shiny modules (mod files in {golem}). The nice thing about python though, is that these can live in their own sub folders. A big and complicated shiny app may look like this when packaged.

shiny_app/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── shiny_app/
│       ├── __init__.py
│       ├── app.py
│       └── helpers.py
│       └── fct/
│           ├── __init__.py
│           ├── fct_1.py
│           ├── fct_2.py
│           └── fct_3.py
│       └── mod/
│           ├── __init__.py
│           ├── mod_1.py
│           ├── mod_2.py
│           └── mod_3.py
└── tests/

To make it work, the imports in the main app.py file should include the folder names as well as the module name and functions needed.

from .helpers import helpe1, helper2
from .fct.fct_1 import function_1
from .mod/mod_1.py import modUI, modServer

Once everything is ready, the package can be build with running the following in the folder where the toml file is:

python3 -m build

Then installed with:

pip install .

Finally ran with:

uvicorn shiny_app.app:app --host 127.0.0.1 --port 8000
Novica Nakov
Novica Nakov

Data Wrangler.