def test_attach_plugin(): """Test how plugins get attached to the AppState and the default behavior when no plugin is specified.""" app_state = AppState() assert isinstance(app_state._plugin, AppStatePlugin) app_state = AppState(plugin=_CustomAppStatePlugin()) assert isinstance(app_state._plugin, _CustomAppStatePlugin)
def test_app_state_not_connected(_): """Test an error message when a disconnected AppState tries to access attributes.""" state = AppState() with pytest.raises(AttributeError, match="Failed to connect and fetch the app state"): _ = state.value with pytest.raises(AttributeError, match="Failed to connect and fetch the app state"): state.value = 1
def run(self): state = AppState() assert state._my_affiliation == ("work_a",) # this would download and push data to the REST API. assert state.var_a == 0 assert isinstance(state.drive, Drive) assert state.drive.component_name == "root.work_a" with open("test_app_state_api.txt", "w") as f: f.write("here") state.drive.put("test_app_state_api.txt") state.var_a = -1
def test_app_state_connection_error(_): """Test an error message when a connection to retrieve the state can't be established.""" app_state = AppState() with pytest.raises( AttributeError, match= r"Failed to connect and fetch the app state\. Is the app running?" ): app_state._request_state() with pytest.raises( AttributeError, match= r"Failed to connect and fetch the app state\. Is the app running?" ): app_state.var = 1
def render_fn(state: AppState): import streamlit as st should_print = st.button("Should print to the terminal ?") if should_print: state.should_print = not state.should_print st.write("Currently printing." if state. should_print else "Currently waiting to print.")
def test_app_state_state_access(): """Test the many ways an AppState object can be accessed to set or get attributes on the state.""" mocked_state = dict( vars=dict(root_var="root"), flows=dict(child0=dict( vars=dict(child_var=1), flows=dict(), works=dict(), )), works=dict(work0=dict( vars=dict(work_var=2), flows=dict(), works=dict(), )), ) state = AppState() state._state = state._last_state = mocked_state assert state.root_var == "root" assert isinstance(state.child0, AppState) assert isinstance(state.work0, AppState) assert state.child0.child_var == 1 assert state.work0.work_var == 2 with pytest.raises( AttributeError, match="Failed to access 'non_existent_var' through `AppState`."): _ = state.work0.non_existent_var with pytest.raises( AttributeError, match="Failed to access 'non_existent_var' through `AppState`."): state.work0.non_existent_var = 22 # TODO: improve msg with pytest.raises(AttributeError, match="You shouldn't set the flows"): state.child0 = "child0" # TODO: verify with tchaton with pytest.raises(AttributeError, match="You shouldn't set the works"): state.work0 = "work0"
async def _make_request(self, fn: Callable, *args, **kwargs): from lightning_app.utilities.state import AppState state = AppState() state._request_state() fn(state, *args, **kwargs) state.send_delta()
def test_app_state_bool(): app_state = AppState() assert not bool(app_state) app_state = AppState() app_state._store_state(dict(vars=dict(x=1, y=2))) assert bool(app_state)
def test_get_send_request(monkeypatch): app = LightningApp(Flow()) monkeypatch.setattr(lightning_app.utilities.state, "_configure_session", mock.MagicMock()) state = AppState(plugin=AppStatePlugin()) state._session.get._mock_return_value = MockResponse( app.state_with_changes, 500) state._request_state() state._session.get._mock_return_value = MockResponse( app.state_with_changes, 200) state._request_state() assert state._my_affiliation == () with pytest.raises(Exception, match="The response from"): state._session.post._mock_return_value = MockResponse( app.state_with_changes, 500) state.w.counter = 1 state._session.post._mock_return_value = MockResponse( app.state_with_changes, 200) state.w.counter = 1
"""This file gets run by streamlit, which we launch within Lightning. From here, we will call the render function that the user provided in ``configure_layout``. """ import os import pydoc from typing import Callable, Union from lightning_app.core.flow import LightningFlow from lightning_app.utilities.app_helpers import StreamLitStatePlugin from lightning_app.utilities.state import AppState app_state = AppState(plugin=StreamLitStatePlugin()) def _get_render_fn_from_environment() -> Callable: render_fn_name = os.environ["LIGHTNING_RENDER_FUNCTION"] render_fn_module_file = os.environ["LIGHTNING_RENDER_MODULE_FILE"] module = pydoc.importfile(render_fn_module_file) return getattr(module, render_fn_name) def _app_state_to_flow_scope(state: AppState, flow: Union[str, LightningFlow]) -> AppState: """Returns a new AppState with the scope reduced to the given flow, as if the given flow as the root.""" flow_name = flow.name if isinstance(flow, LightningFlow) else flow flow_name_parts = flow_name.split(".")[1:] # exclude root flow_state = state for part in flow_name_parts: flow_state = getattr(flow_state, part) return flow_state
def update_state(self): state = AppState() # this would download and push data to the REST API. assert state.a.work_a.var_a == 0 assert state.var_a == 0 state.var_a = -1
def test_app_state_state_access_under_affiliation(*_): """Test the access to attributes when the state is restricted under the given affiliation.""" mocked_state = dict( vars=dict(root_var="root"), flows=dict(child0=dict( vars=dict(child0_var=0), flows=dict(child1=dict( vars=dict(child1_var=1), flows=dict(child2=dict( vars=dict(child2_var=2), flows=dict(), works=dict(), ), ), works=dict(), ), ), works=dict(work1=dict(vars=dict(work1_var=11), ), ), ), ), works=dict(), ) # root-level affiliation state = AppState(my_affiliation=()) state._store_state(mocked_state) assert isinstance(state.child0, AppState) assert state.child0.child0_var == 0 assert state.child0.child1.child1_var == 1 assert state.child0.child1.child2.child2_var == 2 # one child deep state = AppState(my_affiliation=("child0", )) state._store_state(mocked_state) assert state._state == mocked_state["flows"]["child0"] with pytest.raises(AttributeError, match="Failed to access 'child0' through `AppState`"): _ = state.child0 assert state.child0_var == 0 assert state.child1.child1_var == 1 assert state.child1.child2.child2_var == 2 # two flows deep state = AppState(my_affiliation=("child0", "child1")) state._store_state(mocked_state) assert state._state == mocked_state["flows"]["child0"]["flows"]["child1"] with pytest.raises(AttributeError, match="Failed to access 'child1' through `AppState`"): _ = state.child1 state.child1_var = 111 assert state.child1_var == 111 assert state.child2.child2_var == 2 # access to work state = AppState(my_affiliation=("child0", "work1")) state._store_state(mocked_state) assert state._state == mocked_state["flows"]["child0"]["works"]["work1"] with pytest.raises(AttributeError, match="Failed to access 'child1' through `AppState`"): _ = state.child1 assert state.work1_var == 11 state.work1_var = 111 assert state.work1_var == 111 # affiliation does not match state state = AppState(my_affiliation=("child1", "child0")) with pytest.raises( ValueError, match=escape( "Failed to extract the state under the affiliation '('child1', 'child0')'" )): state._store_state(mocked_state)
def test_app_state_affiliation(_, my_affiliation, global_affiliation, expected): AppState._MY_AFFILIATION = global_affiliation state = AppState(my_affiliation=my_affiliation) assert state._my_affiliation == expected AppState._MY_AFFILIATION = ()
def test_app_state_with_no_env_var(**__): state = AppState() assert state._host == "http://127.0.0.1" assert state._port == 7501 assert state._url == "http://127.0.0.1:7501"
def test_app_state_with_env_var(**__): state = AppState() assert state._host == "https://lightning-cloud.com" assert not state._port assert state._url == "https://lightning-cloud.com"
def test_app_state_repr(): app_state = AppState() assert repr(app_state) == "None" app_state = AppState() app_state._store_state(dict(vars=dict(x=1, y=2))) assert repr(app_state) == "{'vars': {'x': 1, 'y': 2}}" app_state = AppState() app_state._store_state(dict(vars=dict(x=1, y=2))) assert repr(app_state.y) == "2" app_state = AppState() app_state._store_state( dict(vars={}, flows=dict(child=dict(vars=dict(child_var="child_val"))))) assert repr(app_state.child) == "{'vars': {'child_var': 'child_val'}}"