From 65901888faa4d02da3563aaccee64966bc29c4a4 Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 09:54:43 +0000 Subject: [PATCH 1/9] update --- src/lightning_app/core/app.py | 11 +++-- src/lightning_app/core/flow.py | 5 +++ tests/tests_app/core/test_lightning_flow.py | 47 ++++++++++++++++++++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/lightning_app/core/app.py b/src/lightning_app/core/app.py index 377a6a0d9e220..b40f1f0c91663 100644 --- a/src/lightning_app/core/app.py +++ b/src/lightning_app/core/app.py @@ -141,6 +141,7 @@ def __init__( self.threads: List[threading.Thread] = [] self.exception = None self.collect_changes: bool = True + self.ready = False # NOTE: Checkpointing is disabled by default for the time being. We # will enable it when resuming from full checkpoint is supported. Also, @@ -446,6 +447,9 @@ def run_once(self): done = True self.stage = AppStage.STOPPING + if not self.ready: + self.ready = self.root.ready + self._last_run_time = time() - t0 self.on_run_once_end() @@ -480,13 +484,12 @@ def _run(self) -> bool: """ self._original_state = deepcopy(self.state) done = False + self.ready = self.root.ready self._start_with_flow_works() - if self.should_publish_changes_to_api and self.api_publish_state_queue: + if self.ready and self.should_publish_changes_to_api and self.api_publish_state_queue: logger.debug("Publishing the state with changes") - # Push two states to optimize start in the cloud. - self.api_publish_state_queue.put(self.state_vars) self.api_publish_state_queue.put(self.state_vars) self._reset_run_time_monitor() @@ -496,7 +499,7 @@ def _run(self) -> bool: self._update_run_time_monitor() - if self._has_updated and self.should_publish_changes_to_api and self.api_publish_state_queue: + if self.ready and self._has_updated and self.should_publish_changes_to_api and self.api_publish_state_queue: self.api_publish_state_queue.put(self.state_vars) self._has_updated = False diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index 3773c7a0dd4f0..f357fa8ff93aa 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -230,6 +230,11 @@ def __getattr__(self, item): return Path.from_dict(self._paths[item]) return self.__getattribute__(item) + @property + def ready(self) -> bool: + flows = self.flows + return all(flow.ready for flow in flows.values()) if flows else True + @property def changes(self): return self._changes.copy() diff --git a/tests/tests_app/core/test_lightning_flow.py b/tests/tests_app/core/test_lightning_flow.py index c0cf780dc5eff..941081956398c 100644 --- a/tests/tests_app/core/test_lightning_flow.py +++ b/tests/tests_app/core/test_lightning_flow.py @@ -4,7 +4,7 @@ from copy import deepcopy from dataclasses import dataclass from time import time -from unittest.mock import ANY +from unittest.mock import ANY, MagicMock import pytest from deepdiff import DeepDiff, Delta @@ -859,3 +859,48 @@ def test_lightning_flow_flows_and_works(): "root.flows_dict.a.w", "root.flows_list.0.w", ] + + +class WorkReady(LightningWork): + def __init__(self): + super().__init__(parallel=True) + self.counter = 0 + + def run(self): + self.counter += 1 + + +class FlowReady(LightningFlow): + def __init__(self): + super().__init__() + self.w = WorkReady() + + @property + def ready(self) -> bool: + return self.w.has_succeeded + + def run(self): + self.w.run() + + if self.ready: + self._exit() + + +def test_flow_ready(): + """This test validates the api publish state queue is populated only when ready is True.""" + + def run_patch(method): + app.api_publish_state_queue = MagicMock() + app.should_publish_changes_to_api = False + method() + + from functools import partial + + app = LightningApp(FlowReady()) + app._run = partial(run_patch, method=app._run) + MultiProcessRuntime(app, start_server=False).dispatch() + + # Validates the state has been added only when ready was true. + state = app.api_publish_state_queue.put._mock_call_args[0][0] + call_hash = state["works"]["w"]["calls"]["latest_call_hash"] + assert state["works"]["w"]["calls"][call_hash]["statuses"][0]["stage"] == "succeeded" From b67beb41b1157626c0a42687d9c34b553d4c2bac Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 09:58:28 +0000 Subject: [PATCH 2/9] update --- src/lightning_app/CHANGELOG.md | 3 +++ tests/tests_app/core/test_lightning_flow.py | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lightning_app/CHANGELOG.md b/src/lightning_app/CHANGELOG.md index b3ab015ce44bc..ec7812e6e7417 100644 --- a/src/lightning_app/CHANGELOG.md +++ b/src/lightning_app/CHANGELOG.md @@ -12,10 +12,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added the CLI command `lightning delete app` to delete a lightning app on the cloud ([#15783](https://github.com/Lightning-AI/lightning/pull/15783)) - Show a message when `BuildConfig(requirements=[...])` is passed but a `requirements.txt` file is already present in the Work ([#15799](https://github.com/Lightning-AI/lightning/pull/15799)) + - Show a message when `BuildConfig(dockerfile="...")` is passed but a `Dockerfile` file is already present in the Work ([#15799](https://github.com/Lightning-AI/lightning/pull/15799)) - Added a CloudMultiProcessBackend which enables running a child App from within the Flow in the cloud ([#15800](https://github.com/Lightning-AI/lightning/pull/15800)) +- Added the property `ready` of the LightningFlow to inform when the `Open App` should be visible ([#15921](https://github.com/Lightning-AI/lightning/pull/15921)) + ### Changed diff --git a/tests/tests_app/core/test_lightning_flow.py b/tests/tests_app/core/test_lightning_flow.py index 941081956398c..ed668c12e9b1b 100644 --- a/tests/tests_app/core/test_lightning_flow.py +++ b/tests/tests_app/core/test_lightning_flow.py @@ -3,6 +3,7 @@ from collections import Counter from copy import deepcopy from dataclasses import dataclass +from functools import partial from time import time from unittest.mock import ANY, MagicMock @@ -887,15 +888,13 @@ def run(self): def test_flow_ready(): - """This test validates the api publish state queue is populated only when ready is True.""" + """This test validates the api publish state queue is populated only once ready is True.""" def run_patch(method): app.api_publish_state_queue = MagicMock() app.should_publish_changes_to_api = False method() - from functools import partial - app = LightningApp(FlowReady()) app._run = partial(run_patch, method=app._run) MultiProcessRuntime(app, start_server=False).dispatch() From af7a68bc77bc987f85cf7319589bb73276c341f4 Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 09:59:42 +0000 Subject: [PATCH 3/9] update --- src/lightning_app/core/flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index f357fa8ff93aa..72527bf7aee6f 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -232,6 +232,7 @@ def __getattr__(self, item): @property def ready(self) -> bool: + """Override to customize when your App should be ready.""" flows = self.flows return all(flow.ready for flow in flows.values()) if flows else True From 22fc7ea4f391405871f1e2afcf3036d8fbbc9bba Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 10:55:09 +0000 Subject: [PATCH 4/9] update --- examples/app_boring/app_dynamic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/app_boring/app_dynamic.py b/examples/app_boring/app_dynamic.py index cfd303505a0ed..97db842b9dc60 100644 --- a/examples/app_boring/app_dynamic.py +++ b/examples/app_boring/app_dynamic.py @@ -37,6 +37,12 @@ def __init__(self): super().__init__() self.dict = Dict() + @property + def ready(self) -> bool: + if "dst_w" in self.dict: + return self.dict["dst_w"].url is not None + return False + def run(self): # create dynamically the source_work at runtime if "src_w" not in self.dict: From 8ed5239bc0df24cff022665d2fd1d06ff6559908 Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 13:46:52 +0000 Subject: [PATCH 5/9] update --- examples/app_boring/app_dynamic.py | 4 ++-- src/lightning_app/core/app.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/app_boring/app_dynamic.py b/examples/app_boring/app_dynamic.py index 97db842b9dc60..4abb7023f4e3a 100644 --- a/examples/app_boring/app_dynamic.py +++ b/examples/app_boring/app_dynamic.py @@ -40,7 +40,7 @@ def __init__(self): @property def ready(self) -> bool: if "dst_w" in self.dict: - return self.dict["dst_w"].url is not None + return self.dict["dst_w"].url != "" return False def run(self): @@ -70,4 +70,4 @@ def configure_layout(self): return {"name": "Boring Tab", "content": self.dict["dst_w"].url + "/file" if "dst_w" in self.dict else ""} -app = L.LightningApp(BoringApp(), log_level="debug") +app = L.LightningApp(BoringApp()) # , log_level="debug") diff --git a/src/lightning_app/core/app.py b/src/lightning_app/core/app.py index b40f1f0c91663..ccf6030083a7c 100644 --- a/src/lightning_app/core/app.py +++ b/src/lightning_app/core/app.py @@ -489,7 +489,6 @@ def _run(self) -> bool: self._start_with_flow_works() if self.ready and self.should_publish_changes_to_api and self.api_publish_state_queue: - logger.debug("Publishing the state with changes") self.api_publish_state_queue.put(self.state_vars) self._reset_run_time_monitor() From 13e27a9c2448f2666080d3a98f696ee99210bc25 Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 13:47:29 +0000 Subject: [PATCH 6/9] update --- src/lightning_app/core/app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lightning_app/core/app.py b/src/lightning_app/core/app.py index ccf6030083a7c..42cf0f241b47e 100644 --- a/src/lightning_app/core/app.py +++ b/src/lightning_app/core/app.py @@ -141,6 +141,8 @@ def __init__( self.threads: List[threading.Thread] = [] self.exception = None self.collect_changes: bool = True + + # TODO: Enable ready locally for opening the UI. self.ready = False # NOTE: Checkpointing is disabled by default for the time being. We From 4d2f6f7f37a1c4fa6ebba0252693cb94c39c4ee1 Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 13:51:56 +0000 Subject: [PATCH 7/9] update --- examples/app_boring/app_dynamic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/app_boring/app_dynamic.py b/examples/app_boring/app_dynamic.py index 4abb7023f4e3a..5edb1f2898012 100644 --- a/examples/app_boring/app_dynamic.py +++ b/examples/app_boring/app_dynamic.py @@ -70,4 +70,4 @@ def configure_layout(self): return {"name": "Boring Tab", "content": self.dict["dst_w"].url + "/file" if "dst_w" in self.dict else ""} -app = L.LightningApp(BoringApp()) # , log_level="debug") +app = L.LightningApp(BoringApp(), log_level="debug") From 7a2ce1c5e0bcd056d663ebf7ad81ff2f258f2cda Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 14:57:08 +0000 Subject: [PATCH 8/9] update --- examples/lightning-quick-start | 1 + src/lightning_app/testing/testing.py | 12 +----------- 2 files changed, 2 insertions(+), 11 deletions(-) create mode 160000 examples/lightning-quick-start diff --git a/examples/lightning-quick-start b/examples/lightning-quick-start new file mode 160000 index 0000000000000..604580d74f03a --- /dev/null +++ b/examples/lightning-quick-start @@ -0,0 +1 @@ +Subproject commit 604580d74f03ab52e2e69224d41363723899e94a diff --git a/src/lightning_app/testing/testing.py b/src/lightning_app/testing/testing.py index 3e09012ac431c..8d112d7fa4a7a 100644 --- a/src/lightning_app/testing/testing.py +++ b/src/lightning_app/testing/testing.py @@ -362,17 +362,7 @@ def run_app_in_cloud( except playwright._impl._api_types.TimeoutError: print("'Create Project' dialog not visible, skipping.") - admin_page.locator(f"role=link[name='{name}']").click() - sleep(5) - # Scroll to the bottom of the page. Used to capture all logs. - admin_page.evaluate( - """ - var intervalID = setInterval(function () { - var scrollingElement = (document.scrollingElement || document.body); - scrollingElement.scrollTop = scrollingElement.scrollHeight; - }, 200); - """ - ) + admin_page.locator(f'[data-cy="{name}"]').click() client = LightningClient() project = _get_project(client) From 276e6abe0114c867e08a335f2980a34ddeaa80bf Mon Sep 17 00:00:00 2001 From: thomas chaton Date: Tue, 6 Dec 2022 14:57:29 +0000 Subject: [PATCH 9/9] update --- examples/lightning-quick-start | 1 - 1 file changed, 1 deletion(-) delete mode 160000 examples/lightning-quick-start diff --git a/examples/lightning-quick-start b/examples/lightning-quick-start deleted file mode 160000 index 604580d74f03a..0000000000000 --- a/examples/lightning-quick-start +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 604580d74f03ab52e2e69224d41363723899e94a