Skip to content

Commit 6007f1c

Browse files
authored
Merge pull request #392 from rstudio/bcwu-shiny-bundle-tests
pyshiny manifest & bundle tests
2 parents f40666b + 15fb99a commit 6007f1c

File tree

5 files changed

+201
-0
lines changed

5 files changed

+201
-0
lines changed

tests/test_bundle.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2313,3 +2313,79 @@ def test_make_api_bundle_bokeh():
23132313
bundle_json = json.loads(tar.extractfile("manifest.json").read().decode("utf-8"))
23142314
assert bokeh_dir_ans["metadata"] == bundle_json["metadata"]
23152315
assert bokeh_dir_ans["files"].keys() == bundle_json["files"].keys()
2316+
2317+
2318+
shiny_dir = os.path.join(cur_dir, "./testdata/top-5-income-share-shiny")
2319+
shiny_file = os.path.join(cur_dir, "./testdata/top-5-income-share-shiny/app.py")
2320+
2321+
2322+
def test_make_api_manifest_shiny():
2323+
shiny_dir_ans = {
2324+
"version": 1,
2325+
"locale": "en_US.UTF-8",
2326+
"metadata": {"appmode": "python-shiny"}, # "entrypoint": "app4"},
2327+
"python": {
2328+
"version": "3.8.12",
2329+
"package_manager": {"name": "pip", "version": "23.0.1", "package_file": "requirements.txt"},
2330+
},
2331+
"files": {
2332+
"requirements.txt": {"checksum": "2a4bdca32428db1f47c6a7f0ba830a9b"},
2333+
"README.md": {"checksum": "7d083dbcdd4731d91bcb470e746b3a38"},
2334+
"app4.py": {"checksum": "f7e4b3b7ff0ada525ec388d037ff6c6a"},
2335+
"data.csv": {"checksum": "aabd9d1210246c69403532a6a9d24286"},
2336+
},
2337+
}
2338+
environment = create_python_environment(
2339+
shiny_dir,
2340+
)
2341+
manifest, _ = make_api_manifest(
2342+
shiny_dir,
2343+
None,
2344+
AppModes.PYTHON_SHINY,
2345+
environment,
2346+
None,
2347+
None,
2348+
)
2349+
2350+
assert shiny_dir_ans["metadata"] == manifest["metadata"]
2351+
assert shiny_dir_ans["files"].keys() == manifest["files"].keys()
2352+
2353+
2354+
def test_make_api_bundle_shiny():
2355+
shiny_dir_ans = {
2356+
"version": 1,
2357+
"locale": "en_US.UTF-8",
2358+
"metadata": {"appmode": "python-shiny"}, # "entrypoint": "app4"},
2359+
"python": {
2360+
"version": "3.8.12",
2361+
"package_manager": {"name": "pip", "version": "23.0.1", "package_file": "requirements.txt"},
2362+
},
2363+
"files": {
2364+
"requirements.txt": {"checksum": "2a4bdca32428db1f47c6a7f0ba830a9b"},
2365+
"README.md": {"checksum": "7d083dbcdd4731d91bcb470e746b3a38"},
2366+
"app4.py": {"checksum": "f7e4b3b7ff0ada525ec388d037ff6c6a"},
2367+
"data.csv": {"checksum": "aabd9d1210246c69403532a6a9d24286"},
2368+
},
2369+
}
2370+
environment = create_python_environment(
2371+
shiny_dir,
2372+
)
2373+
with make_api_bundle(
2374+
shiny_dir,
2375+
None,
2376+
AppModes.PYTHON_SHINY,
2377+
environment,
2378+
None,
2379+
None,
2380+
) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar:
2381+
names = sorted(tar.getnames())
2382+
assert names == [
2383+
"README.md",
2384+
"app4.py",
2385+
"data.csv",
2386+
"manifest.json",
2387+
"requirements.txt",
2388+
]
2389+
bundle_json = json.loads(tar.extractfile("manifest.json").read().decode("utf-8"))
2390+
assert shiny_dir_ans["metadata"] == bundle_json["metadata"]
2391+
assert shiny_dir_ans["files"].keys() == bundle_json["files"].keys()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Top 5% income share
2+
3+
## About this example
4+
5+
A Shiny application makes it easy to transform your analysis into an interactive application using Python so users can ask and answer their own questions in real-time.
6+
7+
8+
## Learn more
9+
10+
* [Shiny for Python documentation](https://shiny.rstudio.com/py)
11+
* [Shiny for Python examples](https://shinylive.io/py/examples/)
12+
13+
## Requirements
14+
15+
* Python version 3.7 or higher
16+
17+
<!-- NOTE: this file is generated -->
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import altair as alt
2+
import pandas as pd
3+
from shinywidgets import output_widget, render_widget
4+
from shiny import App, reactive, ui
5+
6+
income_shares = pd.read_csv("data.csv")
7+
countries = income_shares["Entity"].unique().tolist()
8+
9+
select_countries = {
10+
"default": ["Australia", "China", "Germany", "Japan", "United States"],
11+
"latam": ["Argentina", "Uruguay"],
12+
"apac": ["Australia", "China", "Singapore", "Japan", "Korea, South"],
13+
"emea": ["Mauritius", "France", "Italy", "Norway", "Spain"],
14+
"na": ["United States", "Canada"],
15+
}
16+
17+
app_ui = ui.page_fluid(
18+
ui.panel_title("Top 5% Income Share"),
19+
ui.p("Share of income received by the richest 5% of the population"),
20+
ui.layout_sidebar(
21+
ui.panel_sidebar(
22+
ui.input_selectize(
23+
"countries",
24+
"Countries:",
25+
choices=countries,
26+
multiple=True,
27+
selected=select_countries["default"],
28+
),
29+
ui.p("Regions:"),
30+
ui.TagList(
31+
ui.div(
32+
{"class": "btn-group"},
33+
ui.input_action_button("apac", "APAC"),
34+
ui.input_action_button("emea", "EMEA"),
35+
ui.input_action_button("latam", "LATAM"),
36+
ui.input_action_button("na", "NA"),
37+
)
38+
),
39+
ui.input_slider(
40+
"year_range",
41+
"Year Range:",
42+
min=1946,
43+
max=2015,
44+
value=(1946, 2015),
45+
sep="",
46+
),
47+
),
48+
ui.panel_main(
49+
output_widget("income_plot", width="800px"),
50+
),
51+
),
52+
)
53+
54+
55+
def server(input, output, session):
56+
@reactive.Calc
57+
def plot_data():
58+
df = income_shares.loc[
59+
(income_shares["Entity"].isin(input.countries()))
60+
& (income_shares["Year"] >= input.year_range()[0])
61+
& (income_shares["Year"] <= input.year_range()[1])
62+
]
63+
return df
64+
65+
@output
66+
@render_widget
67+
def income_plot():
68+
chart = (
69+
alt.Chart(plot_data())
70+
.mark_line()
71+
.encode(
72+
x=alt.X("Year", axis=alt.Axis(format="d")),
73+
y=alt.Y("Percent", axis=alt.Axis(format="~s")),
74+
color="Entity",
75+
strokeDash="Entity",
76+
)
77+
)
78+
return chart
79+
80+
def make_button_listener(name):
81+
@reactive.Effect
82+
@reactive.event(input[name])
83+
def _():
84+
ui.update_selectize("countries", selected=select_countries[name])
85+
86+
for name in select_countries.keys():
87+
make_button_listener(name)
88+
89+
90+
app = App(app_ui, server)
91+
if __name__ == "__main__":
92+
app.run()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Entity,Code,Year,Percent
2+
Argentina,ARG,1953,29.07
3+
Argentina,ARG,1954,30.28
4+
Argentina,ARG,1956,28.96
5+
Argentina,ARG,1959,30.41
6+
Argentina,ARG,1961,28
7+
Argentina,ARG,1997,22.45
8+
Australia,AUS,1946,21.76
9+
Australia,AUS,1947,23.41
10+
Australia,AUS,1948,23.35
11+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
shiny
2+
shinywidgets
3+
altair
4+
pandas
5+
vega

0 commit comments

Comments
 (0)