diff --git a/.coveragerc b/.coveragerc index 1f2be51..3342379 100644 --- a/.coveragerc +++ b/.coveragerc @@ -4,7 +4,7 @@ source = . omit = # TODO - app.py + dp_creator_ii/app/* # More strict: Check transitions between lines, not just individual lines. # TODO: branch = True diff --git a/dp_creator_ii/app/__init__.py b/dp_creator_ii/app/__init__.py new file mode 100644 index 0000000..f636d97 --- /dev/null +++ b/dp_creator_ii/app/__init__.py @@ -0,0 +1,23 @@ +from shiny import App, ui + +from dp_creator_ii.app import analysis_panel, dataset_panel, results_panel + + +app_ui = ui.page_bootstrap( + ui.navset_tab( + dataset_panel.dataset_ui(), + analysis_panel.analysis_ui(), + results_panel.results_ui(), + id="top_level_nav", + ), + title="DP Creator II", +) + + +def server(input, output, session): + dataset_panel.dataset_server(input, output, session) + analysis_panel.analysis_server(input, output, session) + results_panel.results_server(input, output, session) + + +app = App(app_ui, server) diff --git a/dp_creator_ii/app/analysis_panel.py b/dp_creator_ii/app/analysis_panel.py new file mode 100644 index 0000000..ff89a81 --- /dev/null +++ b/dp_creator_ii/app/analysis_panel.py @@ -0,0 +1,17 @@ +from shiny import ui, reactive + + +def analysis_ui(): + return ui.nav_panel( + "Perform Analysis", + "TODO: Define analysis", + ui.input_action_button("go_to_results", "Download results"), + value="analysis_panel", + ) + + +def analysis_server(input, output, session): + @reactive.effect + @reactive.event(input.go_to_results) + def go_to_results(): + ui.update_navs("top_level_nav", selected="results_panel") diff --git a/dp_creator_ii/app/dataset_panel.py b/dp_creator_ii/app/dataset_panel.py new file mode 100644 index 0000000..8e83995 --- /dev/null +++ b/dp_creator_ii/app/dataset_panel.py @@ -0,0 +1,36 @@ +from pathlib import Path +import json +from shiny import ui, reactive, render + + +def dataset_ui(): + return ui.nav_panel( + "Select Dataset", + "TODO: Pick dataset", + ui.output_text("csv_path_text"), + ui.output_text("unit_of_privacy_text"), + ui.input_action_button("go_to_analysis", "Perform analysis"), + value="dataset_panel", + ) + + +def dataset_server(input, output, session): + config_path = Path(__file__).parent / "config.json" + config = json.loads(config_path.read_text()) + config_path.unlink() + + csv_path = reactive.value(config["csv_path"]) + unit_of_privacy = reactive.value(config["unit_of_privacy"]) + + @render.text + def csv_path_text(): + return str(csv_path.get()) + + @render.text + def unit_of_privacy_text(): + return str(unit_of_privacy.get()) + + @reactive.effect + @reactive.event(input.go_to_analysis) + def go_to_analysis(): + ui.update_navs("top_level_nav", selected="analysis_panel") diff --git a/dp_creator_ii/app.py b/dp_creator_ii/app/results_panel.py similarity index 52% rename from dp_creator_ii/app.py rename to dp_creator_ii/app/results_panel.py index 0d975a3..aa72abf 100644 --- a/dp_creator_ii/app.py +++ b/dp_creator_ii/app/results_panel.py @@ -1,31 +1,10 @@ -from shiny import App, ui, reactive, render +from shiny import ui, render -from dp_creator_ii import get_arg_parser from dp_creator_ii.template import make_notebook_py, make_script_py from dp_creator_ii.converters import convert_py_to_nb -def dataset_panel(): - return ui.nav_panel( - "Select Dataset", - "TODO: Pick dataset", - ui.output_text("csv_path_text"), - ui.output_text("unit_of_privacy_text"), - ui.input_action_button("go_to_analysis", "Perform analysis"), - value="dataset_panel", - ) - - -def analysis_panel(): - return ui.nav_panel( - "Perform Analysis", - "TODO: Define analysis", - ui.input_action_button("go_to_results", "Download results"), - value="analysis_panel", - ) - - -def results_panel(): +def results_ui(): return ui.nav_panel( "Download Results", "TODO: Download Results", @@ -41,41 +20,7 @@ def results_panel(): ) -app_ui = ui.page_bootstrap( - ui.navset_tab( - dataset_panel(), - analysis_panel(), - results_panel(), - id="top_level_nav", - ), - title="DP Creator II", -) - - -def server(input, output, session): - args = get_arg_parser().parse_args() - - csv_path = reactive.value(args.csv_path) - unit_of_privacy = reactive.value(args.unit_of_privacy) - - @render.text - def csv_path_text(): - return str(csv_path.get()) - - @render.text - def unit_of_privacy_text(): - return str(unit_of_privacy.get()) - - @reactive.effect - @reactive.event(input.go_to_analysis) - def go_to_analysis(): - ui.update_navs("top_level_nav", selected="analysis_panel") - - @reactive.effect - @reactive.event(input.go_to_results) - def go_to_results(): - ui.update_navs("top_level_nav", selected="results_panel") - +def results_server(input, output, session): @render.download( filename="dp-creator-script.py", media_type="text/x-python", @@ -115,6 +60,3 @@ async def download_notebook_executed(): ) notebook_nb = convert_py_to_nb(notebook_py, execute=True) yield notebook_nb - - -app = App(app_ui, server) diff --git a/dp_creator_ii/tests/test_app.py b/dp_creator_ii/tests/test_app.py index ec1ea58..684af42 100644 --- a/dp_creator_ii/tests/test_app.py +++ b/dp_creator_ii/tests/test_app.py @@ -3,7 +3,7 @@ from shiny.pytest import create_app_fixture -app = create_app_fixture("../app.py") +app = create_app_fixture("../app/__init__.py") # TODO: Why is incomplete coverage reported here?