Skip to content

Commit 7a74a9c

Browse files
authored
Merge branch 'main' into users/mjohanse/more_pb_converters
2 parents 8f49a68 + 0b7c6f1 commit 7a74a9c

File tree

8 files changed

+121
-50
lines changed

8 files changed

+121
-50
lines changed

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,3 @@ cython_debug/
172172

173173
# PyPI configuration file
174174
.pypirc
175-
176-
# VS Code settings
177-
.vscode/launch.json

.vscode/launch.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python Debugger: Current File",
9+
"type": "debugpy",
10+
"request": "launch",
11+
"program": "${file}",
12+
"console": "integratedTerminal"
13+
},
14+
{
15+
// To use this configuration, add `debugpy.listen(("localhost", 5678))` to the script you wish to debug
16+
"name": "Attach to Streamlit at localhost:5678",
17+
"type": "debugpy",
18+
"request": "attach",
19+
"connect": {
20+
"host": "localhost",
21+
"port": 5678
22+
},
23+
"justMyCode": false
24+
}
25+
]
26+
}

CONTRIBUTING.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ start docs\_build\index.html
5656

5757
# Debugging on the streamlit side
5858

59-
Debugging the measurement script can be done using standard Python debugging techniques. However, debugging the Streamlit script—or any code invoked by the Streamlit script—is more complex because it runs in a separate process launched by the PythonPanelServer. To debug the Streamlit script, you can use debugpy to attach the Visual Studio Code debugger as follows:
59+
Debugging the measurement script can be done using standard Python debugging
60+
techniques. However, debugging the Streamlit script—or any code invoked by the
61+
Streamlit script—is more complex because it runs in a separate process launched
62+
by the PythonPanelServer. To debug the Streamlit script, you can use debugpy to
63+
attach the Visual Studio Code debugger as follows:
6064

6165
## Instrument Streamlit script to debug
6266

@@ -73,9 +77,15 @@ except RuntimeError as e:
7377
raise
7478
```
7579

76-
The `debugpy.listen()` function opens a port that allows the debugger to attach to the running process. You can specify any available port, as long as it matches the port configured in the launch.json file shown below. Since calling listen() more than once will raise an exception, it is wrapped in a try block to prevent the script from crashing if it is rerun.
80+
The `debugpy.listen()` function opens a port that allows the debugger to attach
81+
to the running process. You can specify any available port, as long as it
82+
matches the port configured in the launch.json file shown below. Since calling
83+
listen() more than once will raise an exception, it is wrapped in a try block to
84+
prevent the script from crashing if it is rerun.
7785

78-
The `debugpy.wait_for_client()` function pauses script execution until the debugger is attached. This is helpful if you need to debug initialization code, but you can omit this line if it is not required.
86+
The `debugpy.wait_for_client()` function pauses script execution until the
87+
debugger is attached. This is helpful if you need to debug initialization code,
88+
but you can omit this line if it is not required.
7989

8090
The `import debugpy` statement includes a type suppression comment to satisfy mypy.
8191

@@ -96,7 +106,12 @@ You will also need this configuration in your launch.json:
96106
}
97107
```
98108

99-
After running your measurement script and allowing the PythonPanelServer to launch Streamlit with your Streamlit script, you can attach the debugger by clicking the **Attach to Streamlit at localhost:5678** button in the VS Code **Run and Debug** tab. Once attached, you can set breakpoints and use all standard debugging features in your Streamlit script, as well as in any nipanel code invoked by the Streamlit script.
109+
After running your measurement script and allowing the PythonPanelServer to
110+
launch Streamlit with your Streamlit script, you can attach the debugger by
111+
clicking the **Attach to Streamlit at localhost:5678** button in the VS Code
112+
**Run and Debug** tab. Once attached, you can set breakpoints and use all
113+
standard debugging features in your Streamlit script, as well as in any nipanel
114+
code invoked by the Streamlit script.
100115

101116
# Developer Certificate of Origin (DCO)
102117

