Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type checking with pyright #164

Merged
merged 47 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
f4a3413
lower and upper more consistently
mccalluc Nov 4, 2024
12c1402
one more
mccalluc Nov 4, 2024
1274e75
handle bounds/bins/counts the same way
mccalluc Nov 5, 2024
19c3065
lots of reactive dicts, but the UI has not changed
mccalluc Nov 5, 2024
603d0bc
data dump on the results page
mccalluc Nov 5, 2024
ad32217
add a pragma: no cover
mccalluc Nov 5, 2024
c8b4ddc
reset widget values after checkbox change
mccalluc Nov 7, 2024
1247392
do not clean up values
mccalluc Nov 7, 2024
34e1170
resolve conflicts
mccalluc Nov 7, 2024
f35ed4f
resolve conflicts
mccalluc Nov 7, 2024
a11c9fa
resolve conflicts
mccalluc Nov 7, 2024
d84c4cd
use "upper" and "lower"
mccalluc Nov 7, 2024
16463b4
put tooltips in labels
mccalluc Nov 8, 2024
9cd991d
pull warning up to analysis panel. TODO: conditional
mccalluc Nov 8, 2024
f2b5192
move warning to bottom of list
mccalluc Nov 8, 2024
da6a0cb
analysis definition JSON
mccalluc Nov 8, 2024
0dbdd7b
stubs for python
mccalluc Nov 8, 2024
610404c
stub a script on results page
mccalluc Nov 8, 2024
c45585b
include column info in generated script
mccalluc Nov 8, 2024
5803715
closer to a runable notebook
mccalluc Nov 8, 2024
93c9543
stuck on split_by_weight... maybe a library bug?
mccalluc Nov 8, 2024
f27a175
margin stubs
mccalluc Nov 13, 2024
6093cfb
resolve conflicts
mccalluc Nov 13, 2024
6b8a38f
format python identifiers correctly
mccalluc Nov 13, 2024
1a9a2a7
script has gotten longer: does not make sense to check for exact equa…
mccalluc Nov 13, 2024
d3be33d
fix syntactic problems in generated code
mccalluc Nov 13, 2024
03c6dfa
fill in columns, but still WIP
mccalluc Nov 14, 2024
d560195
Merge dp_creator_ii -> dp_wizard
mccalluc Nov 15, 2024
a3abd8d
fix column names; tests pass
mccalluc Nov 15, 2024
a79dbdc
move confidence
mccalluc Nov 15, 2024
8ff945a
simplify download panel
mccalluc Nov 15, 2024
d635dd2
add markdown cells
mccalluc Nov 15, 2024
0362d38
tidy up
mccalluc Nov 15, 2024
291dcdb
switch requirements from mypy to pyright
mccalluc Nov 15, 2024
7b24d27
run pyright; currently fails
mccalluc Nov 15, 2024
6e53212
fix pyright errors
mccalluc Nov 15, 2024
b8b76e1
type input, output, session
mccalluc Nov 15, 2024
d6694c1
rm unused session
mccalluc Nov 15, 2024
79fc793
more typing
mccalluc Nov 15, 2024
72c9282
Merge main
mccalluc Nov 18, 2024
238b703
enable strict type checking; lots of errors!
mccalluc Nov 18, 2024
8fde82b
more typing. Add "finish()" for Templates
mccalluc Nov 18, 2024
ab6faf4
add a lot of ignores, but type checks pass locally
mccalluc Nov 18, 2024
6c35bca
I think Optional is needed under 3.9
mccalluc Nov 18, 2024
bb67346
Remove strict, and most of the ignores
mccalluc Nov 21, 2024
39defe6
merge main, resolve conflicts, fix tests
mccalluc Nov 21, 2024
af25659
tests in code generation
mccalluc Nov 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .mypy.ini

This file was deleted.

13 changes: 7 additions & 6 deletions dp_wizard/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from pathlib import Path
import logging

from shiny import App, ui, reactive
from shiny import App, ui, reactive, Inputs, Outputs, Session

from dp_wizard.utils.argparse_helpers import get_cli_info
from dp_wizard.utils.argparse_helpers import get_cli_info, CLIInfo
from dp_wizard.app import analysis_panel, dataset_panel, results_panel, feedback_panel


Expand All @@ -26,16 +26,17 @@ def ctrl_c_reminder(): # pragma: no cover
print("Session ended (Press CTRL+C to quit)")


def make_server_from_cli_info(cli_info):
def server(input, output, session): # pragma: no cover
csv_path = reactive.value(cli_info.csv_path)
def make_server_from_cli_info(cli_info: CLIInfo):
def server(input: Inputs, output: Outputs, session: Session): # pragma: no cover
cli_csv_path = cli_info.csv_path
csv_path = reactive.value("" if cli_csv_path is None else cli_csv_path)
contributions = reactive.value(cli_info.contributions)

lower_bounds = reactive.value({})
upper_bounds = reactive.value({})
bin_counts = reactive.value({})
weights = reactive.value({})
epsilon = reactive.value(1)
epsilon = reactive.value(1.0)

