Migrating App To Tapyr
The migration guide was written before Shiny 1.0 release, and tapyr 0.2 release. Most of the information should still be valid, the only larger change is that uv
is now used instead of poetry
for managing the environment. Instead of poetry add ...
you should use uv add ...
, and to run the a script you should use uv run shiny run app.py
. uv
guide on managing dependencies in projects.
General Steps
To migrate an app to Tapyr, you need to do the following the following steps:
- Create repository from template
- Open it in the devcontainer and select python interpreter
- Update the project name and
pyproject.toml
- Add required dependencies to
pyproject.toml
- Install pre-commit hooks
- Migrate ui and server functions to
stock_app_tapyr/view/root/server.py
andstock_app_tapyr/view/root/ui.py
. Move utility functions tostock_app_tapyr/logic
or other, more suitable directories. - Adjust imports in the
stock_app_tapyr
directory to reflect the new project structure. - Run linter and formatter to fix any issues.
- Fix the tests.
- Fix any issues reported by the linter and type checker.
- Finally, adjust the
README.md
file!
Now let’s go through a simple example of migrating an app to Tapyr.
Simple App Example
We will migrate the stock-app from Shiny for Python templates to Tapyr.
Create Repository From Template
Go to the tapyr repo and click on the “Use this template” button, follow the instructions to create a new repository.
Open It In The Devcontainer
Open the repository in the devcontainer by clicking ctrl+shift+p
and selecting Remote-Containers: Reopen in Container
.
Now open any python file and select the python interpreter by clicking on the python version in the bottom left corner. The name of the interpreter should be stock_app_tapyr-xxxxx
(the beginning should match the poetry environment name).
Update Project Name and pyproject.toml
Update the project name in the pyproject.toml
file and the tapyr_template
directory to stock_app_tapyr
. Adjust all the imports in the tapyr_template
directory to reflect the new project name.
Add Required Dependencies to pyproject.toml
Either add them manually or use the poetry add
. I’ve decided to just run
poetry add plotly yfinance pandas shinywidgets faicons cufflinks
If you edit pyproject.toml
manually, you need to run poetry lock
and poetry install
to update the environment.
Install Pre-commit Hooks
Just run pre-commit install
to install the pre-commit hooks.
Migrate UI and Server Functions
Now from the stock-app/app-core.py
file extract the server to stock_app_tapyr/view/root/server.py
and the ui to stock_app_tapyr/view/root/ui.py
.
Remove unused imports, they are greyed out in the editor.
Migrate Utility Functions
Move the stock-app/stocks.py
to stock_app_tapyr/logic/stocks.py
.
Adjust the imports in ui.py
from from stocks import stocks
to from stock_app_tapyr.logic.stocks import stocks
.
We can run the app to see if everything works.
shiny run app.py
It doesn’t, we see that in stock-app
they include css in the ui.py
file. We already do it, so we need to remove this line.
We run app one more time and we see that styling is a bit off. That’s because we forget to actually copy the css contents to www/style.css
. We do it now.
The works as expected now 🎉.
Run Linter and Formatter
This is simply pre-commit run --all-files
.
Now our code is well formatted.
Fix the tests
We remove the utils test and function.
stock_app_tapyr/logic/utils.py
tests/unit/test_utils.py
In the test_ui.py
we’re removing the test_footer
function and leave only the test_startup
function.
Fix pyright issues
Linter is happy, but pyright is not.
Two small things have to be fixed. Those might seem a bit more advanced, but please check the resulting commit.
- We need to add the return type to
def get_change():
->def get_change() -> float:
inserver.py
- In
ui.py
variablestart
is used inui.input_date_range
function.start
is of typepd.Timestamp
andui.input_date_range
expectsdate
. At least when it comes to typing, because we see that it works fine. We have to case thestart
todate
type. Then we have another issue, because it can bepd.NaT
(not a time) so we narrow the type withif not isinstance(start, date):
check.
Adjust the README.md
file
Now we can adjust the README.md
and describe the app.
Summary
Congratulation 🎉, you’ve successfully migrated the app to Tapyr. Now you have a clean and well-structured project that is easy to maintain and extend. The first test is already there!