FlowerPower 0.11.6.20__py3-none-any.whl → 0.21.0__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 (101) hide show
  1. flowerpower/__init__.py +2 -6
  2. flowerpower/cfg/__init__.py +7 -14
  3. flowerpower/cfg/base.py +29 -25
  4. flowerpower/cfg/pipeline/__init__.py +8 -6
  5. flowerpower/cfg/pipeline/_schedule.py +32 -0
  6. flowerpower/cfg/pipeline/adapter.py +0 -5
  7. flowerpower/cfg/pipeline/builder.py +377 -0
  8. flowerpower/cfg/pipeline/run.py +36 -0
  9. flowerpower/cfg/project/__init__.py +11 -24
  10. flowerpower/cfg/project/adapter.py +0 -12
  11. flowerpower/cli/__init__.py +2 -21
  12. flowerpower/cli/cfg.py +0 -3
  13. flowerpower/cli/mqtt.py +0 -6
  14. flowerpower/cli/pipeline.py +22 -415
  15. flowerpower/cli/utils.py +0 -1
  16. flowerpower/flowerpower.py +345 -146
  17. flowerpower/pipeline/__init__.py +2 -0
  18. flowerpower/pipeline/base.py +21 -12
  19. flowerpower/pipeline/io.py +58 -54
  20. flowerpower/pipeline/manager.py +165 -726
  21. flowerpower/pipeline/pipeline.py +643 -0
  22. flowerpower/pipeline/registry.py +285 -18
  23. flowerpower/pipeline/visualizer.py +5 -6
  24. flowerpower/plugins/io/__init__.py +8 -0
  25. flowerpower/plugins/mqtt/__init__.py +7 -11
  26. flowerpower/settings/__init__.py +0 -2
  27. flowerpower/settings/{backend.py → _backend.py} +0 -21
  28. flowerpower/settings/logging.py +1 -1
  29. flowerpower/utils/logging.py +24 -12
  30. flowerpower/utils/misc.py +17 -256
  31. flowerpower/utils/monkey.py +1 -83
  32. flowerpower-0.21.0.dist-info/METADATA +463 -0
  33. flowerpower-0.21.0.dist-info/RECORD +44 -0
  34. flowerpower/cfg/pipeline/schedule.py +0 -74
  35. flowerpower/cfg/project/job_queue.py +0 -238
  36. flowerpower/cli/job_queue.py +0 -1061
  37. flowerpower/fs/__init__.py +0 -29
  38. flowerpower/fs/base.py +0 -662
  39. flowerpower/fs/ext.py +0 -2143
  40. flowerpower/fs/storage_options.py +0 -1420
  41. flowerpower/job_queue/__init__.py +0 -294
  42. flowerpower/job_queue/apscheduler/__init__.py +0 -11
  43. flowerpower/job_queue/apscheduler/_setup/datastore.py +0 -110
  44. flowerpower/job_queue/apscheduler/_setup/eventbroker.py +0 -93
  45. flowerpower/job_queue/apscheduler/manager.py +0 -1051
  46. flowerpower/job_queue/apscheduler/setup.py +0 -554
  47. flowerpower/job_queue/apscheduler/trigger.py +0 -169
  48. flowerpower/job_queue/apscheduler/utils.py +0 -311
  49. flowerpower/job_queue/base.py +0 -413
  50. flowerpower/job_queue/rq/__init__.py +0 -10
  51. flowerpower/job_queue/rq/_trigger.py +0 -37
  52. flowerpower/job_queue/rq/concurrent_workers/gevent_worker.py +0 -226
  53. flowerpower/job_queue/rq/concurrent_workers/thread_worker.py +0 -231
  54. flowerpower/job_queue/rq/manager.py +0 -1582
  55. flowerpower/job_queue/rq/setup.py +0 -154
  56. flowerpower/job_queue/rq/utils.py +0 -69
  57. flowerpower/mqtt.py +0 -12
  58. flowerpower/pipeline/job_queue.py +0 -583
  59. flowerpower/pipeline/runner.py +0 -603
  60. flowerpower/plugins/io/base.py +0 -2520
  61. flowerpower/plugins/io/helpers/datetime.py +0 -298
  62. flowerpower/plugins/io/helpers/polars.py +0 -875
  63. flowerpower/plugins/io/helpers/pyarrow.py +0 -570
  64. flowerpower/plugins/io/helpers/sql.py +0 -202
  65. flowerpower/plugins/io/loader/__init__.py +0 -28
  66. flowerpower/plugins/io/loader/csv.py +0 -37
  67. flowerpower/plugins/io/loader/deltatable.py +0 -190
  68. flowerpower/plugins/io/loader/duckdb.py +0 -19
  69. flowerpower/plugins/io/loader/json.py +0 -37
  70. flowerpower/plugins/io/loader/mqtt.py +0 -159
  71. flowerpower/plugins/io/loader/mssql.py +0 -26
  72. flowerpower/plugins/io/loader/mysql.py +0 -26
  73. flowerpower/plugins/io/loader/oracle.py +0 -26
  74. flowerpower/plugins/io/loader/parquet.py +0 -35
  75. flowerpower/plugins/io/loader/postgres.py +0 -26
  76. flowerpower/plugins/io/loader/pydala.py +0 -19
  77. flowerpower/plugins/io/loader/sqlite.py +0 -23
  78. flowerpower/plugins/io/metadata.py +0 -244
  79. flowerpower/plugins/io/saver/__init__.py +0 -28
  80. flowerpower/plugins/io/saver/csv.py +0 -36
  81. flowerpower/plugins/io/saver/deltatable.py +0 -186
  82. flowerpower/plugins/io/saver/duckdb.py +0 -19
  83. flowerpower/plugins/io/saver/json.py +0 -36
  84. flowerpower/plugins/io/saver/mqtt.py +0 -28
  85. flowerpower/plugins/io/saver/mssql.py +0 -26
  86. flowerpower/plugins/io/saver/mysql.py +0 -26
  87. flowerpower/plugins/io/saver/oracle.py +0 -26
  88. flowerpower/plugins/io/saver/parquet.py +0 -36
  89. flowerpower/plugins/io/saver/postgres.py +0 -26
  90. flowerpower/plugins/io/saver/pydala.py +0 -20
  91. flowerpower/plugins/io/saver/sqlite.py +0 -24
  92. flowerpower/plugins/mqtt/cfg.py +0 -17
  93. flowerpower/plugins/mqtt/manager.py +0 -962
  94. flowerpower/settings/job_queue.py +0 -87
  95. flowerpower/utils/scheduler.py +0 -311
  96. flowerpower-0.11.6.20.dist-info/METADATA +0 -537
  97. flowerpower-0.11.6.20.dist-info/RECORD +0 -102
  98. {flowerpower-0.11.6.20.dist-info → flowerpower-0.21.0.dist-info}/WHEEL +0 -0
  99. {flowerpower-0.11.6.20.dist-info → flowerpower-0.21.0.dist-info}/entry_points.txt +0 -0
  100. {flowerpower-0.11.6.20.dist-info → flowerpower-0.21.0.dist-info}/licenses/LICENSE +0 -0
  101. {flowerpower-0.11.6.20.dist-info → flowerpower-0.21.0.dist-info}/top_level.txt +0 -0
