FlowerPower 1.0.0b2__py3-none-any.whl → 1.0.0b4__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.
Files changed (38) hide show
  1. flowerpower/__init__.py +2 -3
  2. flowerpower/cfg/__init__.py +10 -8
  3. flowerpower/cfg/pipeline/__init__.py +11 -7
  4. flowerpower/cfg/project/__init__.py +11 -8
  5. flowerpower/cfg/project/job_queue.py +10 -29
  6. flowerpower/cli/__init__.py +62 -28
  7. flowerpower/cli/job_queue.py +306 -123
  8. flowerpower/cli/mqtt.py +22 -16
  9. flowerpower/cli/pipeline.py +294 -114
  10. flowerpower/flowerpower.py +14 -8
  11. flowerpower/fs/__init__.py +7 -3
  12. flowerpower/fs/ext.py +6 -2
  13. flowerpower/io/base.py +17 -10
  14. flowerpower/io/loader/_duckdb.py +1 -0
  15. flowerpower/io/loader/deltatable.py +6 -2
  16. flowerpower/io/saver/deltatable.py +1 -2
  17. flowerpower/job_queue/__init__.py +16 -12
  18. flowerpower/job_queue/apscheduler/__init__.py +1 -1
  19. flowerpower/job_queue/apscheduler/manager.py +11 -6
  20. flowerpower/job_queue/apscheduler/utils.py +6 -4
  21. flowerpower/job_queue/base.py +1 -0
  22. flowerpower/job_queue/rq/__init__.py +1 -1
  23. flowerpower/job_queue/rq/manager.py +12 -3
  24. flowerpower/pipeline/io.py +11 -9
  25. flowerpower/pipeline/job_queue.py +5 -5
  26. flowerpower/pipeline/manager.py +35 -27
  27. flowerpower/pipeline/registry.py +26 -16
  28. flowerpower/pipeline/runner.py +3 -4
  29. flowerpower/plugins/mqtt/__init__.py +7 -7
  30. flowerpower/plugins/mqtt/cfg.py +3 -2
  31. flowerpower/plugins/mqtt/manager.py +25 -23
  32. flowerpower/utils/misc.py +6 -4
  33. flowerpower/utils/templates.py +1 -4
  34. {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b4.dist-info}/METADATA +1 -1
  35. {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b4.dist-info}/RECORD +38 -38
  36. {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b4.dist-info}/WHEEL +0 -0
  37. {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b4.dist-info}/entry_points.txt +0 -0
  38. {flowerpower-1.0.0b2.dist-info → flowerpower-1.0.0b4.dist-info}/top_level.txt +0 -0
@@ -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
- self, name:str, type:HookType, to:str|None, function_name:str|None,
712
- )->None:
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 = 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 = 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 = 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 = 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 = 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 = 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 | str | None = None,
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 = duration_parser.parse(run_in) if isinstance(run_in, str) else run_in #convert to seconds
1349
- run_at = dt.datetime.fromisoformat(run_at) if isinstance(run_at, str) else run_at
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 = duration_parser.parse(interval) if isinstance(interval, str) else 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
-
@@ -1,7 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Pipeline Registry for discovery, listing, creation, and deletion."""
3
- import os
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 PIPELINE_PY_TEMPLATE, HOOK_TEMPLATE__MQTT_BUILD_CONFIG
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
- "name": name,
448
- "path": path,
449
- "mod_time": mod_time,
450
- "size": size,
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(self, name: str, type: HookType, to: str | None = None, function_name: str|None = None):
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(f"🔧 Added hook [bold blue]{type.value}[/bold blue] to {to} as {function_name} for {name}")
568
+ rich.print(
569
+ f"🔧 Added hook [bold blue]{type.value}[/bold blue] to {to} as {function_name} for {name}"
570
+ )
@@ -2,10 +2,11 @@
2
2
  """Pipeline Runner."""
3
3
 
4
4
  from __future__ import annotations
5
- import time
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, start_listener, run_pipeline_on_message
2
+ from .manager import MqttManager, run_pipeline_on_message, start_listener
3
3
 
4
4
  MQTTManager = MqttManager
5
5
 
6
6
  __all__ = [
7
- 'MqttConfig',
8
- 'MqttManager',
9
- 'MQTTManager',
10
- 'start_listener',
11
- 'run_pipeline_on_message',
12
- ]
7
+ "MqttConfig",
8
+ "MqttManager",
9
+ "MQTTManager",
10
+ "start_listener",
11
+ "run_pipeline_on_message",
12
+ ]
@@ -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 = 'localhost'
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 = 'tcp'
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 Callable, Any
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 ...fs import get_filesystem, AbstractFileSystem, BaseStorageOptions
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
- **event_broker_cfg.dict(),
92
+ **event_broker_cfg.dict(),
93
93
  )
94
94
 
95
95
  @classmethod
96
- def from_config(cls, cfg: MqttConfig | None=None, path: str | None = None, fs: AbstractFileSystem | None = None, storage_options: dict | BaseStorageOptions = {}):
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(path=os.path.dirname(path), storage_options=storage_options)
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(on_message=on_message, topic=topic, background=background, qos=qos)
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
- k: v if isinstance(v, (list, tuple)) else [v] * length
158
- for k, v in data.items()
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()})
@@ -1,6 +1,3 @@
1
-
2
-
3
-
4
1
  PIPELINE_PY_TEMPLATE = """# FlowerPower pipeline {name}.py
5
2
  # Created on {date}
6
3
 
@@ -47,4 +44,4 @@ def {function_name}(payload: bytes, topic: str) -> dict:
47
44
  """
48
45
 
49
46
  pass
50
- '''
47
+ '''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: FlowerPower
3
- Version: 1.0.0b2
3
+ Version: 1.0.0b4
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