From 704b694f6e490fd9125256cef54a52d6a2394082 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 14:33:15 +0000 Subject: [PATCH 1/7] update --- src/lightning_app/core/flow.py | 10 +++++++++- tests/tests_app/structures/test_structures.py | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index de079238658a2..96cd90e6eef44 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -142,6 +142,14 @@ def __setattr__(self, name: str, value: Any) -> None: if name in self._works and value != getattr(self, name): raise AttributeError(f"Cannot set attributes as the work can't be changed once defined: {name}") + if isinstance(value, list): + if all(isinstance(va, (LightningFlow, LightningWork)) for va in value): + value = List(*value) + + if isinstance(value, dict): + if all(isinstance(va, (LightningFlow, LightningWork)) for va in value.values()): + value = Dict(**value) + if isinstance(value, LightningFlow): self._flows.add(name) _set_child_name(self, value, name) @@ -163,10 +171,10 @@ def __setattr__(self, name: str, value: Any) -> None: value._register_cloud_compute() elif isinstance(value, (Dict, List)): - value._backend = self._backend self._structures.add(name) _set_child_name(self, value, name) if self._backend: + value._backend = self._backend for flow in value.flows: LightningFlow._attach_backend(flow, self._backend) for work in value.works: diff --git a/tests/tests_app/structures/test_structures.py b/tests/tests_app/structures/test_structures.py index 9c7f492370635..30ce55ea2a2b3 100644 --- a/tests/tests_app/structures/test_structures.py +++ b/tests/tests_app/structures/test_structures.py @@ -518,3 +518,20 @@ def __init__(self): LightningApp(flow) # wrap in app to init all component names assert flow.list_structure[0].name == "root.list_structure.0" assert flow.dict_structure["dict_child"].name == "root.dict_structure.dict_child" + + +class FlowWiStructures(LightningFlow): + def __init__(self): + super().__init__() + + self.ws = [EmptyFlow(), EmptyFlow()] + + self.ws = {"a": EmptyFlow(), "b": EmptyFlow()} + + def run(self): + pass + + +def test_flow_without_structures(): + + FlowWiStructures() From 0293a04624b09f2b89490aca05397e420ac12d24 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 14:40:39 +0000 Subject: [PATCH 2/7] update --- src/lightning_app/core/flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index 96cd90e6eef44..a75e455ddd677 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -173,7 +173,7 @@ def __setattr__(self, name: str, value: Any) -> None: elif isinstance(value, (Dict, List)): self._structures.add(name) _set_child_name(self, value, name) - if self._backend: + if getattr(self, "_backend", None) is not None: value._backend = self._backend for flow in value.flows: LightningFlow._attach_backend(flow, self._backend) From d250a48e69f5a8c438e57e0c09efc16d5a4155ed Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 14:41:40 +0000 Subject: [PATCH 3/7] update --- tests/tests_app/structures/test_structures.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tests_app/structures/test_structures.py b/tests/tests_app/structures/test_structures.py index 30ce55ea2a2b3..4cbeb32b5a661 100644 --- a/tests/tests_app/structures/test_structures.py +++ b/tests/tests_app/structures/test_structures.py @@ -526,7 +526,7 @@ def __init__(self): self.ws = [EmptyFlow(), EmptyFlow()] - self.ws = {"a": EmptyFlow(), "b": EmptyFlow()} + self.ws1 = {"a": EmptyFlow(), "b": EmptyFlow()} def run(self): pass @@ -534,4 +534,6 @@ def run(self): def test_flow_without_structures(): - FlowWiStructures() + flow = FlowWiStructures() + assert isinstance(flow.ws, List) + assert isinstance(flow.ws1, Dict) From 8f5dc77c776051fbc8084652d5b1e6dd91a824d3 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 14:42:45 +0000 Subject: [PATCH 4/7] update --- src/lightning_app/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lightning_app/CHANGELOG.md b/src/lightning_app/CHANGELOG.md index 13b3bc7684dfe..74053303aabeb 100644 --- a/src/lightning_app/CHANGELOG.md +++ b/src/lightning_app/CHANGELOG.md @@ -28,6 +28,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added a `configure_layout` method to the `LightningWork` which can be used to control how the work is handled in the layout of a parent flow ([#15926](https://github.com/Lightning-AI/lightning/pull/15926)) +- Added automatic conversion of list and dict of works and flows to structures ([#15961](https://github.com/Lightning-AI/lightning/pull/15961)) + ### Changed From 05b57e4611eb9081b193e5b270514eba8c2146e4 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 14:49:22 +0000 Subject: [PATCH 5/7] update --- src/lightning_app/core/flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index a75e455ddd677..47f43bd4a386c 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -143,11 +143,11 @@ def __setattr__(self, name: str, value: Any) -> None: raise AttributeError(f"Cannot set attributes as the work can't be changed once defined: {name}") if isinstance(value, list): - if all(isinstance(va, (LightningFlow, LightningWork)) for va in value): + if value and all(isinstance(va, (LightningFlow, LightningWork)) for va in value): value = List(*value) if isinstance(value, dict): - if all(isinstance(va, (LightningFlow, LightningWork)) for va in value.values()): + if value and all(isinstance(va, (LightningFlow, LightningWork)) for va in value.values()): value = Dict(**value) if isinstance(value, LightningFlow): From 6d8ad29f41fe4e47abe6c4f0109f3a1b4e3856a4 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 15:17:22 +0000 Subject: [PATCH 6/7] update --- src/lightning_app/core/flow.py | 11 ++++++----- tests/tests_app/structures/test_structures.py | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index 47f43bd4a386c..1b4318b144626 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -142,13 +142,14 @@ def __setattr__(self, name: str, value: Any) -> None: if name in self._works and value != getattr(self, name): raise AttributeError(f"Cannot set attributes as the work can't be changed once defined: {name}") - if isinstance(value, list): - if value and all(isinstance(va, (LightningFlow, LightningWork)) for va in value): + if isinstance(value, (list, dict)) and value: + _type = (LightningFlow, LightningWork, List, Dict) + if isinstance(value, list) and all(isinstance(va, _type) for va in value): value = List(*value) - if isinstance(value, dict): - if value and all(isinstance(va, (LightningFlow, LightningWork)) for va in value.values()): - value = Dict(**value) + if isinstance(value, dict) and all(isinstance(va, _type) for va in value.values()): + if value and all(isinstance(va, _type) for va in value.values()): + value = Dict(**value) if isinstance(value, LightningFlow): self._flows.add(name) diff --git a/tests/tests_app/structures/test_structures.py b/tests/tests_app/structures/test_structures.py index 4cbeb32b5a661..3346da5a858fc 100644 --- a/tests/tests_app/structures/test_structures.py +++ b/tests/tests_app/structures/test_structures.py @@ -528,6 +528,13 @@ def __init__(self): self.ws1 = {"a": EmptyFlow(), "b": EmptyFlow()} + self.ws2 = { + "a": EmptyFlow(), + "b": EmptyFlow(), + "c": List(EmptyFlow(), EmptyFlow()), + "d": Dict(**{"a": EmptyFlow()}), + } + def run(self): pass From 94c7b1e8382fc2bf6cde559a67ff72d1262fe793 Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 8 Dec 2022 15:18:12 +0000 Subject: [PATCH 7/7] update --- src/lightning_app/core/flow.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lightning_app/core/flow.py b/src/lightning_app/core/flow.py index 1b4318b144626..a79794bac3d20 100644 --- a/src/lightning_app/core/flow.py +++ b/src/lightning_app/core/flow.py @@ -148,8 +148,7 @@ def __setattr__(self, name: str, value: Any) -> None: value = List(*value) if isinstance(value, dict) and all(isinstance(va, _type) for va in value.values()): - if value and all(isinstance(va, _type) for va in value.values()): - value = Dict(**value) + value = Dict(**value) if isinstance(value, LightningFlow): self._flows.add(name)