examples/sample/sample_panel.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
st.write("List")
1919

2020
with col2:
21-
st.write(panel.get_value("sample_string"))
22-
st.write(panel.get_value("sample_int"))
23-
st.write(panel.get_value("sample_float"))
24-
st.write(panel.get_value("sample_bool"))
25-
st.write(panel.get_value("float_values"))
21+
st.write(panel.get_value("sample_string", ""))
22+
st.write(panel.get_value("sample_int", 0))
23+
st.write(panel.get_value("sample_float", 0.0))
24+
st.write(panel.get_value("sample_bool", False))
25+
st.write(panel.get_value("float_values", []))

poetry.lock

Lines changed: 33 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nipanel/_panel_value_accessor.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,23 @@ def panel_id(self) -> str:
4141
"""Read-only accessor for the panel ID."""
4242
return self._panel_id
4343

44-
def get_value(self, value_id: str) -> object:
45-
"""Get the value for a control on the panel.
44+
def get_value(self, value_id: str, default_value: object = None) -> object:
45+
"""Get the value for a control on the panel with an optional default value.
4646
4747
Args:
4848
value_id: The id of the value
49+
default_value: The default value to return if the value is not set
4950
5051
Returns:
51-
The value
52+
The value, or the default value if not set
5253
"""
53-
return self._panel_client.get_value(self._panel_id, value_id)
54+
try:
55+
return self._panel_client.get_value(self._panel_id, value_id)
56+
except grpc.RpcError as e:
57+
if e.code() == grpc.StatusCode.NOT_FOUND and default_value is not None:
58+
return default_value
59+
else:
60+
raise e
5461

5562
def set_value(self, value_id: str, value: object) -> None:
5663
"""Set the value for a control on the panel.

tests/unit/test_streamlit_panel.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def test___panel___set_value___sets_value(
123123
}
124124

125125

126-
def test___panel___get_unset_value___raises_exception(
126+
def test___panel___get_unset_value_with_no_default___raises_exception(
127127
fake_panel_channel: grpc.Channel,
128128
) -> None:
129129
"""Test that get_value() raises an exception for an unset value."""
@@ -146,6 +146,30 @@ def test___panel___set_value___gets_value(
146146
assert panel.get_value(value_id) == string_value
147147

148148

149+
def test___set_value___get_value_ignores_default(
150+
fake_panel_channel: grpc.Channel,
151+
) -> None:
152+
panel = StreamlitPanel("my_panel", "path/to/script", grpc_channel=fake_panel_channel)
153+
154+
value_id = "test_id"
155+
string_value = "test_value"
156+
panel.set_value(value_id, string_value)
157+
158+
assert panel.get_value(value_id, "default") == string_value
159+
160+
161+
def test___get_value_returns_default_when_value_not_set(
162+
fake_panel_channel: grpc.Channel,
163+
) -> None:
164+
panel = StreamlitPanel("my_panel", "path/to/script", grpc_channel=fake_panel_channel)
165+
166+
assert panel.get_value("missing_string", "default") == "default"
167+
assert panel.get_value("missing_int", 123) == 123
168+
assert panel.get_value("missing_float", 1.23) == 1.23
169+
assert panel.get_value("missing_bool", True) is True
170+
assert panel.get_value("missing_list", [1, 2, 3]) == [1, 2, 3]
171+
172+
149173
@pytest.mark.parametrize(
150174
"value_payload",
151175
[

tests/utils/_fake_python_panel_servicer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ def EnumeratePanels( # noqa: N802
5959

6060
def GetValue(self, request: GetValueRequest, context: Any) -> GetValueResponse: # noqa: N802
6161
"""Trivial implementation for testing."""
62+
if request.value_id not in self._panel_value_ids.get(request.panel_id, {}):
63+
context.abort(grpc.StatusCode.NOT_FOUND, "Value ID not found in panel")
6264
value = self._panel_value_ids[request.panel_id][request.value_id]
6365
return GetValueResponse(value=value)
6466

0 commit comments

Comments
 (0)