Skip to content

Commit c0bc164

Browse files
authored
Merge branch 'master' into feature/run-method-validation
2 parents 3e9d624 + 8f14184 commit c0bc164

File tree

6 files changed

+100
-8
lines changed

6 files changed

+100
-8
lines changed

src/lightning_app/CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
1010
### Added
1111

1212
- Add `load_state_dict` and `state_dict` ([#14100](https://github.com/Lightning-AI/lightning/pull/14100))
13+
14+
1315
- Add `--secret` option to CLI to allow binding Secrets to app environment variables when running in the cloud ([#14612](https://github.com/Lightning-AI/lightning/pull/14612))
1416

1517

1618
### Changed
1719

1820
- Application storage prefix moved from `app_id` to `project_id/app_id` ([#14583](https://github.com/Lightning-AI/lightning/pull/14583))
21+
22+
1923
- LightningCloud client calls to use key word arguments instead of positional arguments ([#14685](https://github.com/Lightning-AI/lightning/pull/14685)
2024

2125

@@ -25,22 +29,29 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
2529
- Improved the error messsage when the `LightningWork` is missing the `run` method ([#14759](https://github.com/Lightning-AI/lightning/pull/14759))
2630

2731

32+
- Improved the error messsage when the root `LightningFlow` passed to `LightningApp` is missing the `run` method ([#14760](https://github.com/Lightning-AI/lightning/pull/14760))
33+
34+
35+
2836

2937
### Fixed
3038

3139
- Making threadpool non default from LightningCloud client ([#14757](https://github.com/Lightning-AI/lightning/pull/14757))
3240

41+
3342
- Resolved a bug where the state change detection using DeepDiff won't worked with Path, Drive objects ([#14465](https://github.com/Lightning-AI/lightning/pull/14465))
3443

44+
3545
- Resolved a bug where the wrong client was passed to collect cloud logs ([#14684](https://github.com/Lightning-AI/lightning/pull/14684))
3646

47+
3748
- Resolved the memory leak issue with Lightning Cloud package and bumped the requirements to use the latest version ([#14697](https://github.com/Lightning-AI/lightning/pull/14697)
3849

3950

4051
- Unification of app template: moved `app.py` to root dir for `lightning init app <app_name>` template ([#13853](https://github.com/Lightning-AI/lightning/pull/13853))
4152

42-
- Fixing 5000 log line limitation for Lightning AI BYOC cluster logs ([#14458](https://github.com/Lightning-AI/lightning/pull/14458))
4353

54+
- Fixing 5000 log line limitation for Lightning AI BYOC cluster logs ([#14458](https://github.com/Lightning-AI/lightning/pull/14458))
4455

4556

4657
- Fixed a bug where the uploaded command file wasn't properly parsed ([#14532](https://github.com/Lightning-AI/lightning/pull/14532))
@@ -49,6 +60,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
4960
- Resolved `LightningApp(..., debug=True)` ([#14464](https://github.com/Lightning-AI/lightning/pull/14464))
5061

5162

63+
- Fixed an issue where custom property setters were not being used `LightningWork` class. ([#14259](https://github.com/Lightning-AI/lightning/pull/14259))
64+
65+
5266
## [0.6.0] - 2022-09-08
5367

5468
### Added

src/lightning_app/core/app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from lightning_app.storage.path import storage_root_dir
2727
from lightning_app.utilities.app_helpers import _delta_to_app_state_delta, _LightningAppRef, Logger
2828
from lightning_app.utilities.commands.base import _process_requests
29-
from lightning_app.utilities.component import _convert_paths_after_init
29+
from lightning_app.utilities.component import _convert_paths_after_init, _validate_root_flow
3030
from lightning_app.utilities.enum import AppStage, CacheCallsKeys
3131
from lightning_app.utilities.exceptions import CacheMissException, ExitAppException
3232
from lightning_app.utilities.layout import _collect_layout
@@ -58,8 +58,8 @@ def __init__(
5858
the :class:`~lightning.app.core.flow.LightningFlow` provided.
5959
6060
Arguments:
61-
root: The root LightningFlow component, that defined all
62-
the app's nested components, running infinitely.
61+
root: The root LightningFlow component, that defines all the app's nested components, running infinitely.
62+
It must define a `run()` method that the app can call.
6363
debug: Whether to activate the Lightning Logger debug mode.
6464
This can be helpful when reporting bugs on Lightning repo.
6565
@@ -77,6 +77,7 @@ def __init__(
7777
Hello World!
7878
"""
7979

80+
_validate_root_flow(root)
8081
self._root = root
8182

8283
# queues definition.

src/lightning_app/core/work.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import warnings
33
from copy import deepcopy
44
from functools import partial, wraps
5-
from typing import Any, Callable, Dict, List, Optional
5+
from typing import Any, Callable, Dict, List, Optional, Union
66

77
from deepdiff import DeepHash
88

@@ -316,9 +316,17 @@ def num_successes(self) -> int:
316316

317317
return has_succeeded_counter
318318

319+
def _get_property_if_exists(self, name: str) -> Union[property, None]:
320+
attr = getattr(self.__class__, name, None)
321+
return attr if isinstance(attr, property) else None
322+
319323
def __setattr__(self, name: str, value: Any) -> None:
320-
setattr_fn = getattr(self, "_setattr_replacement", None) or self._default_setattr
321-
setattr_fn(name, value)
324+
property_object = self._get_property_if_exists(name)
325+
if property_object is not None and property_object.fset is not None:
326+
property_object.fset(self, value)
327+
else:
328+
setattr_fn = getattr(self, "_setattr_replacement", None) or self._default_setattr
329+
setattr_fn(name, value)
322330

323331
def _default_setattr(self, name: str, value: Any) -> None:
324332
from lightning_app.core.flow import LightningFlow

src/lightning_app/utilities/component.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from deepdiff.helper import NotPresent
66
from lightning_utilities.core.apply_func import apply_to_collection
77

8+
from lightning_app.utilities.app_helpers import is_overridden
89
from lightning_app.utilities.enum import ComponentContext
910
from lightning_app.utilities.tree import breadth_first
1011

@@ -118,3 +119,13 @@ def _context(ctx: str) -> Generator[None, None, None]:
118119
_set_context(ctx)
119120
yield
120121
_set_context(prev)
122+
123+
124+
def _validate_root_flow(flow: "LightningFlow") -> None:
125+
from lightning_app.core.flow import LightningFlow
126+
127+
if not is_overridden("run", instance=flow, parent=LightningFlow):
128+
raise TypeError(
129+
"The root flow passed to `LightningApp` does not override the `run()` method. This is required. Please"
130+
f" implement `run()` in your `{flow.__class__.__name__}` class."
131+
)

tests/tests_app/core/test_lightning_app.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import os
33
import pickle
4+
from re import escape
45
from time import sleep
56
from unittest import mock
67
from unittest.mock import ANY
@@ -32,6 +33,29 @@
3233
logger = logging.getLogger()
3334

3435

36+
def test_lightning_app_requires_root_run_method():
37+
"""Test that a useful exception is raised if the root flow does not override the run method."""
38+
39+
with pytest.raises(
40+
TypeError, match=escape("The root flow passed to `LightningApp` does not override the `run()` method")
41+
):
42+
LightningApp(LightningFlow())
43+
44+
class FlowWithoutRun(LightningFlow):
45+
pass
46+
47+
with pytest.raises(
48+
TypeError, match=escape("The root flow passed to `LightningApp` does not override the `run()` method")
49+
):
50+
LightningApp(FlowWithoutRun())
51+
52+
class FlowWithRun(LightningFlow):
53+
def run(self):
54+
pass
55+
56+
LightningApp(FlowWithRun()) # no error
57+
58+
3559
class B1(LightningFlow):
3660
def __init__(self):
3761
super().__init__()

tests/tests_app/core/test_lightning_work.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from lightning_app import LightningApp
88
from lightning_app.core.flow import LightningFlow
9-
from lightning_app.core.work import LightningWork, LightningWorkException
9+
from lightning_app.core.work import BuildConfig, LightningWork, LightningWorkException
1010
from lightning_app.runners import MultiProcessRuntime
1111
from lightning_app.storage import Path
1212
from lightning_app.testing.helpers import EmptyFlow, EmptyWork, MockQueue
@@ -293,3 +293,37 @@ def run(self, *args, **kwargs):
293293
w.run(1, [2], (3, 4), {"1": "3"})
294294
assert len(w._calls) == 2
295295
assert w._calls["0d824f7"] == {"ret": None}
296+
297+
298+
def test_work_cloud_build_config_provided():
299+
300+
assert isinstance(LightningWork.cloud_build_config, property)
301+
assert LightningWork.cloud_build_config.fset is not None
302+
303+
class Work(LightningWork):
304+
def __init__(self):
305+
super().__init__()
306+
self.cloud_build_config = BuildConfig(image="ghcr.io/gridai/base-images:v1.8-cpu")
307+
308+
def run(self, *args, **kwargs):
309+
pass
310+
311+
w = Work()
312+
w.run()
313+
314+
315+
def test_work_local_build_config_provided():
316+
317+
assert isinstance(LightningWork.local_build_config, property)
318+
assert LightningWork.local_build_config.fset is not None
319+
320+
class Work(LightningWork):
321+
def __init__(self):
322+
super().__init__()
323+
self.local_build_config = BuildConfig(image="ghcr.io/gridai/base-images:v1.8-cpu")
324+
325+
def run(self, *args, **kwargs):
326+
pass
327+
328+
w = Work()
329+
w.run()

0 commit comments

Comments
 (0)