From b01d60002cd95fd3e20d8cc98a3666f4ee4d80e4 Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 20:32:03 +0100 Subject: [PATCH 1/9] fix `is_running_in_cloud` --- src/lightning_app/utilities/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lightning_app/utilities/cloud.py b/src/lightning_app/utilities/cloud.py index 20ab6d14827c9..a84eef30fa84d 100644 --- a/src/lightning_app/utilities/cloud.py +++ b/src/lightning_app/utilities/cloud.py @@ -39,4 +39,4 @@ def _sigterm_flow_handler(*_, app: "lightning_app.LightningApp"): def is_running_in_cloud() -> bool: """Returns True if the Lightning App is running in the cloud.""" - return "LIGHTNING_APP_STATE_URL" in os.environ + return "LIGHTNING_CLOUD_PROJECT_ID" in os.environ From e13993838ec24b2faea2931fcf2a7f169c656e9e Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 20:35:49 +0100 Subject: [PATCH 2/9] update test --- tests/tests_app/utilities/test_cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests_app/utilities/test_cloud.py b/tests/tests_app/utilities/test_cloud.py index 573ec46106b84..8fa115afc2cd7 100644 --- a/tests/tests_app/utilities/test_cloud.py +++ b/tests/tests_app/utilities/test_cloud.py @@ -10,7 +10,7 @@ def test_is_running_locally(): assert not is_running_in_cloud() -@mock.patch.dict(os.environ, {"LIGHTNING_APP_STATE_URL": "127.0.0.1"}) +@mock.patch.dict(os.environ, {"LIGHTNING_CLOUD_PROJECT_ID": "project-x"}) def test_is_running_cloud(): """We can determine if Lightning is running in the cloud.""" assert is_running_in_cloud() From 8fd6eb8bd8a0d86b2edb7803655361361d3c442a Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 22:13:02 +0100 Subject: [PATCH 3/9] wip --- src/lightning_app/components/multi_node/base.py | 2 +- src/lightning_app/runners/cloud.py | 5 +++-- src/lightning_app/utilities/app_helpers.py | 12 ++++++++++++ src/lightning_app/utilities/cloud.py | 16 ++++++++++++++++ src/lightning_app/utilities/load_app.py | 2 +- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/lightning_app/components/multi_node/base.py b/src/lightning_app/components/multi_node/base.py index 5662442b7375a..ac99abecff028 100644 --- a/src/lightning_app/components/multi_node/base.py +++ b/src/lightning_app/components/multi_node/base.py @@ -56,12 +56,12 @@ def run( """ super().__init__() if num_nodes > 1 and not is_running_in_cloud(): - num_nodes = 1 warnings.warn( f"You set {type(self).__name__}(num_nodes={num_nodes}, ...)` but this app is running locally." " We assume you are debugging and will ignore the `num_nodes` argument." " To run on multiple nodes in the cloud, launch your app with `--cloud`." ) + num_nodes = 1 self.ws = structures.List( *[ work_cls( diff --git a/src/lightning_app/runners/cloud.py b/src/lightning_app/runners/cloud.py index 6ef7770124aae..1f9bc8c5fff9b 100644 --- a/src/lightning_app/runners/cloud.py +++ b/src/lightning_app/runners/cloud.py @@ -63,7 +63,7 @@ from lightning_app.runners.runtime import Runtime from lightning_app.source_code import LocalSourceCodeDir from lightning_app.storage import Drive, Mount -from lightning_app.utilities.app_helpers import _is_headless, Logger +from lightning_app.utilities.app_helpers import _is_headless, Logger, _mock_is_running_in_cloud from lightning_app.utilities.cloud import _get_project from lightning_app.utilities.dependency_caching import get_hash from lightning_app.utilities.load_app import load_app_from_file @@ -530,7 +530,8 @@ def _project_has_sufficient_credits(self, project: V1Membership, app: Optional[L def load_app_from_file(cls, filepath: str) -> "LightningApp": """Load a LightningApp from a file, mocking the imports.""" try: - app = load_app_from_file(filepath, raise_exception=True, mock_imports=True) + with _mock_is_running_in_cloud(): + app = load_app_from_file(filepath, raise_exception=True, mock_imports=True) except FileNotFoundError as e: raise e except Exception: diff --git a/src/lightning_app/utilities/app_helpers.py b/src/lightning_app/utilities/app_helpers.py index 83b78e1929aa5..9a8d099828cfc 100644 --- a/src/lightning_app/utilities/app_helpers.py +++ b/src/lightning_app/utilities/app_helpers.py @@ -507,6 +507,18 @@ def _mock_missing_imports(): builtins.__import__ = original_fn +@contextmanager +def _mock_is_running_in_cloud(return_value: bool = True): + import lightning_app.utilities.cloud as cloud + original_fn = cloud.is_running_in_cloud + assert False + try: + cloud.is_running_in_cloud = lambda: return_value + yield + finally: + cloud.is_running_in_cloud = original_fn + + def is_static_method(klass_or_instance, attr) -> bool: return isinstance(inspect.getattr_static(klass_or_instance, attr), staticmethod) diff --git a/src/lightning_app/utilities/cloud.py b/src/lightning_app/utilities/cloud.py index a84eef30fa84d..3c9b60261ad39 100644 --- a/src/lightning_app/utilities/cloud.py +++ b/src/lightning_app/utilities/cloud.py @@ -1,5 +1,6 @@ import os import warnings +from contextlib import contextmanager from lightning_cloud.openapi import V1Membership @@ -40,3 +41,18 @@ def _sigterm_flow_handler(*_, app: "lightning_app.LightningApp"): def is_running_in_cloud() -> bool: """Returns True if the Lightning App is running in the cloud.""" return "LIGHTNING_CLOUD_PROJECT_ID" in os.environ + + +@contextmanager +def _pretend_running_in_cloud(): + global is_running_in_cloud + original = is_running_in_cloud + is_running_in_cloud = lambda: True + yield + is_running_in_cloud = original + + + +if __name__ == "__main__": + with _pretend_running_in_cloud(): + print(is_running_in_cloud()) \ No newline at end of file diff --git a/src/lightning_app/utilities/load_app.py b/src/lightning_app/utilities/load_app.py index 43a6776721cbb..2f08d1978d000 100644 --- a/src/lightning_app/utilities/load_app.py +++ b/src/lightning_app/utilities/load_app.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: from lightning_app import LightningApp, LightningFlow, LightningWork -from lightning_app.utilities.app_helpers import _mock_missing_imports, Logger +from lightning_app.utilities.app_helpers import _mock_missing_imports, Logger, _mock_is_running_in_cloud logger = Logger(__name__) From 6e76dc058afdef99c417efa36ffc52841f9694ad Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 21:24:46 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/lightning_app/runners/cloud.py | 2 +- src/lightning_app/utilities/app_helpers.py | 1 + src/lightning_app/utilities/cloud.py | 3 +-- src/lightning_app/utilities/load_app.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lightning_app/runners/cloud.py b/src/lightning_app/runners/cloud.py index 1f9bc8c5fff9b..3ef77b1350ec3 100644 --- a/src/lightning_app/runners/cloud.py +++ b/src/lightning_app/runners/cloud.py @@ -63,7 +63,7 @@ from lightning_app.runners.runtime import Runtime from lightning_app.source_code import LocalSourceCodeDir from lightning_app.storage import Drive, Mount -from lightning_app.utilities.app_helpers import _is_headless, Logger, _mock_is_running_in_cloud +from lightning_app.utilities.app_helpers import _is_headless, _mock_is_running_in_cloud, Logger from lightning_app.utilities.cloud import _get_project from lightning_app.utilities.dependency_caching import get_hash from lightning_app.utilities.load_app import load_app_from_file diff --git a/src/lightning_app/utilities/app_helpers.py b/src/lightning_app/utilities/app_helpers.py index 9a8d099828cfc..2cd2959207a30 100644 --- a/src/lightning_app/utilities/app_helpers.py +++ b/src/lightning_app/utilities/app_helpers.py @@ -510,6 +510,7 @@ def _mock_missing_imports(): @contextmanager def _mock_is_running_in_cloud(return_value: bool = True): import lightning_app.utilities.cloud as cloud + original_fn = cloud.is_running_in_cloud assert False try: diff --git a/src/lightning_app/utilities/cloud.py b/src/lightning_app/utilities/cloud.py index 3c9b60261ad39..7be548f9cc9b4 100644 --- a/src/lightning_app/utilities/cloud.py +++ b/src/lightning_app/utilities/cloud.py @@ -52,7 +52,6 @@ def _pretend_running_in_cloud(): is_running_in_cloud = original - if __name__ == "__main__": with _pretend_running_in_cloud(): - print(is_running_in_cloud()) \ No newline at end of file + print(is_running_in_cloud()) diff --git a/src/lightning_app/utilities/load_app.py b/src/lightning_app/utilities/load_app.py index 2f08d1978d000..bd10d51cccde0 100644 --- a/src/lightning_app/utilities/load_app.py +++ b/src/lightning_app/utilities/load_app.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: from lightning_app import LightningApp, LightningFlow, LightningWork -from lightning_app.utilities.app_helpers import _mock_missing_imports, Logger, _mock_is_running_in_cloud +from lightning_app.utilities.app_helpers import _mock_is_running_in_cloud, _mock_missing_imports, Logger logger = Logger(__name__) From 0846d4371a0c935c4cd06450b383d5d8bf19baf1 Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 22:29:58 +0100 Subject: [PATCH 5/9] update --- src/lightning_app/utilities/cloud.py | 17 +---------------- tests/tests_app/utilities/test_cloud.py | 2 +- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/lightning_app/utilities/cloud.py b/src/lightning_app/utilities/cloud.py index 3c9b60261ad39..702c9dc216c06 100644 --- a/src/lightning_app/utilities/cloud.py +++ b/src/lightning_app/utilities/cloud.py @@ -40,19 +40,4 @@ def _sigterm_flow_handler(*_, app: "lightning_app.LightningApp"): def is_running_in_cloud() -> bool: """Returns True if the Lightning App is running in the cloud.""" - return "LIGHTNING_CLOUD_PROJECT_ID" in os.environ - - -@contextmanager -def _pretend_running_in_cloud(): - global is_running_in_cloud - original = is_running_in_cloud - is_running_in_cloud = lambda: True - yield - is_running_in_cloud = original - - - -if __name__ == "__main__": - with _pretend_running_in_cloud(): - print(is_running_in_cloud()) \ No newline at end of file + return "LIGHTNING_APP_STATE_URL" in os.environ diff --git a/tests/tests_app/utilities/test_cloud.py b/tests/tests_app/utilities/test_cloud.py index 8fa115afc2cd7..573ec46106b84 100644 --- a/tests/tests_app/utilities/test_cloud.py +++ b/tests/tests_app/utilities/test_cloud.py @@ -10,7 +10,7 @@ def test_is_running_locally(): assert not is_running_in_cloud() -@mock.patch.dict(os.environ, {"LIGHTNING_CLOUD_PROJECT_ID": "project-x"}) +@mock.patch.dict(os.environ, {"LIGHTNING_APP_STATE_URL": "127.0.0.1"}) def test_is_running_cloud(): """We can determine if Lightning is running in the cloud.""" assert is_running_in_cloud() From 7db203dead6075b943aa71447decc52640d1f879 Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 23:06:07 +0100 Subject: [PATCH 6/9] nonsense --- src/lightning_app/runners/cloud.py | 10 +++++++--- src/lightning_app/utilities/app_helpers.py | 13 ------------- src/lightning_app/utilities/cloud.py | 3 +-- src/lightning_app/utilities/load_app.py | 2 +- tests/tests_app/utilities/test_cloud.py | 21 +++++++++++++-------- 5 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/lightning_app/runners/cloud.py b/src/lightning_app/runners/cloud.py index 3ef77b1350ec3..7b55b0f0cc60a 100644 --- a/src/lightning_app/runners/cloud.py +++ b/src/lightning_app/runners/cloud.py @@ -1,5 +1,6 @@ import fnmatch import json +import os import random import string import sys @@ -63,7 +64,7 @@ from lightning_app.runners.runtime import Runtime from lightning_app.source_code import LocalSourceCodeDir from lightning_app.storage import Drive, Mount -from lightning_app.utilities.app_helpers import _is_headless, _mock_is_running_in_cloud, Logger +from lightning_app.utilities.app_helpers import _is_headless, Logger from lightning_app.utilities.cloud import _get_project from lightning_app.utilities.dependency_caching import get_hash from lightning_app.utilities.load_app import load_app_from_file @@ -529,9 +530,12 @@ def _project_has_sufficient_credits(self, project: V1Membership, app: Optional[L @classmethod def load_app_from_file(cls, filepath: str) -> "LightningApp": """Load a LightningApp from a file, mocking the imports.""" + + # Pretend we are running in the cloud when loading the app locally + os.environ["LAI_RUNNING_IN_CLOUD"] = "1" + try: - with _mock_is_running_in_cloud(): - app = load_app_from_file(filepath, raise_exception=True, mock_imports=True) + app = load_app_from_file(filepath, raise_exception=True, mock_imports=True) except FileNotFoundError as e: raise e except Exception: diff --git a/src/lightning_app/utilities/app_helpers.py b/src/lightning_app/utilities/app_helpers.py index 2cd2959207a30..83b78e1929aa5 100644 --- a/src/lightning_app/utilities/app_helpers.py +++ b/src/lightning_app/utilities/app_helpers.py @@ -507,19 +507,6 @@ def _mock_missing_imports(): builtins.__import__ = original_fn -@contextmanager -def _mock_is_running_in_cloud(return_value: bool = True): - import lightning_app.utilities.cloud as cloud - - original_fn = cloud.is_running_in_cloud - assert False - try: - cloud.is_running_in_cloud = lambda: return_value - yield - finally: - cloud.is_running_in_cloud = original_fn - - def is_static_method(klass_or_instance, attr) -> bool: return isinstance(inspect.getattr_static(klass_or_instance, attr), staticmethod) diff --git a/src/lightning_app/utilities/cloud.py b/src/lightning_app/utilities/cloud.py index 702c9dc216c06..6db634649fdbb 100644 --- a/src/lightning_app/utilities/cloud.py +++ b/src/lightning_app/utilities/cloud.py @@ -1,6 +1,5 @@ import os import warnings -from contextlib import contextmanager from lightning_cloud.openapi import V1Membership @@ -40,4 +39,4 @@ def _sigterm_flow_handler(*_, app: "lightning_app.LightningApp"): def is_running_in_cloud() -> bool: """Returns True if the Lightning App is running in the cloud.""" - return "LIGHTNING_APP_STATE_URL" in os.environ + return bool(int(os.environ.get("LAI_RUNNING_IN_CLOUD", "0"))) or "LIGHTNING_APP_STATE_URL" in os.environ diff --git a/src/lightning_app/utilities/load_app.py b/src/lightning_app/utilities/load_app.py index bd10d51cccde0..43a6776721cbb 100644 --- a/src/lightning_app/utilities/load_app.py +++ b/src/lightning_app/utilities/load_app.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: from lightning_app import LightningApp, LightningFlow, LightningWork -from lightning_app.utilities.app_helpers import _mock_is_running_in_cloud, _mock_missing_imports, Logger +from lightning_app.utilities.app_helpers import _mock_missing_imports, Logger logger = Logger(__name__) diff --git a/tests/tests_app/utilities/test_cloud.py b/tests/tests_app/utilities/test_cloud.py index 573ec46106b84..6e93ad1e68d57 100644 --- a/tests/tests_app/utilities/test_cloud.py +++ b/tests/tests_app/utilities/test_cloud.py @@ -4,13 +4,18 @@ from lightning_app.utilities.cloud import is_running_in_cloud -@mock.patch.dict(os.environ, clear=True) -def test_is_running_locally(): - """We can determine if Lightning is running locally.""" - assert not is_running_in_cloud() - - -@mock.patch.dict(os.environ, {"LIGHTNING_APP_STATE_URL": "127.0.0.1"}) def test_is_running_cloud(): """We can determine if Lightning is running in the cloud.""" - assert is_running_in_cloud() + with mock.patch.dict(os.environ, {}, clear=True): + assert not is_running_in_cloud() + + with mock.patch.dict(os.environ, {"LAI_RUNNING_IN_CLOUD": "0"}, clear=True): + assert not is_running_in_cloud() + + # in the cloud, LIGHTNING_APP_STATE_URL is defined + with mock.patch.dict(os.environ, {"LIGHTNING_APP_STATE_URL": "defined"}, clear=True): + assert is_running_in_cloud() + + # LAI_RUNNING_IN_CLOUD is used to fake the value of `is_running_in_cloud` when loading the app for --cloud + with mock.patch.dict(os.environ, {"LAI_RUNNING_IN_CLOUD": "1"}): + assert is_running_in_cloud() From 6ae0921e9f5adfcb33bb268decf220f94b375a5e Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 23:10:58 +0100 Subject: [PATCH 7/9] changelog --- src/lightning_app/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lightning_app/CHANGELOG.md b/src/lightning_app/CHANGELOG.md index 8fffe362fdd04..f1113f0167163 100644 --- a/src/lightning_app/CHANGELOG.md +++ b/src/lightning_app/CHANGELOG.md @@ -13,7 +13,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Changed -- + +- The utility `lightning.app.utilities.cloud.is_running_in_cloud` now returns `True` during loading of the app locally when running with `--cloud` ([#16045](https://github.com/Lightning-AI/lightning/pull/16045)) ### Deprecated From 93c527b489d4bace66ad9d517ae21423cecc56ed Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 23:49:48 +0100 Subject: [PATCH 8/9] fix number --- tests/tests_app/components/multi_node/test_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests_app/components/multi_node/test_base.py b/tests/tests_app/components/multi_node/test_base.py index 8582047a2ff20..8fd4f28e679a0 100644 --- a/tests/tests_app/components/multi_node/test_base.py +++ b/tests/tests_app/components/multi_node/test_base.py @@ -13,7 +13,7 @@ class Work(LightningWork): def run(self): pass - with pytest.warns(UserWarning, match=escape("You set MultiNode(num_nodes=1, ...)` but ")): + with pytest.warns(UserWarning, match=escape("You set MultiNode(num_nodes=2, ...)` but ")): MultiNode(Work, num_nodes=2, cloud_compute=CloudCompute("gpu")) with no_warning_call(UserWarning, match=escape("You set MultiNode(num_nodes=1, ...)` but ")): From 6219e866dee85a1ecbd9275132ca32e3d58ed6ae Mon Sep 17 00:00:00 2001 From: awaelchli Date: Tue, 13 Dec 2022 23:53:48 +0100 Subject: [PATCH 9/9] clean up --- src/lightning_app/runners/cloud.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lightning_app/runners/cloud.py b/src/lightning_app/runners/cloud.py index 5dbacf8394dac..8c626ea453596 100644 --- a/src/lightning_app/runners/cloud.py +++ b/src/lightning_app/runners/cloud.py @@ -568,6 +568,8 @@ def load_app_from_file(cls, filepath: str) -> "LightningApp": # Create a generic app. logger.info("Could not load the app locally. Starting the app directly on the cloud.") app = LightningApp(EmptyFlow()) + finally: + del os.environ["LAI_RUNNING_IN_CLOUD"] return app @staticmethod