@@ -1,238 +0,0 @@
1
- import datetime as dt
2
- import importlib
3
- import os
4
-
5
- import msgspec
6
-
7
- from ... import settings
8
- from ...settings.backend import BACKEND_PROPERTIES
9
- from ..base import BaseConfig
10
-
11
-
12
- class JobQueueBackendConfig(BaseConfig):
13
- """
14
- Job Queue backend configuration for FlowerPower.
15
- Inherits from BaseConfig and adapts Redis logic.
16
- """
17
-
18
- type: str | None = msgspec.field(default=None)
19
- uri: str | None = msgspec.field(default=None)
20
- username: str | None = msgspec.field(default=None)
21
- password: str | None = msgspec.field(default=None)
22
- host: str | None = msgspec.field(default=None)
23
- port: int | None = msgspec.field(default=None)
24
- database: int | None = msgspec.field(default=None)
25
- ssl: bool = msgspec.field(default=False)
26
- cert_file: str | None = msgspec.field(default=None)
27
- key_file: str | None = msgspec.field(default=None)
28
- ca_file: str | None = msgspec.field(default=None)
29
- verify_ssl: bool = msgspec.field(default=False)
30
-
31
-
32
- class APSDataStoreConfig(JobQueueBackendConfig):
33
- type: str = msgspec.field(default=settings.APS_BACKEND_DS or "memory")
34
- username: str | None = msgspec.field(default=None)
35
- password: str | None = msgspec.field(default=None)
36
- host: str | None = msgspec.field(default=None)
37
- port: int | None = msgspec.field(default=None)
38
- database: str | None = msgspec.field(default=None)
39
- schema: str | None = msgspec.field(default=None)
40
-
41
- def __post_init__(self):
42
- self.update_settings_from_env()
43
- self.host = (
44
- settings.APS_BACKEND_DS_HOST
45
- or BACKEND_PROPERTIES[self.type]["default_host"]
46
- )
47
- self.port = (
48
- settings.APS_BACKEND_DS_PORT
49
- or BACKEND_PROPERTIES[self.type]["default_port"]
50
- )
51
- self.database = (
52
- settings.APS_BACKEND_DS_DB
53
- or BACKEND_PROPERTIES[self.type]["default_database"]
54
- )
55
- self.username = (
56
- settings.APS_BACKEND_DS_USERNAME
57
- or BACKEND_PROPERTIES[self.type]["default_username"]
58
- )
59
- self.password = (
60
- settings.APS_BACKEND_DS_PASSWORD
61
- or BACKEND_PROPERTIES[self.type]["default_password"]
62
- )
63
-
64
- def update_settings_from_env(self):
65
- if os.getenv("FP_APS_BACKEND_DS") is not None:
66
- settings.APS_BACKEND_DS = os.getenv("FP_APS_BACKEND_DS")
67
- if os.getenv("FP_APS_BACKEND_DS_USERNAME") is not None:
68
- settings.APS_BACKEND_DS_USERNAME = os.getenv("FP_APS_BACKEND_DS_USERNAME")
69
- if os.getenv("FP_APS_BACKEND_DS_PASSWORD") is not None:
70
- settings.APS_BACKEND_DS_PASSWORD = os.getenv("FP_APS_BACKEND_DS_PASSWORD")
71
- if os.getenv("FP_APS_BACKEND_DS_HOST") is not None:
72
- settings.APS_BACKEND_DS_HOST = os.getenv("FP_APS_BACKEND_DS_HOST")
73
- if os.getenv("FP_APS_BACKEND_DS_PORT") is not None:
74
- settings.APS_BACKEND_DS_PORT = int(os.getenv("FP_APS_BACKEND_DS_PORT"))
75
- if os.getenv("FP_APS_BACKEND_DS_DB") is not None:
76
- settings.APS_BACKEND_DS_DB = os.getenv("FP_APS_BACKEND_DS_DB")
77
-
78
-
79
- class APSEventBrokerConfig(JobQueueBackendConfig):
80
- type: str = msgspec.field(default=settings.APS_BACKEND_EB or "memory")
81
- username: str | None = msgspec.field(default=None)
82
- password: str | None = msgspec.field(default=None)
83
- host: str | None = msgspec.field(default=None)
84
- port: int | None = msgspec.field(default=None)
85
- database: str | None = msgspec.field(default=None)
86
- from_ds_sqla: bool = msgspec.field(
87
- default_factory=lambda: settings.APS_BACKEND_EB == "postgresql"
88
- and settings.APS_BACKEND_DS == "postgresql"
89
- )
90
-
91
- def __post_init__(self):
92
- self.update_settings_from_env()
93
- self.host = (
94
- settings.APS_BACKEND_EB_HOST
95
- or BACKEND_PROPERTIES[self.type]["default_host"]
96
- )
97
- self.port = (
98
- settings.APS_BACKEND_EB_PORT
99
- or BACKEND_PROPERTIES[self.type]["default_port"]
100
- )
101
- self.database = (
102
- settings.APS_BACKEND_EB_DB
103
- or BACKEND_PROPERTIES[self.type]["default_database"]
104
- )
105
- self.username = (
106
- settings.APS_BACKEND_EB_USERNAME
107
- or BACKEND_PROPERTIES[self.type]["default_username"]
108
- )
109
- self.password = (
110
- settings.APS_BACKEND_EB_PASSWORD
111
- or BACKEND_PROPERTIES[self.type]["default_password"]
112
- )
113
-
114
- def update_settings_from_env(self):
115
- if os.getenv("FP_APS_BACKEND_EB") is not None:
116
- settings.APS_BACKEND_EB = os.getenv("FP_APS_BACKEND_EB")
117
- if os.getenv("FP_APS_BACKEND_EB_USERNAME") is not None:
118
- settings.APS_BACKEND_EB_USERNAME = os.getenv("FP_APS_BACKEND_EB_USERNAME")
119
- if os.getenv("FP_APS_BACKEND_EB_PASSWORD") is not None:
120
- settings.APS_BACKEND_EB_PASSWORD = os.getenv("FP_APS_BACKEND_EB_PASSWORD")
121
- if os.getenv("FP_APS_BACKEND_EB_HOST") is not None:
122
- settings.APS_BACKEND_EB_HOST = os.getenv("FP_APS_BACKEND_EB_HOST")
123
- if os.getenv("FP_APS_BACKEND_EB_PORT") is not None:
124
- settings.APS_BACKEND_EB_PORT = int(os.getenv("FP_APS_BACKEND_EB_PORT"))
125
- if os.getenv("FP_APS_BACKEND_EB_DB") is not None:
126
- settings.APS_BACKEND_EB_DB = os.getenv("FP_APS_BACKEND_EB_DB")
127
-
128
-
129
- class APSBackendConfig(BaseConfig):
130
- data_store: APSDataStoreConfig = msgspec.field(default_factory=APSDataStoreConfig)
131
- event_broker: APSEventBrokerConfig = msgspec.field(
132
- default_factory=APSEventBrokerConfig
133
- )
134
- cleanup_interval: int | float | dt.timedelta = msgspec.field(
135
- default=settings.APS_CLEANUP_INTERVAL
136
- ) # int in seconds
137
- max_concurrent_jobs: int = msgspec.field(default=settings.APS_MAX_CONCURRENT_JOBS)
138
- default_job_executor: str | None = msgspec.field(default=settings.EXECUTOR)
139
- # num_workers: int | None = msgspec.field(default=settings.APS_NUM_WORKERS)
140
-
141
- # def __post_init__(self):
142
- # self.data_store.update_settings_from_env()
143
- # self.event_broker.update_settings_from_env()
144
-
145
-
146
- class RQBackendConfig(JobQueueBackendConfig):
147
- type: str = msgspec.field(default="redis")
148
- username: str | None = msgspec.field(default=settings.RQ_BACKEND_USERNAME)
149
- password: str | None = msgspec.field(default=settings.RQ_BACKEND_PASSWORD)
150
- host: str = msgspec.field(default=settings.RQ_BACKEND_HOST)
151
- port: int = msgspec.field(default=settings.RQ_BACKEND_PORT)
152
- database: int = msgspec.field(default=settings.RQ_BACKEND_DB)
153
- queues: str | list[str] = msgspec.field(default_factory=lambda: settings.RQ_QUEUES)
154
- # num_workers: int = msgspec.field(default=settings.RQ_NUM_WORKERS) # int in seconds
155
-
156
- def update_from_settings(self):
157
- if self.host == BACKEND_PROPERTIES[self.type]["default_host"]:
158
- self.host = settings.RQ_BACKEND_HOST
159
- if self.port == BACKEND_PROPERTIES[self.type]["default_port"]:
160
- self.port = settings.RQ_BACKEND_PORT
161
- if self.database == BACKEND_PROPERTIES[self.type]["default_database"]:
162
- self.database = settings.RQ_BACKEND_DB
163
- if self.username == BACKEND_PROPERTIES[self.type]["default_username"]:
164
- self.username = settings.RQ_BACKEND_USERNAME
165
- if self.password == BACKEND_PROPERTIES[self.type]["default_password"]:
166
- self.password = settings.RQ_BACKEND_PASSWORD
167
-
168
- def update_from_env(self):
169
- if os.getenv("FP_RQ_BACKEND") is not None:
170
- settings.RQ_BACKEND = os.getenv("FP_RQ_BACKEND")
171
- if os.getenv("FP_RQ_BACKEND_USERNAME") is not None:
172
- settings.RQ_BACKEND_USERNAME = os.getenv("FP_RQ_BACKEND_USERNAME")
173
- if os.getenv("FP_RQ_BACKEND_PASSWORD") is not None:
174
- settings.RQ_BACKEND_PASSWORD = os.getenv("FP_RQ_BACKEND_PASSWORD")
175
- if os.getenv("FP_RQ_BACKEND_HOST") is not None:
176
- settings.RQ_BACKEND_HOST = os.getenv("FP_RQ_BACKEND_HOST")
177
- if os.getenv("FP_RQ_BACKEND_PORT") is not None:
178
- settings.RQ_BACKEND_PORT = int(os.getenv("FP_RQ_BACKEND_PORT"))
179
- if os.getenv("FP_RQ_BACKEND_DB") is not None:
180
- settings.RQ_BACKEND_DB = int(os.getenv("FP_RQ_BACKEND_DB"))
181
- self.update_from_settings()
182
-
183
- def __post_init__(self):
184
- if isinstance(self.queues, str):
185
- self.queues = self.queues.replace(" ", "").split(",")
186
- elif not isinstance(self.queues, list):
187
- raise ValueError(
188
- f"Invalid queues type: {type(self.queues)}. Must be a string or a list."
189
- )
190
- self.update_from_env()
191
-
192
-
193
- class HueyBackendConfig(JobQueueBackendConfig):
194
- pass
195
-
196
-
197
- class JobQueueConfig(BaseConfig):
198
- type: str | None = msgspec.field(default="rq")
199
- backend: dict | None = msgspec.field(default=None)
200
- num_workers: int | None = msgspec.field(default=None)
201
-
202
- def __post_init__(self):
203
- if self.type is not None:
204
- self.type = self.type.lower()
205
- if self.type == "rq":
206
- self.backend = self.backend or RQBackendConfig()
207
-
208
- if isinstance(self.backend, dict):
209
- self.backend = RQBackendConfig.from_dict(self.backend)
210
- elif isinstance(self.backend, RQBackendConfig):
211
- pass
212
- else:
213
- raise ValueError(
214
- f"Invalid backend type for RQ: {type(self.backend)}"
215
- )
216
- self.num_workers = self.num_workers or settings.RQ_NUM_WORKERS
217
-
218
- elif self.type == "apscheduler":
219
- self.backend = self.backend or APSBackendConfig()
220
- if isinstance(self.backend, dict):
221
- self.backend = APSBackendConfig.from_dict(self.backend)
222
- elif isinstance(self.backend, APSBackendConfig):
223
- pass
224
- else:
225
- raise ValueError(
226
- f"Invalid backend type for APScheduler: {type(self.backend)}"
227
- )
228
- self.num_workers = self.num_workers or settings.APS_NUM_WORKERS
229
- else:
230
- raise ValueError(
231
- f"Invalid job queue type: {self.type}. Valid types: {['rq', 'apscheduler', 'huey']}"
232
- )
233
-
234
- def update_type(self, type: str):
235
- if type != self.type:
236
- self.type = type
237
- self.backend = None
238
- self.__post_init__()