Skip to content

Commit acc1e9b

Browse files
Mike ProsserMike Prosser
authored andcommitted
GetValueResponse.found
1 parent 163735b commit acc1e9b

File tree

10 files changed

+45
-36
lines changed

10 files changed

+45
-36
lines changed

examples/simple_graph/simple_graph.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
# Generate and update the sine wave data periodically
2323
while True:
24+
# not-found values need to be performant
25+
not_found = panel.get_value("no_such_value", "Hello, World!")
26+
2427
amplitude_enum = panel.get_value("amplitude_enum", AmplitudeEnum.SMALL)
2528
base_frequency = panel.get_value("base_frequency", 1.0)
2629

protos/ni/pythonpanel/v1/python_panel_service.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ message GetValueRequest {
100100
message GetValueResponse {
101101
// The value
102102
google.protobuf.Any value = 1;
103+
104+
// Was the value found?
105+
bool found = 2;
103106
}
104107

105108
message SetValueRequest {

src/ni/pythonpanel/v1/python_panel_service_pb2.py

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

src/ni/pythonpanel/v1/python_panel_service_pb2.pyi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ class GetValueResponse(google.protobuf.message.Message):
162162
DESCRIPTOR: google.protobuf.descriptor.Descriptor
163163

164164
VALUE_FIELD_NUMBER: builtins.int
165+
FOUND_FIELD_NUMBER: builtins.int
166+
found: builtins.bool
167+
"""Was the value found?"""
165168
@property
166169
def value(self) -> google.protobuf.any_pb2.Any:
167170
"""The value"""
@@ -170,9 +173,10 @@ class GetValueResponse(google.protobuf.message.Message):
170173
self,
171174
*,
172175
value: google.protobuf.any_pb2.Any | None = ...,
176+
found: builtins.bool = ...,
173177
) -> None: ...
174178
def HasField(self, field_name: typing.Literal["value", b"value"]) -> builtins.bool: ...
175-
def ClearField(self, field_name: typing.Literal["value", b"value"]) -> None: ...
179+
def ClearField(self, field_name: typing.Literal["found", b"found", "value", b"value"]) -> None: ...
176180

177181
global___GetValueResponse = GetValueResponse
178182

src/nipanel/_panel_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def set_value(self, panel_id: str, value_id: str, value: object, notify: bool) -
116116
)
117117
self._invoke_with_retry(self._get_stub().SetValue, set_value_request)
118118

119-
def get_value(self, panel_id: str, value_id: str) -> object:
119+
def get_value(self, panel_id: str, value_id: str) -> tuple[bool, object]:
120120
"""Get the value for the control with value_id.
121121
122122
Args:
@@ -128,8 +128,10 @@ def get_value(self, panel_id: str, value_id: str) -> object:
128128
"""
129129
get_value_request = GetValueRequest(panel_id=panel_id, value_id=value_id)
130130
response = self._invoke_with_retry(self._get_stub().GetValue, get_value_request)
131+
if not response.found:
132+
return False, None
131133
the_value = from_any(response.value)
132-
return the_value
134+
return True, the_value
133135

134136
def _get_stub(self) -> PythonPanelServiceStub:
135137
if self._stub is None:

src/nipanel/_panel_value_accessor.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,25 +61,22 @@ def get_value(self, value_id: str, default_value: _T | None = None) -> _T | obje
6161
Returns:
6262
The value, or the default value if not set
6363
"""
64-
try:
65-
value = self._panel_client.get_value(self._panel_id, value_id)
66-
67-
if default_value is not None and not isinstance(value, type(default_value)):
68-
if isinstance(default_value, enum.Enum):
69-
enum_type = type(default_value)
70-
return enum_type(value)
64+
found, value = self._panel_client.get_value(self._panel_id, value_id)
65+
if not found:
66+
if default_value is not None:
67+
return default_value
68+
raise KeyError(f"Value with id '{value_id}' not found on panel '{self._panel_id}'.")
7169

72-
raise TypeError(
73-
f"Value type {type(value).__name__} does not match default value type {type(default_value).__name__}."
74-
)
70+
if default_value is not None and not isinstance(value, type(default_value)):
71+
if isinstance(default_value, enum.Enum):
72+
enum_type = type(default_value)
73+
return enum_type(value)
7574

76-
return value
75+
raise TypeError(
76+
f"Value type {type(value).__name__} does not match default value type {type(default_value).__name__}."
77+
)
7778

78-
except grpc.RpcError as e:
79-
if e.code() == grpc.StatusCode.NOT_FOUND and default_value is not None:
80-
return default_value
81-
else:
82-
raise e
79+
return value
8380

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

src/nipanel/_streamlit_panel_initializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def _initialize_panel_from_base_path() -> StreamlitPanelValueAccessor:
7979
return StreamlitPanelValueAccessor(panel_id)
8080

8181

82-
def _sync_session_state(panel):
82+
def _sync_session_state(panel: StreamlitPanelValueAccessor) -> None:
8383
"""Automatically read keyed control values from the session state."""
8484
for key in st.session_state.keys():
8585
value = st.session_state[key]

tests/unit/test_panel_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import grpc
2-
import pytest
32

43
from nipanel._panel_client import PanelClient
54

@@ -51,11 +50,12 @@ def test___start_panels___stop_panel_1_without_reset___enumerate_has_both_panels
5150
}
5251

5352

54-
def test___get_unset_value_raises_exception(fake_panel_channel: grpc.Channel) -> None:
53+
def test___get_unset_value___returns_not_found(fake_panel_channel: grpc.Channel) -> None:
5554
client = create_panel_client(fake_panel_channel)
5655

57-
with pytest.raises(Exception):
58-
client.get_value("panel1", "unset_id")
56+
response = client.get_value("panel1", "unset_id")
57+
58+
assert response == (False, None)
5959

6060

6161
def test___set_value___enumerate_panels_shows_value(
@@ -73,7 +73,7 @@ def test___set_value___gets_value(fake_panel_channel: grpc.Channel) -> None:
7373

7474
client.set_value("panel1", "val1", "value1", notify=False)
7575

76-
assert client.get_value("panel1", "val1") == "value1"
76+
assert client.get_value("panel1", "val1") == (True, "value1")
7777

7878

7979
def create_panel_client(fake_panel_channel: grpc.Channel) -> PanelClient:

tests/unit/test_streamlit_panel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def test___panel___get_unset_value_with_no_default___raises_exception(
131131
panel = StreamlitPanel("my_panel", "path/to/script", grpc_channel=fake_panel_channel)
132132

133133
value_id = "test_id"
134-
with pytest.raises(grpc.RpcError):
134+
with pytest.raises(KeyError):
135135
panel.get_value(value_id)
136136

137137

tests/utils/_fake_python_panel_servicer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ def EnumeratePanels( # noqa: N802
6262
def GetValue(self, request: GetValueRequest, context: Any) -> GetValueResponse: # noqa: N802
6363
"""Trivial implementation for testing."""
6464
if request.value_id not in self._panel_value_ids.get(request.panel_id, {}):
65-
context.abort(grpc.StatusCode.NOT_FOUND, "Value ID not found in panel")
65+
return GetValueResponse(found=False)
6666
value = self._panel_value_ids[request.panel_id][request.value_id]
67-
return GetValueResponse(value=value)
67+
return GetValueResponse(found=True, value=value)
6868

6969
def SetValue(self, request: SetValueRequest, context: Any) -> SetValueResponse: # noqa: N802
7070
"""Trivial implementation for testing."""

0 commit comments

Comments
 (0)