-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinputs.py
100 lines (86 loc) · 3.58 KB
/
inputs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import streamlit as st
import urllib
from typing import Tuple
from ast import literal_eval
class Inputs:
def __init__(self):
self.inputs = {}
# get the input value and session state for an input
#
# the default value is loaded in this priority order:
# 1. session
# 2. URL query_params
# 3. lambda function
# 4. constant
#
# this function should have no `st` dependencies
def input_value(
self,
func_name: str,
session_state_value: str | int | float,
query_param_value: str | int | float,
**args,
) -> Tuple[dict, str | int | float]:
if type(query_param_value) == str and len(query_param_value) > 100:
raise ValueError(f"query param is too long for {func_name}")
if func_name == "text_area" or func_name == "color_picker":
if query_param_value:
args["value"] = str(query_param_value)
elif func_name == "selectbox":
if query_param_value and query_param_value in args["options"]:
args["index"] = args["options"].index(query_param_value)
elif func_name == "multiselect":
if query_param_value:
args["default"] = []
for value in literal_eval(str(query_param_value)):
if value in args["options"]:
args["default"].append(value)
elif func_name == "slider":
if query_param_value:
if type(query_param_value) == str:
if "(" in query_param_value:
args["value"] = tuple(
[int(i) for i in query_param_value[1:-1].split(",")]
)
else:
args["value"] = int(query_param_value)
elif func_name == "checkbox":
if query_param_value:
args["value"] = str(query_param_value) == "True"
elif func_name == "number_input":
if session_state_value:
args["value"] = session_state_value
elif query_param_value:
if type(query_param_value) == str and "." in query_param_value:
args["value"] = float(query_param_value)
else:
args["value"] = int(query_param_value)
elif "value" in args and callable(args["value"]):
# defining the value as a lambda is helpful for generating
# runtime defaults that should persist after they are initially set
# e.g. random.randint()
value = args["value"]()
session_state_value = value
args["value"] = value
else:
raise ValueError(f"unknown input function: {func_name}")
return args, session_state_value
# the load and input_value parsing are separate functions so loading the value
# can be tested outside of a streamlit context
def load(self, func, key, **args):
if key in self.inputs:
raise ValueError(f"duplicate key: {key}")
session_state_value = st.session_state.get(key)
query_param_value = st.query_params.get(key)
[args, st.session_state[key]] = self.input_value(
func.__name__, session_state_value, query_param_value, **args
)
val = func(**args)
self.inputs[key] = val
return val
def permalink(self):
params = {}
for name, sli in self.inputs.items():
if sli is not None:
params[name] = sli
return f"/?{urllib.parse.urlencode(params)}"