dataset_panel.dataset_server(
input,
Expand Down
31 changes: 17 additions & 14 deletions dp_wizard/app/analysis_panel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from math import pow
from typing import Iterable, Any

from shiny import ui, reactive, render, req
from shiny import ui, reactive, render, req, Inputs, Outputs, Session

from dp_wizard.app.components.inputs import log_slider
from dp_wizard.app.components.column_module import column_ui, column_server
Expand Down Expand Up @@ -39,7 +40,9 @@ def analysis_ui():
)


def _cleanup_reactive_dict(reactive_dict, keys_to_keep): # pragma: no cover
def _cleanup_reactive_dict(
reactive_dict: reactive.Value[dict[str, Any]], keys_to_keep: Iterable[str]
): # pragma: no cover
reactive_dict_copy = {**reactive_dict()}
keys_to_del = set(reactive_dict_copy.keys()) - set(keys_to_keep)
for key in keys_to_del:
Expand All @@ -48,17 +51,17 @@ def _cleanup_reactive_dict(reactive_dict, keys_to_keep): # pragma: no cover


def analysis_server(
input,
output,
session,
csv_path,
contributions,
is_demo,
lower_bounds,
upper_bounds,
bin_counts,
weights,
epsilon,
input: Inputs,
output: Outputs,
session: Session,
csv_path: reactive.Value[str],
contributions: reactive.Value[int],
is_demo: bool,
lower_bounds: reactive.Value[dict[str, float]],
upper_bounds: reactive.Value[dict[str, float]],
bin_counts: reactive.Value[dict[str, int]],
weights: reactive.Value[dict[str, str]],
epsilon: reactive.Value[float],
): # pragma: no cover
@reactive.calc
def button_enabled():
Expand Down Expand Up @@ -133,7 +136,7 @@ def columns_ui():
"""
)
],
col_widths=col_widths,
col_widths=col_widths, # type: ignore
)
if column_ids
else []
Expand Down
46 changes: 23 additions & 23 deletions dp_wizard/app/components/column_module.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
from logging import info

from shiny import ui, render, module, reactive
from shiny import ui, render, module, reactive, Inputs, Outputs, Session

from dp_wizard.utils.dp_helper import make_confidence_accuracy_histogram
from dp_wizard.utils.shared import plot_histogram
from dp_wizard.utils.code_generators import make_column_config_block
from dp_wizard.app.components.outputs import output_code_sample, demo_tooltip


default_weight = 2
default_weight = "2"

col_widths = {
# Controls stay roughly a constant width;
# Graph expands to fill space.
"sm": (4, 8),
"md": (3, 9),
"lg": (2, 10),
"sm": [4, 8],
"md": [3, 9],
"lg": [2, 10],
}


Expand All @@ -37,9 +37,9 @@ def column_ui(): # pragma: no cover
"weight",
["Weight", ui.output_ui("weight_tooltip_ui")],
choices={
1: "Less accurate",
"1": "Less accurate",
default_weight: "Default",
4: "More accurate",
"4": "More accurate",
},
selected=default_weight,
width=width,
Expand All @@ -50,31 +50,31 @@ def column_ui(): # pragma: no cover
# Make plot smaller than default: about the same size as the other column.
output_code_sample("Column Definition", "column_code"),
],
col_widths=col_widths,
col_widths=col_widths, # type: ignore
)


@module.server
def column_server(
input,
output,
session,
name,
contributions,
epsilon,
lower_bounds,
upper_bounds,
bin_counts,
weights,
is_demo,
input: Inputs,
output: Outputs,
session: Session,
name: str,
contributions: int,
epsilon: float,
lower_bounds: reactive.Value[dict[str, float]],
upper_bounds: reactive.Value[dict[str, float]],
bin_counts: reactive.Value[dict[str, int]],
weights: reactive.Value[dict[str, str]],
is_demo: bool,
): # pragma: no cover
@reactive.effect
def _set_all_inputs():
with reactive.isolate(): # Without isolate, there is an infinite loop.
ui.update_numeric("lower", value=lower_bounds().get(name, 0))
ui.update_numeric("upper", value=upper_bounds().get(name, 10))
ui.update_numeric("bins", value=bin_counts().get(name, 10))
ui.update_numeric("weight", value=weights().get(name, default_weight))
ui.update_numeric("weight", value=int(weights().get(name, default_weight)))

@reactive.effect
@reactive.event(input.lower)
Expand All @@ -89,12 +89,12 @@ def _set_upper():
@reactive.effect
@reactive.event(input.bins)
def _set_bins():
bin_counts.set({**bin_counts(), name: float(input.bins())})
bin_counts.set({**bin_counts(), name: int(input.bins())})

@reactive.effect
@reactive.event(input.weight)
def _set_weight():
weights.set({**weights(), name: float(input.weight())})
weights.set({**weights(), name: input.weight()})

@render.ui
def bounds_tooltip_ui():
Expand Down Expand Up @@ -149,7 +149,7 @@ def column_plot():
upper_x = float(input.upper())
bin_count = int(input.bins())
weight = float(input.weight())
weights_sum = sum(weights().values())
weights_sum = sum(float(weight) for weight in weights().values())
info(f"Weight ratio for {name}: {weight}/{weights_sum}")
if weights_sum == 0:
# This function is triggered when column is removed;
Expand Down
2 changes: 1 addition & 1 deletion dp_wizard/app/components/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from shiny import ui


def log_slider(id, lower, upper):
def log_slider(id: str, lower: float, upper: float):
# Rather than engineer a new widget, hide the numbers we don't want.
# The rendered widget doesn't have a unique ID, but the following
# element does, so we can use some fancy CSS to get the preceding element.
Expand Down
4 changes: 2 additions & 2 deletions dp_wizard/app/components/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from faicons import icon_svg


def output_code_sample(title, name_of_render_function):
def output_code_sample(title: str, name_of_render_function: str):
return details(
summary(f"Code sample: {title}"),
ui.output_code(name_of_render_function),
)


def demo_tooltip(is_demo, text): # pragma: no cover
def demo_tooltip(is_demo: bool, text: str): # pragma: no cover
if is_demo:
return ui.tooltip(
icon_svg("circle-question"),
Expand Down
13 changes: 8 additions & 5 deletions dp_wizard/app/dataset_panel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from shiny import ui, reactive, render
from shiny import ui, reactive, render, Inputs, Outputs, Session

from dp_wizard.utils.argparse_helpers import get_cli_info
from dp_wizard.app.components.outputs import output_code_sample, demo_tooltip
Expand All @@ -9,9 +9,7 @@

def dataset_ui():
cli_info = get_cli_info()
csv_placeholder = (
None if cli_info.csv_path is None else Path(cli_info.csv_path).name
)
csv_placeholder = "" if cli_info.csv_path is None else Path(cli_info.csv_path).name

return ui.nav_panel(
"Select Dataset",
Expand Down Expand Up @@ -41,7 +39,12 @@ def dataset_ui():


def dataset_server(
input, output, session, csv_path=None, contributions=None, is_demo=None
input: Inputs,
output: Outputs,
session: Session,
csv_path: reactive.Value[str],
contributions: reactive.Value[int],
is_demo: bool,
): # pragma: no cover
@reactive.effect
@reactive.event(input.csv_path)
Expand Down
8 changes: 4 additions & 4 deletions dp_wizard/app/feedback_panel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from shiny import ui
from shiny import ui, Inputs, Outputs, Session
from htmltools import HTML


Expand All @@ -25,8 +25,8 @@ def feedback_ui():


def feedback_server(
input,
output,
session,
input: Inputs,
output: Outputs,
session: Session,
): # pragma: no cover
pass
22 changes: 11 additions & 11 deletions dp_wizard/app/results_panel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from shiny import ui, render, reactive
from shiny import ui, render, reactive, Inputs, Outputs, Session

from dp_wizard.utils.code_generators import (
NotebookGenerator,
Expand Down Expand Up @@ -26,16 +26,16 @@ def results_ui():


def results_server(
input,
output,
session,
csv_path,
contributions,
lower_bounds,
upper_bounds,
bin_counts,
weights,
epsilon,
input: Inputs,
output: Outputs,
session: Session,
csv_path: reactive.Value[str],
contributions: reactive.Value[int],
lower_bounds: reactive.Value[dict[str, float]],
upper_bounds: reactive.Value[dict[str, float]],
bin_counts: reactive.Value[dict[str, int]],
weights: reactive.Value[dict[str, str]],
epsilon: reactive.Value[float],
): # pragma: no cover
@reactive.calc
def analysis_plan() -> AnalysisPlan:
Expand Down
19 changes: 11 additions & 8 deletions dp_wizard/utils/argparse_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
import csv
import random
from warnings import warn
from collections import namedtuple
from typing import NamedTuple, Optional


def _existing_csv_type(arg):
def _existing_csv_type(arg: str) -> Path:
path = Path(arg)
if not path.exists():
raise ArgumentTypeError(f"No such file: {arg}")
Expand Down Expand Up @@ -54,7 +54,7 @@ def _get_args():
return arg_parser.parse_args() # pragma: no cover


def _clip(n, lower, upper):
def _clip(n: float, lower: float, upper: float) -> float:
"""
>>> _clip(-5, 0, 10)
0
Expand All @@ -66,7 +66,13 @@ def _clip(n, lower, upper):
return max(min(n, upper), lower)


def _get_demo_csv_contrib():
class CLIInfo(NamedTuple):
csv_path: Optional[str]
contributions: int
is_demo: bool


def _get_demo_csv_contrib() -> CLIInfo:
"""
>>> csv_path, contributions, is_demo = _get_demo_csv_contrib()
>>> with open(csv_path, newline="") as csv_handle:
Expand Down Expand Up @@ -103,10 +109,7 @@ def _get_demo_csv_contrib():
}
)

return CLIInfo(csv_path=csv_path, contributions=contributions, is_demo=True)


CLIInfo = namedtuple("CLIInfo", ["csv_path", "contributions", "is_demo"])
return CLIInfo(csv_path=str(csv_path), contributions=contributions, is_demo=True)


def get_cli_info(): # pragma: no cover
Expand Down
Loading
Loading