Skip to content

Commit d69e03e

Browse files
awaelchlirohitgr7
authored andcommitted
User-friendly exception if root flow does not override the run() method (#14760)
1 parent 76ec605 commit d69e03e

File tree

4 files changed

+43
-3
lines changed

4 files changed

+43
-3
lines changed

src/lightning_app/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
2222
- Improve Lightning App connect logic by disconnecting automatically ([#14532](https://github.com/Lightning-AI/lightning/pull/14532))
2323

2424

25+
- 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))
26+
27+
28+
2529
### Fixed
2630

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

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/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__()

0 commit comments

Comments
 (0)