Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/lightning_app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Improve Lightning App connect logic by disconnecting automatically ([#14532](https://github.com/Lightning-AI/lightning/pull/14532))


- 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))



### Fixed

- Making threadpool non default from LightningCloud client ([#14757](https://github.com/Lightning-AI/lightning/pull/14757))
Expand Down
7 changes: 4 additions & 3 deletions src/lightning_app/core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from lightning_app.storage.path import storage_root_dir
from lightning_app.utilities.app_helpers import _delta_to_app_state_delta, _LightningAppRef, Logger
from lightning_app.utilities.commands.base import _process_requests
from lightning_app.utilities.component import _convert_paths_after_init
from lightning_app.utilities.component import _convert_paths_after_init, _validate_root_flow
from lightning_app.utilities.enum import AppStage, CacheCallsKeys
from lightning_app.utilities.exceptions import CacheMissException, ExitAppException
from lightning_app.utilities.layout import _collect_layout
Expand Down Expand Up @@ -58,8 +58,8 @@ def __init__(
the :class:`~lightning.app.core.flow.LightningFlow` provided.

Arguments:
root: The root LightningFlow component, that defined all
the app's nested components, running infinitely.
root: The root LightningFlow component, that defines all the app's nested components, running infinitely.
It must define a `run()` method that the app can call.
debug: Whether to activate the Lightning Logger debug mode.
This can be helpful when reporting bugs on Lightning repo.

Expand All @@ -77,6 +77,7 @@ def __init__(
Hello World!
"""

_validate_root_flow(root)
self._root = root

# queues definition.
Expand Down
11 changes: 11 additions & 0 deletions src/lightning_app/utilities/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from deepdiff.helper import NotPresent
from lightning_utilities.core.apply_func import apply_to_collection

from lightning_app.utilities.app_helpers import is_overridden
from lightning_app.utilities.enum import ComponentContext
from lightning_app.utilities.tree import breadth_first

Expand Down Expand Up @@ -118,3 +119,13 @@ def _context(ctx: str) -> Generator[None, None, None]:
_set_context(ctx)
yield
_set_context(prev)


def _validate_root_flow(flow: "LightningFlow") -> None:
from lightning_app.core.flow import LightningFlow

if not is_overridden("run", instance=flow, parent=LightningFlow):
raise TypeError(
"The root flow passed to `LightningApp` does not override the `run()` method. This is required. Please"
f" implement `run()` in your `{flow.__class__.__name__}` class."
)
24 changes: 24 additions & 0 deletions tests/tests_app/core/test_lightning_app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import os
import pickle
from re import escape
from time import sleep
from unittest import mock
from unittest.mock import ANY
Expand Down Expand Up @@ -32,6 +33,29 @@
logger = logging.getLogger()


def test_lightning_app_requires_root_run_method():
"""Test that a useful exception is raised if the root flow does not override the run method."""

with pytest.raises(
TypeError, match=escape("The root flow passed to `LightningApp` does not override the `run()` method")
):
LightningApp(LightningFlow())

class FlowWithoutRun(LightningFlow):
pass

with pytest.raises(
TypeError, match=escape("The root flow passed to `LightningApp` does not override the `run()` method")
):
LightningApp(FlowWithoutRun())

class FlowWithRun(LightningFlow):
def run(self):
pass

LightningApp(FlowWithRun()) # no error


class B1(LightningFlow):
def __init__(self):
super().__init__()
Expand Down