meerschaum 2.9.4__py3-none-any.whl → 3.0.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.
- meerschaum/__init__.py +5 -2
- meerschaum/_internal/__init__.py +1 -0
- meerschaum/_internal/arguments/_parse_arguments.py +4 -4
- meerschaum/_internal/arguments/_parser.py +33 -4
- meerschaum/_internal/cli/__init__.py +6 -0
- meerschaum/_internal/cli/daemons.py +103 -0
- meerschaum/_internal/cli/entry.py +220 -0
- meerschaum/_internal/cli/workers.py +435 -0
- meerschaum/_internal/docs/index.py +48 -2
- meerschaum/_internal/entry.py +50 -14
- meerschaum/_internal/shell/Shell.py +121 -29
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +359 -0
- meerschaum/_internal/term/TermPageHandler.py +1 -2
- meerschaum/_internal/term/__init__.py +40 -6
- meerschaum/_internal/term/tools.py +33 -8
- meerschaum/actions/__init__.py +6 -4
- meerschaum/actions/api.py +53 -13
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/bootstrap.py +8 -8
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +171 -25
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +143 -6
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +184 -31
- meerschaum/actions/start.py +166 -17
- meerschaum/actions/stop.py +38 -2
- meerschaum/actions/sync.py +7 -2
- meerschaum/actions/tag.py +9 -8
- meerschaum/actions/verify.py +5 -8
- meerschaum/api/__init__.py +45 -15
- meerschaum/api/_events.py +46 -4
- meerschaum/api/_oauth2.py +162 -9
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -3
- meerschaum/api/dash/callbacks/__init__.py +1 -0
- meerschaum/api/dash/callbacks/custom.py +4 -3
- meerschaum/api/dash/callbacks/dashboard.py +228 -117
- meerschaum/api/dash/callbacks/jobs.py +14 -7
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/pipes.py +194 -14
- meerschaum/api/dash/callbacks/plugins.py +0 -1
- meerschaum/api/dash/callbacks/register.py +10 -3
- meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
- meerschaum/api/dash/callbacks/tokens.py +389 -0
- meerschaum/api/dash/components.py +36 -15
- meerschaum/api/dash/jobs.py +1 -1
- meerschaum/api/dash/keys.py +35 -93
- meerschaum/api/dash/pages/__init__.py +2 -1
- meerschaum/api/dash/pages/dashboard.py +1 -20
- meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pages/pipes.py +16 -5
- meerschaum/api/dash/pages/settings/password_reset.py +1 -1
- meerschaum/api/dash/pages/tokens.py +53 -0
- meerschaum/api/dash/pipes.py +438 -88
- meerschaum/api/dash/sessions.py +12 -0
- meerschaum/api/dash/tokens.py +603 -0
- meerschaum/api/dash/websockets.py +1 -1
- meerschaum/api/dash/webterm.py +18 -6
- meerschaum/api/models/__init__.py +23 -3
- meerschaum/api/models/_actions.py +22 -0
- meerschaum/api/models/_pipes.py +91 -7
- meerschaum/api/models/_tokens.py +81 -0
- meerschaum/api/resources/static/css/dash.css +16 -0
- meerschaum/api/resources/static/js/terminado.js +3 -0
- meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
- meerschaum/api/resources/templates/termpage.html +13 -0
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +3 -4
- meerschaum/api/routes/_connectors.py +3 -7
- meerschaum/api/routes/_jobs.py +26 -35
- meerschaum/api/routes/_login.py +120 -15
- meerschaum/api/routes/_misc.py +5 -10
- meerschaum/api/routes/_pipes.py +178 -143
- meerschaum/api/routes/_plugins.py +38 -28
- meerschaum/api/routes/_tokens.py +236 -0
- meerschaum/api/routes/_users.py +47 -35
- meerschaum/api/routes/_version.py +3 -3
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +100 -30
- meerschaum/config/_default.py +132 -64
- meerschaum/config/_edit.py +38 -32
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +10 -8
- meerschaum/config/_paths.py +133 -13
- meerschaum/config/_read_config.py +87 -36
- meerschaum/config/_sync.py +6 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +37 -15
- meerschaum/config/static.py +18 -0
- meerschaum/connectors/_Connector.py +11 -6
- meerschaum/connectors/__init__.py +41 -22
- meerschaum/connectors/api/_APIConnector.py +34 -6
- meerschaum/connectors/api/_actions.py +2 -2
- meerschaum/connectors/api/_jobs.py +12 -1
- meerschaum/connectors/api/_login.py +33 -7
- meerschaum/connectors/api/_misc.py +2 -2
- meerschaum/connectors/api/_pipes.py +23 -32
- meerschaum/connectors/api/_plugins.py +2 -2
- meerschaum/connectors/api/_request.py +1 -1
- meerschaum/connectors/api/_tokens.py +146 -0
- meerschaum/connectors/api/_users.py +70 -58
- meerschaum/connectors/instance/_InstanceConnector.py +83 -0
- meerschaum/connectors/instance/__init__.py +10 -0
- meerschaum/connectors/instance/_pipes.py +442 -0
- meerschaum/connectors/instance/_plugins.py +159 -0
- meerschaum/connectors/instance/_tokens.py +317 -0
- meerschaum/connectors/instance/_users.py +188 -0
- meerschaum/connectors/parse.py +5 -2
- meerschaum/connectors/sql/_SQLConnector.py +22 -5
- meerschaum/connectors/sql/_cli.py +12 -11
- meerschaum/connectors/sql/_create_engine.py +12 -168
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +295 -278
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +47 -22
- meerschaum/connectors/sql/_users.py +36 -2
- meerschaum/connectors/sql/tables/__init__.py +254 -122
- meerschaum/connectors/valkey/_ValkeyConnector.py +5 -7
- meerschaum/connectors/valkey/_pipes.py +60 -31
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +115 -85
- meerschaum/core/Pipe/_attributes.py +425 -124
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +96 -68
- meerschaum/core/Pipe/_deduplicate.py +0 -13
- meerschaum/core/Pipe/_delete.py +12 -21
- meerschaum/core/Pipe/_drop.py +11 -23
- meerschaum/core/Pipe/_dtypes.py +49 -19
- meerschaum/core/Pipe/_edit.py +14 -4
- meerschaum/core/Pipe/_fetch.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +123 -204
- meerschaum/core/Pipe/_verify.py +4 -4
- meerschaum/{plugins → core/Plugin}/_Plugin.py +16 -12
- meerschaum/core/Plugin/__init__.py +1 -1
- meerschaum/core/Token/_Token.py +220 -0
- meerschaum/core/Token/__init__.py +12 -0
- meerschaum/core/User/_User.py +35 -10
- meerschaum/core/User/__init__.py +9 -1
- meerschaum/core/__init__.py +1 -0
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +149 -38
- meerschaum/jobs/__init__.py +3 -2
- meerschaum/jobs/systemd.py +8 -3
- meerschaum/models/__init__.py +35 -0
- meerschaum/models/pipes.py +247 -0
- meerschaum/models/tokens.py +38 -0
- meerschaum/models/users.py +26 -0
- meerschaum/plugins/__init__.py +301 -88
- meerschaum/plugins/bootstrap.py +510 -4
- meerschaum/utils/_get_pipes.py +97 -30
- meerschaum/utils/daemon/Daemon.py +199 -43
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
- meerschaum/utils/daemon/RotatingFile.py +63 -36
- meerschaum/utils/daemon/StdinFile.py +53 -13
- meerschaum/utils/daemon/__init__.py +47 -6
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/dataframe.py +480 -82
- meerschaum/utils/debug.py +49 -19
- meerschaum/utils/dtypes/__init__.py +478 -37
- meerschaum/utils/dtypes/sql.py +369 -29
- meerschaum/utils/formatting/__init__.py +5 -2
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +52 -50
- meerschaum/utils/formatting/_pprint.py +1 -0
- meerschaum/utils/formatting/_shell.py +44 -18
- meerschaum/utils/misc.py +268 -186
- meerschaum/utils/packages/__init__.py +25 -40
- meerschaum/utils/packages/_packages.py +42 -34
- meerschaum/utils/pipes.py +213 -0
- meerschaum/utils/process.py +2 -2
- meerschaum/utils/prompt.py +175 -144
- meerschaum/utils/schedule.py +2 -1
- meerschaum/utils/sql.py +135 -49
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/typing.py +1 -4
- meerschaum/utils/venv/_Venv.py +2 -2
- meerschaum/utils/venv/__init__.py +7 -7
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/METADATA +94 -96
- meerschaum-3.0.0.dist-info/RECORD +289 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/WHEEL +1 -1
- meerschaum-3.0.0.dist-info/licenses/NOTICE +2 -0
- meerschaum/api/models/_interfaces.py +0 -15
- meerschaum/api/models/_locations.py +0 -15
- meerschaum/api/models/_metrics.py +0 -15
- meerschaum/config/_environment.py +0 -145
- meerschaum/config/static/__init__.py +0 -186
- meerschaum-2.9.4.dist-info/RECORD +0 -263
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0.dist-info}/zip-safe +0 -0
meerschaum/core/Pipe/_data.py
CHANGED
@@ -29,6 +29,7 @@ def get_data(
|
|
29
29
|
as_iterator: bool = False,
|
30
30
|
as_chunks: bool = False,
|
31
31
|
as_dask: bool = False,
|
32
|
+
add_missing_columns: bool = False,
|
32
33
|
chunk_interval: Union[timedelta, int, None] = None,
|
33
34
|
order: Optional[str] = 'asc',
|
34
35
|
limit: Optional[int] = None,
|
@@ -72,6 +73,9 @@ def get_data(
|
|
72
73
|
If `True`, return a `dask.DataFrame`
|
73
74
|
(which may be loaded into a Pandas DataFrame with `df.compute()`).
|
74
75
|
|
76
|
+
add_missing_columns: bool, default False
|
77
|
+
If `True`, add any missing columns from `Pipe.dtypes` to the dataframe.
|
78
|
+
|
75
79
|
chunk_interval: Union[timedelta, int, None], default None
|
76
80
|
If `as_iterator`, then return chunks with `begin` and `end` separated by this interval.
|
77
81
|
This may be set under `pipe.parameters['chunk_minutes']`.
|
@@ -103,13 +107,13 @@ def get_data(
|
|
103
107
|
from meerschaum.utils.warnings import warn
|
104
108
|
from meerschaum.utils.venv import Venv
|
105
109
|
from meerschaum.connectors import get_connector_plugin
|
106
|
-
from meerschaum.utils.
|
107
|
-
from meerschaum.utils.dtypes import to_pandas_dtype, coerce_timezone
|
110
|
+
from meerschaum.utils.dtypes import to_pandas_dtype
|
108
111
|
from meerschaum.utils.dataframe import add_missing_cols_to_df, df_is_chunk_generator
|
109
112
|
from meerschaum.utils.packages import attempt_import
|
113
|
+
from meerschaum.utils.warnings import dprint
|
110
114
|
dd = attempt_import('dask.dataframe') if as_dask else None
|
111
115
|
dask = attempt_import('dask') if as_dask else None
|
112
|
-
|
116
|
+
_ = attempt_import('partd', lazy=False) if as_dask else None
|
113
117
|
|
114
118
|
if select_columns == '*':
|
115
119
|
select_columns = None
|
@@ -188,48 +192,22 @@ def get_data(
|
|
188
192
|
order=order,
|
189
193
|
limit=limit,
|
190
194
|
fresh=fresh,
|
195
|
+
add_missing_columns=True,
|
191
196
|
debug=debug,
|
192
197
|
)
|
193
198
|
for (chunk_begin, chunk_end) in bounds
|
194
199
|
]
|
195
200
|
dask_meta = {
|
196
201
|
col: to_pandas_dtype(typ)
|
197
|
-
for col, typ in self.
|
202
|
+
for col, typ in self.get_dtypes(refresh=True, infer=True, debug=debug).items()
|
198
203
|
}
|
204
|
+
if debug:
|
205
|
+
dprint(f"Dask meta:\n{dask_meta}")
|
199
206
|
return _sort_df(dd.from_delayed(dask_chunks, meta=dask_meta))
|
200
207
|
|
201
208
|
if not self.exists(debug=debug):
|
202
209
|
return None
|
203
210
|
|
204
|
-
if self.cache_pipe is not None:
|
205
|
-
if not fresh:
|
206
|
-
_sync_cache_tuple = self.cache_pipe.sync(
|
207
|
-
begin=begin,
|
208
|
-
end=end,
|
209
|
-
params=params,
|
210
|
-
debug=debug,
|
211
|
-
**kw
|
212
|
-
)
|
213
|
-
if not _sync_cache_tuple[0]:
|
214
|
-
warn(f"Failed to sync cache for {self}:\n" + _sync_cache_tuple[1])
|
215
|
-
fresh = True
|
216
|
-
else: ### Successfully synced cache.
|
217
|
-
return self.enforce_dtypes(
|
218
|
-
self.cache_pipe.get_data(
|
219
|
-
select_columns=select_columns,
|
220
|
-
omit_columns=omit_columns,
|
221
|
-
begin=begin,
|
222
|
-
end=end,
|
223
|
-
params=params,
|
224
|
-
order=order,
|
225
|
-
limit=limit,
|
226
|
-
debug=debug,
|
227
|
-
fresh=True,
|
228
|
-
**kw
|
229
|
-
),
|
230
|
-
debug=debug,
|
231
|
-
)
|
232
|
-
|
233
211
|
with Venv(get_connector_plugin(self.instance_connector)):
|
234
212
|
df = self.instance_connector.get_pipe_data(
|
235
213
|
pipe=self,
|
@@ -249,6 +227,7 @@ def get_data(
|
|
249
227
|
if not select_columns:
|
250
228
|
select_columns = [col for col in df.columns]
|
251
229
|
|
230
|
+
pipe_dtypes = self.get_dtypes(refresh=False, debug=debug)
|
252
231
|
cols_to_omit = [
|
253
232
|
col
|
254
233
|
for col in df.columns
|
@@ -262,7 +241,11 @@ def get_data(
|
|
262
241
|
col
|
263
242
|
for col in select_columns
|
264
243
|
if col not in df.columns
|
265
|
-
]
|
244
|
+
] + ([
|
245
|
+
col
|
246
|
+
for col in pipe_dtypes
|
247
|
+
if col not in df.columns
|
248
|
+
] if add_missing_columns else [])
|
266
249
|
if cols_to_omit:
|
267
250
|
warn(
|
268
251
|
(
|
@@ -278,16 +261,26 @@ def get_data(
|
|
278
261
|
df = df[_cols_to_select]
|
279
262
|
|
280
263
|
if cols_to_add:
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
264
|
+
if not add_missing_columns:
|
265
|
+
from meerschaum.utils.misc import items_str
|
266
|
+
warn(
|
267
|
+
f"Will add columns {items_str(cols_to_add)} as nulls to dataframe.",
|
268
|
+
stack=False,
|
269
|
+
)
|
270
|
+
|
271
|
+
df = add_missing_cols_to_df(
|
272
|
+
df,
|
273
|
+
{
|
274
|
+
col: pipe_dtypes.get(col, 'string')
|
275
|
+
for col in cols_to_add
|
276
|
+
},
|
287
277
|
)
|
288
|
-
df = add_missing_cols_to_df(df, {col: 'string' for col in cols_to_add})
|
289
278
|
|
290
|
-
enforced_df = self.enforce_dtypes(
|
279
|
+
enforced_df = self.enforce_dtypes(
|
280
|
+
df,
|
281
|
+
dtypes=pipe_dtypes,
|
282
|
+
debug=debug,
|
283
|
+
)
|
291
284
|
|
292
285
|
if order:
|
293
286
|
return _sort_df(enforced_df)
|
@@ -311,7 +304,7 @@ def _get_data_as_iterator(
|
|
311
304
|
"""
|
312
305
|
Return a pipe's data as a generator.
|
313
306
|
"""
|
314
|
-
from meerschaum.utils.
|
307
|
+
from meerschaum.utils.dtypes import round_time
|
315
308
|
begin, end = self.parse_date_bounds(begin, end)
|
316
309
|
if not self.exists(debug=debug):
|
317
310
|
return
|
@@ -452,27 +445,6 @@ def get_backtrack_data(
|
|
452
445
|
else backtrack_interval
|
453
446
|
)
|
454
447
|
|
455
|
-
if self.cache_pipe is not None:
|
456
|
-
if not fresh:
|
457
|
-
_sync_cache_tuple = self.cache_pipe.sync(begin=begin, params=params, debug=debug, **kw)
|
458
|
-
if not _sync_cache_tuple[0]:
|
459
|
-
warn(f"Failed to sync cache for {self}:\n" + _sync_cache_tuple[1])
|
460
|
-
fresh = True
|
461
|
-
else: ### Successfully synced cache.
|
462
|
-
return self.enforce_dtypes(
|
463
|
-
self.cache_pipe.get_backtrack_data(
|
464
|
-
fresh=True,
|
465
|
-
begin=begin,
|
466
|
-
backtrack_minutes=backtrack_minutes,
|
467
|
-
params=params,
|
468
|
-
limit=limit,
|
469
|
-
order=kw.get('order', 'desc'),
|
470
|
-
debug=debug,
|
471
|
-
**kw
|
472
|
-
),
|
473
|
-
debug=debug,
|
474
|
-
)
|
475
|
-
|
476
448
|
if hasattr(self.instance_connector, 'get_backtrack_data'):
|
477
449
|
with Venv(get_connector_plugin(self.instance_connector)):
|
478
450
|
return self.enforce_dtypes(
|
@@ -624,7 +596,7 @@ def get_chunk_interval(
|
|
624
596
|
if dt_col is None:
|
625
597
|
return timedelta(minutes=chunk_minutes)
|
626
598
|
|
627
|
-
dt_dtype = self.dtypes.get(dt_col, '
|
599
|
+
dt_dtype = self.dtypes.get(dt_col, 'datetime')
|
628
600
|
if 'int' in dt_dtype.lower():
|
629
601
|
return chunk_minutes
|
630
602
|
return timedelta(minutes=chunk_minutes)
|
@@ -688,11 +660,26 @@ def get_chunk_bounds(
|
|
688
660
|
elif are_dtypes_equal(str(type(end)), 'int'):
|
689
661
|
end += 1
|
690
662
|
consolidate_end_chunk = True
|
663
|
+
|
691
664
|
if begin is None and end is None:
|
692
665
|
return [(None, None)]
|
693
666
|
|
694
667
|
begin, end = self.parse_date_bounds(begin, end)
|
695
668
|
|
669
|
+
if begin and end:
|
670
|
+
if begin >= end:
|
671
|
+
return (
|
672
|
+
[(begin, begin)]
|
673
|
+
if bounded
|
674
|
+
else [(begin, None)]
|
675
|
+
)
|
676
|
+
if end <= begin:
|
677
|
+
return (
|
678
|
+
[(end, end)]
|
679
|
+
if bounded
|
680
|
+
else [(None, begin)]
|
681
|
+
)
|
682
|
+
|
696
683
|
### Set the chunk interval under `pipe.parameters['verify']['chunk_minutes']`.
|
697
684
|
chunk_interval = self.get_chunk_interval(chunk_interval, debug=debug)
|
698
685
|
|
@@ -799,7 +786,7 @@ def parse_date_bounds(self, *dt_vals: Union[datetime, int, None]) -> Union[
|
|
799
786
|
Given a date bound (begin, end), coerce a timezone if necessary.
|
800
787
|
"""
|
801
788
|
from meerschaum.utils.misc import is_int
|
802
|
-
from meerschaum.utils.dtypes import coerce_timezone
|
789
|
+
from meerschaum.utils.dtypes import coerce_timezone, MRSM_PD_DTYPES
|
803
790
|
from meerschaum.utils.warnings import warn
|
804
791
|
dateutil_parser = mrsm.attempt_import('dateutil.parser')
|
805
792
|
|
@@ -824,12 +811,53 @@ def parse_date_bounds(self, *dt_vals: Union[datetime, int, None]) -> Union[
|
|
824
811
|
return None
|
825
812
|
|
826
813
|
dt_col = self.columns.get('datetime', None)
|
827
|
-
dt_typ = str(self.dtypes.get(dt_col, '
|
814
|
+
dt_typ = str(self.dtypes.get(dt_col, 'datetime'))
|
828
815
|
if dt_typ == 'datetime':
|
829
|
-
dt_typ = '
|
816
|
+
dt_typ = MRSM_PD_DTYPES['datetime']
|
830
817
|
return coerce_timezone(dt_val, strip_utc=('utc' not in dt_typ.lower()))
|
831
818
|
|
832
819
|
bounds = tuple(_parse_date_bound(dt_val) for dt_val in dt_vals)
|
833
820
|
if len(bounds) == 1:
|
834
821
|
return bounds[0]
|
835
822
|
return bounds
|
823
|
+
|
824
|
+
|
825
|
+
def get_doc(self, **kwargs) -> Union[Dict[str, Any], None]:
|
826
|
+
"""
|
827
|
+
Convenience function to return a single row as a dictionary (or `None`) from `Pipe.get_data().
|
828
|
+
Keywords arguments are passed to `Pipe.get_data()`.
|
829
|
+
"""
|
830
|
+
from meerschaum.utils.warnings import warn
|
831
|
+
kwargs['limit'] = 1
|
832
|
+
try:
|
833
|
+
result_df = self.get_data(**kwargs)
|
834
|
+
if result_df is None or len(result_df) == 0:
|
835
|
+
return None
|
836
|
+
return result_df.reset_index(drop=True).iloc[0].to_dict()
|
837
|
+
except Exception as e:
|
838
|
+
warn(f"Failed to read value from {self}:\n{e}", stack=False)
|
839
|
+
return None
|
840
|
+
|
841
|
+
def get_value(
|
842
|
+
self,
|
843
|
+
column: str,
|
844
|
+
params: Optional[Dict[str, Any]] = None,
|
845
|
+
**kwargs: Any
|
846
|
+
) -> Any:
|
847
|
+
"""
|
848
|
+
Convenience function to return a single value (or `None`) from `Pipe.get_data()`.
|
849
|
+
Keywords arguments are passed to `Pipe.get_data()`.
|
850
|
+
"""
|
851
|
+
from meerschaum.utils.warnings import warn
|
852
|
+
kwargs['select_columns'] = [column]
|
853
|
+
kwargs['limit'] = 1
|
854
|
+
try:
|
855
|
+
result_df = self.get_data(params=params, **kwargs)
|
856
|
+
if result_df is None or len(result_df) == 0:
|
857
|
+
return None
|
858
|
+
if column not in result_df.columns:
|
859
|
+
raise ValueError(f"Column '{column}' was not included in the result set.")
|
860
|
+
return result_df[column][0]
|
861
|
+
except Exception as e:
|
862
|
+
warn(f"Failed to read value from {self}:\n{e}", stack=False)
|
863
|
+
return None
|
@@ -67,19 +67,6 @@ def deduplicate(
|
|
67
67
|
|
68
68
|
begin, end = self.parse_date_bounds(begin, end)
|
69
69
|
|
70
|
-
if self.cache_pipe is not None:
|
71
|
-
success, msg = self.cache_pipe.deduplicate(
|
72
|
-
begin=begin,
|
73
|
-
end=end,
|
74
|
-
params=params,
|
75
|
-
bounded=bounded,
|
76
|
-
debug=debug,
|
77
|
-
_use_instance_method=_use_instance_method,
|
78
|
-
**kwargs
|
79
|
-
)
|
80
|
-
if not success:
|
81
|
-
warn(msg)
|
82
|
-
|
83
70
|
workers = self.get_num_workers(workers=workers)
|
84
71
|
pool = get_pool(workers=workers)
|
85
72
|
|
meerschaum/core/Pipe/_delete.py
CHANGED
@@ -9,11 +9,11 @@ Delete a Pipe's contents and registration
|
|
9
9
|
from meerschaum.utils.typing import SuccessTuple
|
10
10
|
|
11
11
|
def delete(
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
self,
|
13
|
+
drop: bool = True,
|
14
|
+
debug: bool = False,
|
15
|
+
**kw
|
16
|
+
) -> SuccessTuple:
|
17
17
|
"""
|
18
18
|
Call the Pipe's instance connector's `delete_pipe()` method.
|
19
19
|
|
@@ -30,29 +30,22 @@ def delete(
|
|
30
30
|
A `SuccessTuple` of success (`bool`), message (`str`).
|
31
31
|
|
32
32
|
"""
|
33
|
-
import os, pathlib
|
34
33
|
from meerschaum.utils.warnings import warn
|
35
34
|
from meerschaum.utils.venv import Venv
|
36
35
|
from meerschaum.connectors import get_connector_plugin
|
37
36
|
|
38
37
|
if self.temporary:
|
38
|
+
if self.cache:
|
39
|
+
invalidate_success, invalidate_msg = self._invalidate_cache(hard=True, debug=debug)
|
40
|
+
if not invalidate_success:
|
41
|
+
return invalidate_success, invalidate_msg
|
42
|
+
|
39
43
|
return (
|
40
44
|
False,
|
41
45
|
"Cannot delete pipes created with `temporary=True` (read-only). "
|
42
46
|
+ "You may want to call `pipe.drop()` instead."
|
43
47
|
)
|
44
48
|
|
45
|
-
if self.cache_pipe is not None:
|
46
|
-
_drop_cache_tuple = self.cache_pipe.drop(debug=debug, **kw)
|
47
|
-
if not _drop_cache_tuple[0]:
|
48
|
-
warn(_drop_cache_tuple[1])
|
49
|
-
if getattr(self.cache_connector, 'flavor', None) == 'sqlite':
|
50
|
-
_cache_db_path = pathlib.Path(self.cache_connector.database)
|
51
|
-
try:
|
52
|
-
os.remove(_cache_db_path)
|
53
|
-
except Exception as e:
|
54
|
-
warn(f"Could not delete cache file '{_cache_db_path}' for {self}:\n{e}")
|
55
|
-
|
56
49
|
if drop:
|
57
50
|
drop_success, drop_msg = self.drop(debug=debug)
|
58
51
|
if not drop_success:
|
@@ -65,8 +58,6 @@ def delete(
|
|
65
58
|
return False, f"Received an unexpected result from '{self.instance_connector}': {result}"
|
66
59
|
|
67
60
|
if result[0]:
|
68
|
-
|
69
|
-
|
70
|
-
if member in self.__dict__:
|
71
|
-
del self.__dict__[member]
|
61
|
+
self._invalidate_cache(hard=True, debug=debug)
|
62
|
+
|
72
63
|
return result
|
meerschaum/core/Pipe/_drop.py
CHANGED
@@ -28,15 +28,10 @@ def drop(
|
|
28
28
|
A `SuccessTuple` of success, message.
|
29
29
|
|
30
30
|
"""
|
31
|
-
self._exists = False
|
32
|
-
from meerschaum.utils.warnings import warn
|
33
31
|
from meerschaum.utils.venv import Venv
|
34
32
|
from meerschaum.connectors import get_connector_plugin
|
35
33
|
|
36
|
-
|
37
|
-
_drop_cache_tuple = self.cache_pipe.drop(debug=debug, **kw)
|
38
|
-
if not _drop_cache_tuple[0]:
|
39
|
-
warn(_drop_cache_tuple[1])
|
34
|
+
self._clear_cache_key('_exists', debug=debug)
|
40
35
|
|
41
36
|
with Venv(get_connector_plugin(self.instance_connector)):
|
42
37
|
if hasattr(self.instance_connector, 'drop_pipe'):
|
@@ -50,9 +45,8 @@ def drop(
|
|
50
45
|
)
|
51
46
|
)
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
_ = self.__dict__.pop('_exists_timestamp', None)
|
48
|
+
self._clear_cache_key('_exists', debug=debug)
|
49
|
+
self._clear_cache_key('_exists_timestamp', debug=debug)
|
56
50
|
|
57
51
|
return result
|
58
52
|
|
@@ -79,19 +73,13 @@ def drop_indices(
|
|
79
73
|
A `SuccessTuple` of success, message.
|
80
74
|
|
81
75
|
"""
|
82
|
-
from meerschaum.utils.warnings import warn
|
83
76
|
from meerschaum.utils.venv import Venv
|
84
77
|
from meerschaum.connectors import get_connector_plugin
|
85
78
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
if self.cache_pipe is not None:
|
92
|
-
_drop_cache_tuple = self.cache_pipe.drop_indices(columns=columns, debug=debug, **kw)
|
93
|
-
if not _drop_cache_tuple[0]:
|
94
|
-
warn(_drop_cache_tuple[1])
|
79
|
+
self._clear_cache_key('_columns_indices', debug=debug)
|
80
|
+
self._clear_cache_key('_columns_indices_timestamp', debug=debug)
|
81
|
+
self._clear_cache_key('_columns_types', debug=debug)
|
82
|
+
self._clear_cache_key('_columns_types_timestamp', debug=debug)
|
95
83
|
|
96
84
|
with Venv(get_connector_plugin(self.instance_connector)):
|
97
85
|
if hasattr(self.instance_connector, 'drop_pipe_indices'):
|
@@ -110,9 +98,9 @@ def drop_indices(
|
|
110
98
|
)
|
111
99
|
)
|
112
100
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
101
|
+
self._clear_cache_key('_columns_indices', debug=debug)
|
102
|
+
self._clear_cache_key('_columns_indices_timestamp', debug=debug)
|
103
|
+
self._clear_cache_key('_columns_types', debug=debug)
|
104
|
+
self._clear_cache_key('_columns_types_timestamp', debug=debug)
|
117
105
|
|
118
106
|
return result
|
meerschaum/core/Pipe/_dtypes.py
CHANGED
@@ -22,6 +22,7 @@ def enforce_dtypes(
|
|
22
22
|
chunksize: Optional[int] = -1,
|
23
23
|
enforce: bool = True,
|
24
24
|
safe_copy: bool = True,
|
25
|
+
dtypes: Optional[Dict[str, str]] = None,
|
25
26
|
debug: bool = False,
|
26
27
|
) -> 'pd.DataFrame':
|
27
28
|
"""
|
@@ -31,7 +32,11 @@ def enforce_dtypes(
|
|
31
32
|
import traceback
|
32
33
|
from meerschaum.utils.warnings import warn
|
33
34
|
from meerschaum.utils.debug import dprint
|
34
|
-
from meerschaum.utils.dataframe import
|
35
|
+
from meerschaum.utils.dataframe import (
|
36
|
+
parse_df_datetimes,
|
37
|
+
enforce_dtypes as _enforce_dtypes,
|
38
|
+
parse_simple_lines,
|
39
|
+
)
|
35
40
|
from meerschaum.utils.dtypes import are_dtypes_equal
|
36
41
|
from meerschaum.utils.packages import import_pandas
|
37
42
|
pd = import_pandas(debug=debug)
|
@@ -45,23 +50,35 @@ def enforce_dtypes(
|
|
45
50
|
|
46
51
|
if not self.enforce:
|
47
52
|
enforce = False
|
48
|
-
|
53
|
+
|
54
|
+
explicit_dtypes = self.get_dtypes(infer=False, debug=debug) if enforce else {}
|
55
|
+
pipe_dtypes = self.get_dtypes(infer=True, debug=debug) if not dtypes else dtypes
|
49
56
|
|
50
57
|
try:
|
51
58
|
if isinstance(df, str):
|
52
|
-
df
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
if df.strip() and df.strip()[0] not in ('{', '['):
|
60
|
+
df = parse_df_datetimes(
|
61
|
+
parse_simple_lines(df),
|
62
|
+
ignore_cols=[
|
63
|
+
col
|
64
|
+
for col, dtype in pipe_dtypes.items()
|
65
|
+
if (not enforce or not are_dtypes_equal(dtype, 'datetime'))
|
66
|
+
],
|
67
|
+
)
|
68
|
+
else:
|
69
|
+
df = parse_df_datetimes(
|
70
|
+
pd.read_json(StringIO(df)),
|
71
|
+
ignore_cols=[
|
72
|
+
col
|
73
|
+
for col, dtype in pipe_dtypes.items()
|
74
|
+
if (not enforce or not are_dtypes_equal(dtype, 'datetime'))
|
75
|
+
],
|
76
|
+
ignore_all=(not enforce),
|
77
|
+
strip_timezone=(self.tzinfo is None),
|
78
|
+
chunksize=chunksize,
|
79
|
+
debug=debug,
|
80
|
+
)
|
81
|
+
elif isinstance(df, (dict, list, tuple)):
|
65
82
|
df = parse_df_datetimes(
|
66
83
|
df,
|
67
84
|
ignore_cols=[
|
@@ -81,21 +98,28 @@ def enforce_dtypes(
|
|
81
98
|
if debug:
|
82
99
|
dprint(
|
83
100
|
f"Could not find dtypes for {self}.\n"
|
84
|
-
+ "
|
101
|
+
+ "Skipping dtype enforcement..."
|
85
102
|
)
|
86
103
|
return df
|
87
104
|
|
88
105
|
return _enforce_dtypes(
|
89
106
|
df,
|
90
107
|
pipe_dtypes,
|
108
|
+
explicit_dtypes=explicit_dtypes,
|
91
109
|
safe_copy=safe_copy,
|
92
110
|
strip_timezone=(self.tzinfo is None),
|
111
|
+
coerce_numeric=self.mixed_numerics,
|
93
112
|
coerce_timezone=enforce,
|
94
113
|
debug=debug,
|
95
114
|
)
|
96
115
|
|
97
116
|
|
98
|
-
def infer_dtypes(
|
117
|
+
def infer_dtypes(
|
118
|
+
self,
|
119
|
+
persist: bool = False,
|
120
|
+
refresh: bool = False,
|
121
|
+
debug: bool = False,
|
122
|
+
) -> Dict[str, Any]:
|
99
123
|
"""
|
100
124
|
If `dtypes` is not set in `meerschaum.Pipe.parameters`,
|
101
125
|
infer the data types from the underlying table if it exists.
|
@@ -104,6 +128,11 @@ def infer_dtypes(self, persist: bool = False, debug: bool = False) -> Dict[str,
|
|
104
128
|
----------
|
105
129
|
persist: bool, default False
|
106
130
|
If `True`, persist the inferred data types to `meerschaum.Pipe.parameters`.
|
131
|
+
NOTE: Use with caution! Generally `dtypes` is meant to be user-configurable only.
|
132
|
+
|
133
|
+
refresh: bool, default False
|
134
|
+
If `True`, retrieve the latest columns-types for the pipe.
|
135
|
+
See `Pipe.get_columns.types()`.
|
107
136
|
|
108
137
|
Returns
|
109
138
|
-------
|
@@ -117,7 +146,7 @@ def infer_dtypes(self, persist: bool = False, debug: bool = False) -> Dict[str,
|
|
117
146
|
|
118
147
|
### NOTE: get_columns_types() may return either the types as
|
119
148
|
### PostgreSQL- or Pandas-style.
|
120
|
-
columns_types = self.get_columns_types(debug=debug)
|
149
|
+
columns_types = self.get_columns_types(refresh=refresh, debug=debug)
|
121
150
|
|
122
151
|
remote_pd_dtypes = {
|
123
152
|
c: (
|
@@ -130,7 +159,8 @@ def infer_dtypes(self, persist: bool = False, debug: bool = False) -> Dict[str,
|
|
130
159
|
if not persist:
|
131
160
|
return remote_pd_dtypes
|
132
161
|
|
133
|
-
|
162
|
+
parameters = self.get_parameters(refresh=refresh, debug=debug)
|
163
|
+
dtypes = parameters.get('dtypes', {})
|
134
164
|
dtypes.update({
|
135
165
|
col: typ
|
136
166
|
for col, typ in remote_pd_dtypes.items()
|
meerschaum/core/Pipe/_edit.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# vim:fenc=utf-8
|
4
4
|
|
5
5
|
"""
|
6
|
-
Edit a Pipe's parameters
|
6
|
+
Edit a Pipe's parameters.
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
@@ -47,6 +47,15 @@ def edit(
|
|
47
47
|
if self.temporary:
|
48
48
|
return False, "Cannot edit pipes created with `temporary=True` (read-only)."
|
49
49
|
|
50
|
+
self._invalidate_cache(hard=True, debug=debug)
|
51
|
+
|
52
|
+
if hasattr(self, '_symlinks'):
|
53
|
+
from meerschaum.utils.misc import get_val_from_dict_path, set_val_in_dict_path
|
54
|
+
for path, vals in self._symlinks.items():
|
55
|
+
current_val = get_val_from_dict_path(self.parameters, path)
|
56
|
+
if current_val == vals['substituted']:
|
57
|
+
set_val_in_dict_path(self.parameters, path, vals['original'])
|
58
|
+
|
50
59
|
if not interactive:
|
51
60
|
with Venv(get_connector_plugin(self.instance_connector)):
|
52
61
|
return self.instance_connector.edit_pipe(self, patch=patch, debug=debug, **kw)
|
@@ -65,7 +74,8 @@ def edit(
|
|
65
74
|
from meerschaum.config import get_config
|
66
75
|
parameters = dict(get_config('pipes', 'parameters', patch=True))
|
67
76
|
from meerschaum.config._patch import apply_patch_to_config
|
68
|
-
|
77
|
+
raw_parameters = self.attributes.get('parameters', {})
|
78
|
+
parameters = apply_patch_to_config(parameters, raw_parameters)
|
69
79
|
|
70
80
|
### write parameters to yaml file
|
71
81
|
with open(parameters_path, 'w+') as f:
|
@@ -194,7 +204,7 @@ def edit_definition(
|
|
194
204
|
return True, "Success"
|
195
205
|
|
196
206
|
def _edit_sql():
|
197
|
-
import
|
207
|
+
import textwrap
|
198
208
|
from meerschaum.config._paths import PIPES_CACHE_RESOURCES_PATH
|
199
209
|
from meerschaum.utils.misc import edit_file
|
200
210
|
definition_filename = str(self) + '.sql'
|
@@ -214,7 +224,7 @@ def edit_definition(
|
|
214
224
|
|
215
225
|
edit_file(definition_path)
|
216
226
|
try:
|
217
|
-
with open(definition_path, 'r') as f:
|
227
|
+
with open(definition_path, 'r', encoding='utf-8') as f:
|
218
228
|
file_definition = f.read()
|
219
229
|
except Exception as e:
|
220
230
|
return False, f"Failed reading file '{definition_path}':\n" + str(e)
|
meerschaum/core/Pipe/_fetch.py
CHANGED
@@ -127,7 +127,7 @@ def get_backtrack_interval(
|
|
127
127
|
if dt_col is None:
|
128
128
|
return backtrack_interval
|
129
129
|
|
130
|
-
dt_dtype = self.dtypes.get(dt_col, '
|
130
|
+
dt_dtype = self.dtypes.get(dt_col, 'datetime')
|
131
131
|
if 'int' in dt_dtype.lower():
|
132
132
|
return backtrack_minutes
|
133
133
|
|
meerschaum/core/Pipe/_index.py
CHANGED
@@ -29,19 +29,13 @@ def create_indices(
|
|
29
29
|
A `SuccessTuple` of success, message.
|
30
30
|
|
31
31
|
"""
|
32
|
-
from meerschaum.utils.warnings import warn
|
33
32
|
from meerschaum.utils.venv import Venv
|
34
33
|
from meerschaum.connectors import get_connector_plugin
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if self.cache_pipe is not None:
|
42
|
-
cache_success, cache_msg = self.cache_pipe.index(columns=columns, debug=debug, **kw)
|
43
|
-
if not cache_success:
|
44
|
-
warn(cache_msg)
|
35
|
+
self._clear_cache_key('_columns_indices', debug=debug)
|
36
|
+
self._clear_cache_key('_columns_indices_timestamp', debug=debug)
|
37
|
+
self._clear_cache_key('_columns_types', debug=debug)
|
38
|
+
self._clear_cache_key('_columns_types_timestamp', debug=debug)
|
45
39
|
|
46
40
|
with Venv(get_connector_plugin(self.instance_connector)):
|
47
41
|
if hasattr(self.instance_connector, 'create_pipe_indices'):
|
@@ -60,9 +54,9 @@ def create_indices(
|
|
60
54
|
)
|
61
55
|
)
|
62
56
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
57
|
+
self._clear_cache_key('_columns_indices', debug=debug)
|
58
|
+
self._clear_cache_key('_columns_indices_timestamp', debug=debug)
|
59
|
+
self._clear_cache_key('_columns_types', debug=debug)
|
60
|
+
self._clear_cache_key('_columns_types_timestamp', debug=debug)
|
67
61
|
|
68
62
|
return result
|
meerschaum/core/Pipe/_show.py
CHANGED
@@ -9,11 +9,11 @@ Show information about a Pipe
|
|
9
9
|
from meerschaum.utils.typing import SuccessTuple
|
10
10
|
|
11
11
|
def show(
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
self,
|
13
|
+
nopretty: bool = False,
|
14
|
+
debug: bool = False,
|
15
|
+
**kw
|
16
|
+
) -> SuccessTuple:
|
17
17
|
"""
|
18
18
|
Show attributes of a Pipe.
|
19
19
|
|