FlowerPower 1.0.0b2__py3-none-any.whl → 1.0.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flowerpower/__init__.py +2 -3
- flowerpower/cfg/__init__.py +10 -8
- flowerpower/cfg/pipeline/__init__.py +11 -7
- flowerpower/cfg/project/__init__.py +11 -8
- flowerpower/cfg/project/job_queue.py +10 -29
- flowerpower/cli/__init__.py +62 -28
- flowerpower/cli/job_queue.py +306 -123
- flowerpower/cli/mqtt.py +22 -16
- flowerpower/cli/pipeline.py +294 -114
- flowerpower/flowerpower.py +14 -8
- flowerpower/fs/__init__.py +7 -3
- flowerpower/fs/ext.py +6 -2
- flowerpower/io/base.py +17 -10
- flowerpower/io/loader/_duckdb.py +1 -0
- flowerpower/io/loader/deltatable.py +6 -2
- flowerpower/io/saver/deltatable.py +1 -2
- flowerpower/job_queue/__init__.py +16 -12
- flowerpower/job_queue/apscheduler/__init__.py +1 -1
- flowerpower/job_queue/apscheduler/manager.py +11 -6
- flowerpower/job_queue/apscheduler/utils.py +6 -4
- flowerpower/job_queue/base.py +1 -0
- flowerpower/job_queue/rq/__init__.py +1 -1
- flowerpower/job_queue/rq/manager.py +12 -3
- flowerpower/pipeline/io.py +11 -9
- flowerpower/pipeline/job_queue.py +5 -5
- flowerpower/pipeline/manager.py +35 -27
- flowerpower/pipeline/registry.py +26 -16
- flowerpower/pipeline/runner.py +3 -4
- flowerpower/plugins/mqtt/__init__.py +7 -7
- flowerpower/plugins/mqtt/cfg.py +3 -2
- flowerpower/plugins/mqtt/manager.py +25 -23
- flowerpower/utils/misc.py +6 -4
- flowerpower/utils/templates.py +1 -4
- {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b3.dist-info}/METADATA +1 -1
- {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b3.dist-info}/RECORD +38 -38
- {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b3.dist-info}/WHEEL +0 -0
- {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b3.dist-info}/entry_points.txt +0 -0
- {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b3.dist-info}/top_level.txt +0 -0
flowerpower/pipeline/manager.py
CHANGED
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
5
5
|
from types import TracebackType
|
6
6
|
from typing import Any, Callable, TypeVar, Union
|
7
7
|
from uuid import UUID
|
8
|
+
|
8
9
|
import duration_parser
|
9
10
|
from loguru import logger
|
10
11
|
from munch import Munch
|
@@ -22,9 +23,9 @@ from ..cfg.project.adapter import AdapterConfig as ProjectAdapterConfig
|
|
22
23
|
from ..fs import AbstractFileSystem, BaseStorageOptions, get_filesystem
|
23
24
|
from ..utils.logging import setup_logging
|
24
25
|
from .io import PipelineIOManager
|
25
|
-
from .registry import PipelineRegistry, HookType
|
26
|
-
from .runner import PipelineRunner, run_pipeline
|
27
26
|
from .job_queue import PipelineJobQueue
|
27
|
+
from .registry import HookType, PipelineRegistry
|
28
|
+
from .runner import PipelineRunner, run_pipeline
|
28
29
|
from .visualizer import PipelineVisualizer
|
29
30
|
|
30
31
|
setup_logging()
|
@@ -416,7 +417,6 @@ class PipelineManager:
|
|
416
417
|
retry_delay: float | None = None,
|
417
418
|
jitter_factor: float | None = None,
|
418
419
|
retry_exceptions: tuple | list | None = None,
|
419
|
-
|
420
420
|
) -> dict[str, Any]:
|
421
421
|
"""Execute a pipeline synchronously and return its results.
|
422
422
|
|
@@ -495,7 +495,7 @@ class PipelineManager:
|
|
495
495
|
pipeline_adapter_cfg=pipeline_adapter_cfg,
|
496
496
|
project_adapter_cfg=project_adapter_cfg,
|
497
497
|
adapter=adapter,
|
498
|
-
#reload=reload, # Runner handles module reload if needed
|
498
|
+
# reload=reload, # Runner handles module reload if needed
|
499
499
|
log_level=log_level,
|
500
500
|
max_retries=max_retries,
|
501
501
|
retry_delay=retry_delay,
|
@@ -649,7 +649,7 @@ class PipelineManager:
|
|
649
649
|
>>>
|
650
650
|
>>> manager = PipelineManager()
|
651
651
|
>>> manager.show_pipelines()
|
652
|
-
|
652
|
+
|
653
653
|
"""
|
654
654
|
self.registry.show_pipelines()
|
655
655
|
|
@@ -706,21 +706,25 @@ class PipelineManager:
|
|
706
706
|
ml_pipeline: streaming
|
707
707
|
"""
|
708
708
|
return self.registry.summary
|
709
|
-
|
709
|
+
|
710
710
|
def add_hook(
|
711
|
-
|
712
|
-
|
711
|
+
self,
|
712
|
+
name: str,
|
713
|
+
type: HookType,
|
714
|
+
to: str | None,
|
715
|
+
function_name: str | None,
|
716
|
+
) -> None:
|
713
717
|
"""Add a hook to the pipeline module.
|
714
|
-
|
718
|
+
|
715
719
|
Args:
|
716
720
|
name (str): The name of the pipeline
|
717
721
|
type (HookType): The type of the hook.
|
718
722
|
to (str | None, optional): The name of the file to add the hook to. Defaults to the hook.py file in the pipelines hooks folder.
|
719
723
|
function_name (str | None, optional): The name of the function. If not provided uses default name of hook type.
|
720
|
-
|
724
|
+
|
721
725
|
Returns:
|
722
726
|
None
|
723
|
-
|
727
|
+
|
724
728
|
Raises:
|
725
729
|
ValueError: If the hook type is not valid
|
726
730
|
|
@@ -734,7 +738,7 @@ class PipelineManager:
|
|
734
738
|
... to="pre_execute_hook",
|
735
739
|
... function_name="my_pre_execute_function"
|
736
740
|
... )
|
737
|
-
|
741
|
+
"""
|
738
742
|
self.registry.add_hook(
|
739
743
|
name=name,
|
740
744
|
type=type,
|
@@ -748,7 +752,7 @@ class PipelineManager:
|
|
748
752
|
name: str,
|
749
753
|
base_dir: str,
|
750
754
|
src_fs: AbstractFileSystem | None = None,
|
751
|
-
storage_options: BaseStorageOptions | None =
|
755
|
+
storage_options: dict | BaseStorageOptions | None = {},
|
752
756
|
overwrite: bool = False,
|
753
757
|
) -> None:
|
754
758
|
"""Import a pipeline from another FlowerPower project.
|
@@ -807,7 +811,7 @@ class PipelineManager:
|
|
807
811
|
pipelines: dict[str, str] | list[str],
|
808
812
|
base_dir: str, # Base dir for source if pipelines is a list
|
809
813
|
src_fs: AbstractFileSystem | None = None,
|
810
|
-
src_storage_options: BaseStorageOptions | None =
|
814
|
+
src_storage_options: dict | BaseStorageOptions | None = {},
|
811
815
|
overwrite: bool = False,
|
812
816
|
) -> None:
|
813
817
|
"""Import multiple pipelines from another project or location.
|
@@ -867,7 +871,7 @@ class PipelineManager:
|
|
867
871
|
self,
|
868
872
|
base_dir: str,
|
869
873
|
src_fs: AbstractFileSystem | None = None,
|
870
|
-
src_storage_options: BaseStorageOptions | None =
|
874
|
+
src_storage_options: dict | BaseStorageOptions | None = {},
|
871
875
|
overwrite: bool = False,
|
872
876
|
) -> None:
|
873
877
|
"""Import all pipelines from another FlowerPower project.
|
@@ -911,7 +915,7 @@ class PipelineManager:
|
|
911
915
|
name: str,
|
912
916
|
base_dir: str,
|
913
917
|
dest_fs: AbstractFileSystem | None = None,
|
914
|
-
dest_storage_options: BaseStorageOptions | None =
|
918
|
+
dest_storage_options: dict | BaseStorageOptions | None = {},
|
915
919
|
overwrite: bool = False,
|
916
920
|
) -> None:
|
917
921
|
"""Export a pipeline to another location or project.
|
@@ -970,7 +974,7 @@ class PipelineManager:
|
|
970
974
|
pipelines: list[str],
|
971
975
|
base_dir: str,
|
972
976
|
dest_fs: AbstractFileSystem | None = None,
|
973
|
-
dest_storage_options: BaseStorageOptions | None =
|
977
|
+
dest_storage_options: dict | BaseStorageOptions | None = {},
|
974
978
|
overwrite: bool = False,
|
975
979
|
) -> None:
|
976
980
|
"""Export multiple pipelines to another location.
|
@@ -1024,7 +1028,7 @@ class PipelineManager:
|
|
1024
1028
|
self,
|
1025
1029
|
base_dir: str,
|
1026
1030
|
dest_fs: AbstractFileSystem | None = None,
|
1027
|
-
dest_storage_options: BaseStorageOptions | None =
|
1031
|
+
dest_storage_options: dict | BaseStorageOptions | None = {},
|
1028
1032
|
overwrite: bool = False,
|
1029
1033
|
) -> None:
|
1030
1034
|
"""Export all pipelines to another location.
|
@@ -1206,7 +1210,7 @@ class PipelineManager:
|
|
1206
1210
|
retry_delay (float): Delay between retries in seconds.
|
1207
1211
|
jitter_factor (float): Random jitter factor to add to retry delay
|
1208
1212
|
retry_exceptions (tuple): Exceptions that trigger a retry.
|
1209
|
-
|
1213
|
+
|
1210
1214
|
**kwargs: JobQueue-specific arguments
|
1211
1215
|
For RQ:
|
1212
1216
|
- queue_name: Queue to use (str)
|
@@ -1252,7 +1256,7 @@ class PipelineManager:
|
|
1252
1256
|
pipeline_adapter_cfg=pipeline_adapter_cfg,
|
1253
1257
|
project_adapter_cfg=project_adapter_cfg,
|
1254
1258
|
adapter=adapter,
|
1255
|
-
#reload=reload,
|
1259
|
+
# reload=reload,
|
1256
1260
|
log_level=log_level,
|
1257
1261
|
max_retries=max_retries,
|
1258
1262
|
retry_delay=retry_delay,
|
@@ -1277,7 +1281,7 @@ class PipelineManager:
|
|
1277
1281
|
log_level: str | None = None,
|
1278
1282
|
result_ttl: int | dt.timedelta = 0,
|
1279
1283
|
run_at: dt.datetime | str | None = None,
|
1280
|
-
run_in: dt.datetime |
|
1284
|
+
run_in: dt.datetime | str | None = None,
|
1281
1285
|
max_retries: int = 3,
|
1282
1286
|
retry_delay: float = 1.0,
|
1283
1287
|
jitter_factor: float = 0.1,
|
@@ -1345,9 +1349,12 @@ class PipelineManager:
|
|
1345
1349
|
|
1346
1350
|
"""
|
1347
1351
|
run_func = self._get_run_func_for_job(name, reload)
|
1348
|
-
run_in =
|
1349
|
-
|
1350
|
-
|
1352
|
+
run_in = (
|
1353
|
+
duration_parser.parse(run_in) if isinstance(run_in, str) else run_in
|
1354
|
+
) # convert to seconds
|
1355
|
+
run_at = (
|
1356
|
+
dt.datetime.fromisoformat(run_at) if isinstance(run_at, str) else run_at
|
1357
|
+
)
|
1351
1358
|
|
1352
1359
|
return self.job_queue.add_job(
|
1353
1360
|
run_func=run_func,
|
@@ -1362,7 +1369,7 @@ class PipelineManager:
|
|
1362
1369
|
pipeline_adapter_cfg=pipeline_adapter_cfg,
|
1363
1370
|
project_adapter_cfg=project_adapter_cfg,
|
1364
1371
|
adapter=adapter,
|
1365
|
-
#reload=reload, # Note: reload already happened
|
1372
|
+
# reload=reload, # Note: reload already happened
|
1366
1373
|
log_level=log_level,
|
1367
1374
|
result_ttl=result_ttl,
|
1368
1375
|
run_at=run_at,
|
@@ -1476,7 +1483,9 @@ class PipelineManager:
|
|
1476
1483
|
"""
|
1477
1484
|
pipeline_cfg = self._load_pipeline_cfg(name=name, reload=reload)
|
1478
1485
|
run_func = self._get_run_func_for_job(name, reload)
|
1479
|
-
interval =
|
1486
|
+
interval = (
|
1487
|
+
duration_parser.parse(interval) if isinstance(interval, str) else interval
|
1488
|
+
)
|
1480
1489
|
date = dt.datetime.fromisoformat(date) if isinstance(date, str) else date
|
1481
1490
|
|
1482
1491
|
return self.job_queue.schedule(
|
@@ -1583,4 +1592,3 @@ class PipelineManager:
|
|
1583
1592
|
except Exception as e:
|
1584
1593
|
logger.error(f"Failed to retrieve schedules: {e}")
|
1585
1594
|
return []
|
1586
|
-
|
flowerpower/pipeline/registry.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""Pipeline Registry for discovery, listing, creation, and deletion."""
|
3
|
-
|
3
|
+
|
4
4
|
import datetime as dt
|
5
|
+
import os
|
5
6
|
import posixpath
|
6
7
|
from typing import TYPE_CHECKING
|
7
8
|
|
@@ -14,12 +15,14 @@ from rich.table import Table
|
|
14
15
|
from rich.tree import Tree
|
15
16
|
|
16
17
|
from .. import settings
|
18
|
+
|
17
19
|
# Import necessary config types and utility functions
|
18
20
|
from ..cfg import PipelineConfig, ProjectConfig
|
19
21
|
from ..fs import AbstractFileSystem
|
20
22
|
from ..utils.logging import setup_logging
|
23
|
+
|
21
24
|
# Assuming view_img might be used indirectly or needed later
|
22
|
-
from ..utils.templates import
|
25
|
+
from ..utils.templates import HOOK_TEMPLATE__MQTT_BUILD_CONFIG, PIPELINE_PY_TEMPLATE
|
23
26
|
|
24
27
|
if TYPE_CHECKING:
|
25
28
|
# Keep this for type hinting if needed elsewhere, though Config is imported directly now
|
@@ -27,6 +30,7 @@ if TYPE_CHECKING:
|
|
27
30
|
|
28
31
|
from enum import Enum
|
29
32
|
|
33
|
+
|
30
34
|
class HookType(str, Enum):
|
31
35
|
MQTT_BUILD_CONFIG = "mqtt-build-config"
|
32
36
|
|
@@ -40,6 +44,7 @@ class HookType(str, Enum):
|
|
40
44
|
def __str__(self) -> str:
|
41
45
|
return self.value
|
42
46
|
|
47
|
+
|
43
48
|
setup_logging(level=settings.LOG_LEVEL)
|
44
49
|
|
45
50
|
|
@@ -443,12 +448,14 @@ class PipelineRegistry:
|
|
443
448
|
logger.warning(f"Could not get size for {path}: {e}")
|
444
449
|
size = "Error"
|
445
450
|
|
446
|
-
pipeline_info.append(
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
451
|
+
pipeline_info.append(
|
452
|
+
{
|
453
|
+
"name": name,
|
454
|
+
"path": path,
|
455
|
+
"mod_time": mod_time,
|
456
|
+
"size": size,
|
457
|
+
}
|
458
|
+
)
|
452
459
|
|
453
460
|
if show:
|
454
461
|
table = Table(title="Available Pipelines")
|
@@ -514,7 +521,13 @@ class PipelineRegistry:
|
|
514
521
|
"""
|
515
522
|
return self._all_pipelines(show=False)
|
516
523
|
|
517
|
-
def add_hook(
|
524
|
+
def add_hook(
|
525
|
+
self,
|
526
|
+
name: str,
|
527
|
+
type: HookType,
|
528
|
+
to: str | None = None,
|
529
|
+
function_name: str | None = None,
|
530
|
+
):
|
518
531
|
"""
|
519
532
|
Add a hook to the pipeline module.
|
520
533
|
|
@@ -534,7 +547,6 @@ class PipelineRegistry:
|
|
534
547
|
```
|
535
548
|
"""
|
536
549
|
|
537
|
-
|
538
550
|
if to is None:
|
539
551
|
to = f"hooks/{name}/hook.py"
|
540
552
|
else:
|
@@ -551,10 +563,8 @@ class PipelineRegistry:
|
|
551
563
|
self._fs.makedirs(os.path.dirname(to), exist_ok=True)
|
552
564
|
|
553
565
|
with self._fs.open(to, "a") as f:
|
554
|
-
f.write(
|
555
|
-
template.format(
|
556
|
-
function_name=function_name
|
557
|
-
)
|
558
|
-
)
|
566
|
+
f.write(template.format(function_name=function_name))
|
559
567
|
|
560
|
-
rich.print(
|
568
|
+
rich.print(
|
569
|
+
f"🔧 Added hook [bold blue]{type.value}[/bold blue] to {to} as {function_name} for {name}"
|
570
|
+
)
|
flowerpower/pipeline/runner.py
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
"""Pipeline Runner."""
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
|
-
|
6
|
-
import random
|
5
|
+
|
7
6
|
import datetime as dt
|
8
7
|
import importlib.util
|
8
|
+
import random
|
9
|
+
import time
|
9
10
|
from typing import Any, Callable
|
10
11
|
|
11
12
|
import humanize
|
@@ -14,12 +15,10 @@ from hamilton.execution import executors
|
|
14
15
|
from hamilton.registry import disable_autoload
|
15
16
|
from hamilton.telemetry import disable_telemetry
|
16
17
|
from hamilton_sdk.api.clients import UnauthorizedException
|
17
|
-
|
18
18
|
from requests.exceptions import HTTPError
|
19
19
|
|
20
20
|
from .. import settings
|
21
21
|
|
22
|
-
|
23
22
|
if importlib.util.find_spec("opentelemetry"):
|
24
23
|
from hamilton.plugins import h_opentelemetry
|
25
24
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
from .cfg import MqttConfig
|
2
|
-
from .manager import MqttManager,
|
2
|
+
from .manager import MqttManager, run_pipeline_on_message, start_listener
|
3
3
|
|
4
4
|
MQTTManager = MqttManager
|
5
5
|
|
6
6
|
__all__ = [
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
]
|
7
|
+
"MqttConfig",
|
8
|
+
"MqttManager",
|
9
|
+
"MQTTManager",
|
10
|
+
"start_listener",
|
11
|
+
"run_pipeline_on_message",
|
12
|
+
]
|
flowerpower/plugins/mqtt/cfg.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
from ...cfg.base import BaseConfig
|
2
2
|
|
3
|
+
|
3
4
|
class MqttConfig(BaseConfig):
|
4
5
|
username: str | None = None
|
5
6
|
password: str | None = None
|
6
|
-
host: str | None =
|
7
|
+
host: str | None = "localhost"
|
7
8
|
port: int | None = 1883
|
8
9
|
topic: str | None = None
|
9
10
|
first_reconnect_delay: int = 1
|
10
11
|
max_reconnect_count: int = 5
|
11
12
|
reconnect_rate: int = 2
|
12
13
|
max_reconnect_delay: int = 60
|
13
|
-
transport: str =
|
14
|
+
transport: str = "tcp"
|
14
15
|
clean_session: bool = True
|
15
16
|
client_id: str | None = None
|
16
17
|
client_id_suffix: str | None = None
|
@@ -4,20 +4,20 @@ import socket
|
|
4
4
|
import time
|
5
5
|
from pathlib import Path
|
6
6
|
from types import TracebackType
|
7
|
-
from typing import
|
7
|
+
from typing import Any, Callable
|
8
8
|
|
9
9
|
import mmh3
|
10
10
|
from loguru import logger
|
11
11
|
from munch import Munch
|
12
12
|
from paho.mqtt.client import CallbackAPIVersion, Client
|
13
13
|
|
14
|
-
from .cfg import MqttConfig
|
15
14
|
from ...cfg import ProjectConfig
|
16
15
|
from ...cfg.pipeline.run import ExecutorConfig, WithAdapterConfig
|
17
16
|
from ...cfg.project.adapter import AdapterConfig
|
17
|
+
from ...fs import AbstractFileSystem, BaseStorageOptions, get_filesystem
|
18
18
|
from ...pipeline.manager import PipelineManager
|
19
19
|
from ...utils.logging import setup_logging
|
20
|
-
from
|
20
|
+
from .cfg import MqttConfig
|
21
21
|
|
22
22
|
setup_logging()
|
23
23
|
|
@@ -89,28 +89,37 @@ class MqttManager:
|
|
89
89
|
else:
|
90
90
|
event_broker_cfg = jq_backend.event_broker
|
91
91
|
return cls(
|
92
|
-
|
92
|
+
**event_broker_cfg.dict(),
|
93
93
|
)
|
94
94
|
|
95
95
|
@classmethod
|
96
|
-
def from_config(
|
96
|
+
def from_config(
|
97
|
+
cls,
|
98
|
+
cfg: MqttConfig | None = None,
|
99
|
+
path: str | None = None,
|
100
|
+
fs: AbstractFileSystem | None = None,
|
101
|
+
storage_options: dict | BaseStorageOptions = {},
|
102
|
+
):
|
97
103
|
if cfg is None:
|
98
104
|
if path is None:
|
99
105
|
raise ValueError(
|
100
106
|
"No configuration provided. Please provide `config` or `path` to the configuration file."
|
101
107
|
)
|
102
|
-
|
108
|
+
|
103
109
|
if cfg is None:
|
104
110
|
import os
|
111
|
+
|
105
112
|
if fs is None:
|
106
|
-
fs = get_filesystem(
|
113
|
+
fs = get_filesystem(
|
114
|
+
path=os.path.dirname(path), storage_options=storage_options
|
115
|
+
)
|
107
116
|
|
108
117
|
cfg = MqttConfig.from_yaml(path=os.path.basename(path), fs=fs)
|
109
118
|
|
110
119
|
return cls(
|
111
120
|
**cfg.dict(),
|
112
121
|
)
|
113
|
-
|
122
|
+
|
114
123
|
@classmethod
|
115
124
|
def from_dict(cls, cfg: dict):
|
116
125
|
return cls(
|
@@ -344,8 +353,6 @@ class MqttManager:
|
|
344
353
|
self._client.loop_stop()
|
345
354
|
logger.info("Client stopped.")
|
346
355
|
|
347
|
-
|
348
|
-
|
349
356
|
def run_pipeline_on_message(
|
350
357
|
self,
|
351
358
|
name: str,
|
@@ -447,12 +454,9 @@ class MqttManager:
|
|
447
454
|
config_ = config_hook(inputs["payload"], inputs["topic"])
|
448
455
|
logger.debug(f"Config from hook: {config_}")
|
449
456
|
if any([k in config_ for k in config.keys()]):
|
450
|
-
logger.warning(
|
451
|
-
"Config from hook overwrites config from pipeline"
|
452
|
-
)
|
457
|
+
logger.warning("Config from hook overwrites config from pipeline")
|
453
458
|
config.update(config_)
|
454
459
|
logger.debug(f"Config after update: {config}")
|
455
|
-
|
456
460
|
|
457
461
|
with PipelineManager(
|
458
462
|
storage_options=storage_options, fs=fs, base_dir=base_dir
|
@@ -478,7 +482,7 @@ class MqttManager:
|
|
478
482
|
retry_delay=retry_delay,
|
479
483
|
jitter_factor=jitter_factor,
|
480
484
|
retry_exceptions=retry_exceptions,
|
481
|
-
**kwargs,
|
485
|
+
**kwargs,
|
482
486
|
)
|
483
487
|
else:
|
484
488
|
pipeline.run(
|
@@ -564,7 +568,7 @@ def start_listener(
|
|
564
568
|
Raises:
|
565
569
|
ValueError: If the config_hook is not callable
|
566
570
|
ValueError: If no client configuration is found
|
567
|
-
|
571
|
+
|
568
572
|
Example:
|
569
573
|
```python
|
570
574
|
from flowerpower.plugins.mqtt import start_listener
|
@@ -596,7 +600,6 @@ def start_listener(
|
|
596
600
|
client_id_suffix=client_id_suffix,
|
597
601
|
config_hook=config_hook,
|
598
602
|
**kwargs,
|
599
|
-
|
600
603
|
)
|
601
604
|
else:
|
602
605
|
raise ValueError(
|
@@ -605,7 +608,9 @@ def start_listener(
|
|
605
608
|
"configured in the `config/project.yml` file."
|
606
609
|
)
|
607
610
|
|
608
|
-
client.start_listener(
|
611
|
+
client.start_listener(
|
612
|
+
on_message=on_message, topic=topic, background=background, qos=qos
|
613
|
+
)
|
609
614
|
|
610
615
|
|
611
616
|
def run_pipeline_on_message(
|
@@ -688,7 +693,7 @@ def run_pipeline_on_message(
|
|
688
693
|
|
689
694
|
Returns:
|
690
695
|
None
|
691
|
-
|
696
|
+
|
692
697
|
Raises:
|
693
698
|
ValueError: If the config_hook is not callable
|
694
699
|
ValueError: If no client configuration is found
|
@@ -723,9 +728,8 @@ def run_pipeline_on_message(
|
|
723
728
|
clean_session=clean_session,
|
724
729
|
client_id=client_id,
|
725
730
|
client_id_suffix=client_id_suffix,
|
726
|
-
config_hook=config_hook,
|
731
|
+
config_hook=config_hook,
|
727
732
|
**kwargs,
|
728
|
-
|
729
733
|
)
|
730
734
|
else:
|
731
735
|
raise ValueError(
|
@@ -785,5 +789,3 @@ def run_pipeline_on_message(
|
|
785
789
|
config_hook=config_hook,
|
786
790
|
**kwargs,
|
787
791
|
)
|
788
|
-
|
789
|
-
|
flowerpower/utils/misc.py
CHANGED
@@ -153,10 +153,12 @@ if importlib.util.find_spec("polars"):
|
|
153
153
|
next(v for v in data.values() if isinstance(v, (list, tuple)))
|
154
154
|
)
|
155
155
|
# Convert to DataFrame where each list element becomes a row
|
156
|
-
data = pl.DataFrame(
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
data = pl.DataFrame(
|
157
|
+
{
|
158
|
+
k: v if isinstance(v, (list, tuple)) else [v] * length
|
159
|
+
for k, v in data.items()
|
160
|
+
}
|
161
|
+
)
|
160
162
|
else:
|
161
163
|
# If values are scalars, wrap them in a list to create a single row
|
162
164
|
data = pl.DataFrame({k: [v] for k, v in data.items()})
|
flowerpower/utils/templates.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: FlowerPower
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.0b3
|
4
4
|
Summary: A simple workflow framework. Hamilton + APScheduler = FlowerPower
|
5
5
|
Author-email: "Volker L." <ligno.blades@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/legout/flowerpower
|