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
@@ -13,7 +13,7 @@ from meerschaum.utils.typing import SuccessTuple, Any, Union, Optional, Dict, Li
|
|
13
13
|
from meerschaum.utils.misc import string_to_dict
|
14
14
|
from meerschaum.utils.dtypes import json_serialize_value
|
15
15
|
from meerschaum.utils.warnings import warn, dprint
|
16
|
-
from meerschaum.
|
16
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
17
17
|
|
18
18
|
PIPES_TABLE: str = 'mrsm_pipes'
|
19
19
|
PIPES_COUNTER: str = 'mrsm_pipes:counter'
|
@@ -276,7 +276,7 @@ def edit_pipe(
|
|
276
276
|
return False, f"{pipe} is not registered."
|
277
277
|
|
278
278
|
parameters_key = get_pipe_parameters_key(pipe)
|
279
|
-
parameters_str = json.dumps(pipe.
|
279
|
+
parameters_str = json.dumps(pipe.get_parameters(apply_symlinks=False), separators=(',', ':'))
|
280
280
|
self.set(parameters_key, parameters_str)
|
281
281
|
return True, "Success"
|
282
282
|
|
@@ -321,14 +321,40 @@ def drop_pipe(
|
|
321
321
|
-------
|
322
322
|
A `SuccessTuple` indicating success.
|
323
323
|
"""
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
324
|
+
if not pipe.exists(debug=debug):
|
325
|
+
return True, f"{pipe} does not exist, so it was not dropped."
|
326
|
+
|
327
|
+
table_name = self.quote_table(pipe.target)
|
328
|
+
dt_col = pipe.columns.get('datetime', None)
|
329
|
+
|
330
|
+
try:
|
331
|
+
members = (
|
332
|
+
self.client.zrange(table_name, 0, -1)
|
333
|
+
if dt_col
|
334
|
+
else self.client.smembers(table_name)
|
329
335
|
)
|
330
|
-
|
331
|
-
|
336
|
+
|
337
|
+
keys_to_delete = []
|
338
|
+
for member_bytes in members:
|
339
|
+
member_str = member_bytes.decode('utf-8')
|
340
|
+
member_doc = json.loads(member_str)
|
341
|
+
ix_str = member_doc.get('ix')
|
342
|
+
if not ix_str:
|
343
|
+
continue
|
344
|
+
|
345
|
+
ix_doc = string_to_dict(ix_str.replace(COLON, ':'))
|
346
|
+
doc_key = self.get_document_key(ix_doc, list(ix_doc.keys()), table_name)
|
347
|
+
keys_to_delete.append(doc_key)
|
348
|
+
|
349
|
+
if keys_to_delete:
|
350
|
+
batch_size = 1000
|
351
|
+
for i in range(0, len(keys_to_delete), batch_size):
|
352
|
+
batch = keys_to_delete[i:i+batch_size]
|
353
|
+
self.client.delete(*batch)
|
354
|
+
|
355
|
+
except Exception as e:
|
356
|
+
return False, f"Failed to delete documents for {pipe}:\n{e}"
|
357
|
+
|
332
358
|
try:
|
333
359
|
self.drop_table(pipe.target, debug=debug)
|
334
360
|
except Exception as e:
|
@@ -337,7 +363,7 @@ def drop_pipe(
|
|
337
363
|
if 'valkey' not in pipe.parameters:
|
338
364
|
return True, "Success"
|
339
365
|
|
340
|
-
pipe.parameters['valkey']['dtypes'] = {}
|
366
|
+
pipe._attributes['parameters']['valkey']['dtypes'] = {}
|
341
367
|
if not pipe.temporary:
|
342
368
|
edit_success, edit_msg = pipe.edit(debug=debug)
|
343
369
|
if not edit_success:
|
@@ -558,11 +584,7 @@ def sync_pipe(
|
|
558
584
|
|
559
585
|
valkey_dtypes = pipe.parameters.get('valkey', {}).get('dtypes', {})
|
560
586
|
new_dtypes = {
|
561
|
-
str(key): (
|
562
|
-
str(val)
|
563
|
-
if not are_dtypes_equal(str(val), 'datetime')
|
564
|
-
else 'datetime64[ns, UTC]'
|
565
|
-
)
|
587
|
+
str(key): str(val)
|
566
588
|
for key, val in df.dtypes.items()
|
567
589
|
if str(key) not in valkey_dtypes
|
568
590
|
}
|
@@ -571,19 +593,20 @@ def sync_pipe(
|
|
571
593
|
try:
|
572
594
|
df[col] = df[col].astype(typ)
|
573
595
|
except Exception:
|
596
|
+
import traceback
|
597
|
+
traceback.print_exc()
|
574
598
|
valkey_dtypes[col] = 'string'
|
575
599
|
new_dtypes[col] = 'string'
|
576
600
|
df[col] = df[col].astype('string')
|
577
601
|
|
578
602
|
if new_dtypes and (not static or not valkey_dtypes):
|
579
603
|
valkey_dtypes.update(new_dtypes)
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
return edit_success, edit_msg
|
604
|
+
update_success, update_msg = pipe.update_parameters(
|
605
|
+
{'valkey': {'dtypes': valkey_dtypes}},
|
606
|
+
debug=debug,
|
607
|
+
)
|
608
|
+
if not update_success:
|
609
|
+
return False, update_msg
|
587
610
|
|
588
611
|
unseen_df, update_df, delta_df = (
|
589
612
|
pipe.filter_existing(df, include_unchanged_columns=True, debug=debug)
|
@@ -781,7 +804,7 @@ def get_sync_time(
|
|
781
804
|
"""
|
782
805
|
from meerschaum.utils.dtypes import are_dtypes_equal
|
783
806
|
dt_col = pipe.columns.get('datetime', None)
|
784
|
-
dt_typ = pipe.dtypes.get(dt_col, '
|
807
|
+
dt_typ = pipe.dtypes.get(dt_col, 'datetime')
|
785
808
|
if not dt_col:
|
786
809
|
return None
|
787
810
|
|
@@ -789,14 +812,18 @@ def get_sync_time(
|
|
789
812
|
table_name = self.quote_table(pipe.target)
|
790
813
|
try:
|
791
814
|
vals = (
|
792
|
-
self.client.zrevrange(table_name, 0, 0)
|
815
|
+
self.client.zrevrange(table_name, 0, 0, withscores=True)
|
793
816
|
if newest
|
794
|
-
else self.client.zrange(table_name, 0, 0)
|
817
|
+
else self.client.zrange(table_name, 0, 0, withscores=True)
|
795
818
|
)
|
796
819
|
if not vals:
|
797
820
|
return None
|
798
|
-
val = vals[0]
|
821
|
+
val = vals[0][0]
|
822
|
+
if isinstance(val, bytes):
|
823
|
+
val = val.decode('utf-8')
|
799
824
|
except Exception:
|
825
|
+
import traceback
|
826
|
+
traceback.print_exc()
|
800
827
|
return None
|
801
828
|
|
802
829
|
doc = json.loads(val)
|
@@ -861,7 +888,9 @@ def fetch_pipes_keys(
|
|
861
888
|
tags: Optional[List[str]] = None,
|
862
889
|
params: Optional[Dict[str, Any]] = None,
|
863
890
|
debug: bool = False
|
864
|
-
) ->
|
891
|
+
) -> List[
|
892
|
+
Tuple[str, str, Union[str, None], Dict[str, Any]]
|
893
|
+
]:
|
865
894
|
"""
|
866
895
|
Return the keys for the registered pipes.
|
867
896
|
"""
|
@@ -892,6 +921,7 @@ def fetch_pipes_keys(
|
|
892
921
|
doc['connector_keys'],
|
893
922
|
doc['metric_key'],
|
894
923
|
doc['location_key'],
|
924
|
+
doc.get('parameters', {})
|
895
925
|
)
|
896
926
|
for doc in df.to_dict(orient='records')
|
897
927
|
]
|
@@ -902,9 +932,8 @@ def fetch_pipes_keys(
|
|
902
932
|
in_ex_tag_groups = [separate_negation_values(tag_group) for tag_group in tag_groups]
|
903
933
|
|
904
934
|
filtered_keys = []
|
905
|
-
for ck, mk, lk in keys:
|
906
|
-
|
907
|
-
pipe_tags = set(pipe.tags)
|
935
|
+
for ck, mk, lk, parameters in keys:
|
936
|
+
pipe_tags = set(parameters.get('tags', []))
|
908
937
|
|
909
938
|
include_pipe = True
|
910
939
|
for in_tags, ex_tags in in_ex_tag_groups:
|
@@ -916,6 +945,6 @@ def fetch_pipes_keys(
|
|
916
945
|
continue
|
917
946
|
|
918
947
|
if include_pipe:
|
919
|
-
filtered_keys.append((ck, mk, lk))
|
948
|
+
filtered_keys.append((ck, mk, lk, parameters))
|
920
949
|
|
921
950
|
return filtered_keys
|
@@ -127,7 +127,8 @@ def get_plugin_id(
|
|
127
127
|
"""
|
128
128
|
Return a plugin's ID.
|
129
129
|
"""
|
130
|
-
|
130
|
+
user_id = self.get_plugin_user_id(plugin, debug=debug)
|
131
|
+
return plugin.name if user_id is not None else None
|
131
132
|
|
132
133
|
|
133
134
|
def get_plugin_version(
|
@@ -199,31 +200,6 @@ def get_plugin_attributes(
|
|
199
200
|
return {}
|
200
201
|
|
201
202
|
|
202
|
-
def get_plugins(
|
203
|
-
self,
|
204
|
-
user_id: Optional[int] = None,
|
205
|
-
search_term: Optional[str] = None,
|
206
|
-
debug: bool = False,
|
207
|
-
**kw: Any
|
208
|
-
) -> List[str]:
|
209
|
-
"""
|
210
|
-
Return a list of plugin names.
|
211
|
-
"""
|
212
|
-
plugins_pipe = self.get_plugins_pipe()
|
213
|
-
params = {}
|
214
|
-
if user_id:
|
215
|
-
params['user_id'] = user_id
|
216
|
-
|
217
|
-
df = plugins_pipe.get_data(['plugin_name'], params=params, debug=debug)
|
218
|
-
docs = df.to_dict(orient='records')
|
219
|
-
|
220
|
-
return [
|
221
|
-
doc['plugin_name']
|
222
|
-
for doc in docs
|
223
|
-
if (plugin_name := doc['plugin_name']).startswith(search_term or '')
|
224
|
-
]
|
225
|
-
|
226
|
-
|
227
203
|
def delete_plugin(
|
228
204
|
self,
|
229
205
|
plugin: 'mrsm.core.Plugin',
|
meerschaum/core/Pipe/__init__.py
CHANGED
@@ -50,12 +50,16 @@ with correct credentials, as well as a network connection and valid permissions.
|
|
50
50
|
"""
|
51
51
|
|
52
52
|
from __future__ import annotations
|
53
|
+
|
53
54
|
import sys
|
54
55
|
import copy
|
55
|
-
|
56
|
+
|
57
|
+
import meerschaum as mrsm
|
58
|
+
from meerschaum.utils.typing import Optional, Dict, Any, Union, List, InstanceConnector
|
56
59
|
from meerschaum.utils.formatting._pipes import pipe_repr
|
57
60
|
from meerschaum.config import get_config
|
58
61
|
|
62
|
+
|
59
63
|
class Pipe:
|
60
64
|
"""
|
61
65
|
Access Meerschaum pipes via Pipe objects.
|
@@ -89,6 +93,9 @@ class Pipe:
|
|
89
93
|
get_data,
|
90
94
|
get_backtrack_data,
|
91
95
|
get_rowcount,
|
96
|
+
get_data,
|
97
|
+
get_doc,
|
98
|
+
get_value,
|
92
99
|
_get_data_as_iterator,
|
93
100
|
get_chunk_interval,
|
94
101
|
get_chunk_bounds,
|
@@ -104,15 +111,20 @@ class Pipe:
|
|
104
111
|
indexes,
|
105
112
|
dtypes,
|
106
113
|
autoincrement,
|
114
|
+
autotime,
|
107
115
|
upsert,
|
108
116
|
static,
|
109
117
|
tzinfo,
|
110
118
|
enforce,
|
111
119
|
null_indices,
|
120
|
+
mixed_numerics,
|
112
121
|
get_columns,
|
113
122
|
get_columns_types,
|
114
123
|
get_columns_indices,
|
115
124
|
get_indices,
|
125
|
+
get_parameters,
|
126
|
+
get_dtypes,
|
127
|
+
update_parameters,
|
116
128
|
tags,
|
117
129
|
get_id,
|
118
130
|
id,
|
@@ -123,6 +135,30 @@ class Pipe:
|
|
123
135
|
target,
|
124
136
|
_target_legacy,
|
125
137
|
guess_datetime,
|
138
|
+
precision,
|
139
|
+
get_precision,
|
140
|
+
)
|
141
|
+
from ._cache import (
|
142
|
+
_get_cache_connector,
|
143
|
+
_cache_value,
|
144
|
+
_get_cached_value,
|
145
|
+
_invalidate_cache,
|
146
|
+
_get_cache_dir_path,
|
147
|
+
_write_cache_key,
|
148
|
+
_write_cache_file,
|
149
|
+
_write_cache_conn_key,
|
150
|
+
_read_cache_key,
|
151
|
+
_read_cache_file,
|
152
|
+
_read_cache_conn_key,
|
153
|
+
_load_cache_keys,
|
154
|
+
_load_cache_files,
|
155
|
+
_load_cache_conn_keys,
|
156
|
+
_get_cache_keys,
|
157
|
+
_get_cache_file_keys,
|
158
|
+
_get_cache_conn_keys,
|
159
|
+
_clear_cache_key,
|
160
|
+
_clear_cache_file,
|
161
|
+
_clear_cache_conn_key,
|
126
162
|
)
|
127
163
|
from ._show import show
|
128
164
|
from ._edit import edit, edit_definition, update
|
@@ -133,11 +169,7 @@ class Pipe:
|
|
133
169
|
filter_existing,
|
134
170
|
_get_chunk_label,
|
135
171
|
get_num_workers,
|
136
|
-
|
137
|
-
_persist_new_numeric_columns,
|
138
|
-
_persist_new_uuid_columns,
|
139
|
-
_persist_new_bytes_columns,
|
140
|
-
_persist_new_geometry_columns,
|
172
|
+
_persist_new_special_columns,
|
141
173
|
)
|
142
174
|
from ._verify import (
|
143
175
|
verify,
|
@@ -165,20 +197,24 @@ class Pipe:
|
|
165
197
|
target: Optional[str] = None,
|
166
198
|
dtypes: Optional[Dict[str, str]] = None,
|
167
199
|
instance: Optional[Union[str, InstanceConnector]] = None,
|
168
|
-
temporary: bool = False,
|
169
200
|
upsert: Optional[bool] = None,
|
170
201
|
autoincrement: Optional[bool] = None,
|
202
|
+
autotime: Optional[bool] = None,
|
203
|
+
precision: Union[str, Dict[str, Union[str, int]], None] = None,
|
171
204
|
static: Optional[bool] = None,
|
172
205
|
enforce: Optional[bool] = None,
|
173
206
|
null_indices: Optional[bool] = None,
|
207
|
+
mixed_numerics: Optional[bool] = None,
|
208
|
+
temporary: bool = False,
|
209
|
+
cache: Optional[bool] = None,
|
210
|
+
cache_connector_keys: Optional[str] = None,
|
174
211
|
mrsm_instance: Optional[Union[str, InstanceConnector]] = None,
|
175
|
-
cache: bool = False,
|
176
|
-
debug: bool = False,
|
177
212
|
connector_keys: Optional[str] = None,
|
178
213
|
metric_key: Optional[str] = None,
|
179
214
|
location_key: Optional[str] = None,
|
180
215
|
instance_keys: Optional[str] = None,
|
181
216
|
indexes: Union[Dict[str, str], List[str], None] = None,
|
217
|
+
debug: bool = False,
|
182
218
|
):
|
183
219
|
"""
|
184
220
|
Parameters
|
@@ -226,6 +262,16 @@ class Pipe:
|
|
226
262
|
autoincrement: Optional[bool], default None
|
227
263
|
If `True`, set `autoincrement` in the parameters.
|
228
264
|
|
265
|
+
autotime: Optional[bool], default None
|
266
|
+
If `True`, set `autotime` in the parameters.
|
267
|
+
|
268
|
+
precision: Union[str, Dict[str, Union[str, int]], None], default None
|
269
|
+
If provided, set `precision` in the parameters.
|
270
|
+
This may be either a string (the precision unit) or a dictionary of in the form
|
271
|
+
`{'unit': <unit>, 'interval': <interval>}`.
|
272
|
+
Default is determined by the `datetime` column dtype
|
273
|
+
(e.g. `datetime64[us]` is `microsecond` precision).
|
274
|
+
|
229
275
|
static: Optional[bool], default None
|
230
276
|
If `True`, set `static` in the parameters.
|
231
277
|
|
@@ -237,12 +283,21 @@ class Pipe:
|
|
237
283
|
Set to `False` if there will be no null values in the index columns.
|
238
284
|
Defaults to `True`.
|
239
285
|
|
286
|
+
mixed_numerics: bool, default None
|
287
|
+
If `True`, integer columns will be converted to `numeric` when floats are synced.
|
288
|
+
Set to `False` to disable this behavior.
|
289
|
+
Defaults to `True`.
|
290
|
+
|
240
291
|
temporary: bool, default False
|
241
292
|
If `True`, prevent instance tables (pipes, users, plugins) from being created.
|
242
293
|
|
243
|
-
cache: bool, default
|
244
|
-
If `True`, cache
|
245
|
-
|
294
|
+
cache: Optional[bool], default None
|
295
|
+
If `True`, cache the pipe's metadata to disk (in addition to in-memory caching).
|
296
|
+
If `cache` is not explicitly `True`, it is set to `False` if `temporary` is `True`.
|
297
|
+
Defaults to `True` (from `None`).
|
298
|
+
|
299
|
+
cache_connector_keys: Optional[str], default None
|
300
|
+
If provided, use the keys to a Valkey connector (e.g. `valkey:main`).
|
246
301
|
"""
|
247
302
|
from meerschaum.utils.warnings import error, warn
|
248
303
|
if (not connector and not connector_keys) or (not metric and not metric_key):
|
@@ -264,7 +319,7 @@ class Pipe:
|
|
264
319
|
if location in ('[None]', 'None'):
|
265
320
|
location = None
|
266
321
|
|
267
|
-
from meerschaum.
|
322
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
268
323
|
negation_prefix = STATIC_CONFIG['system']['fetch_pipes_keys']['negation_prefix']
|
269
324
|
for k in (connector, metric, location, *(tags or [])):
|
270
325
|
if str(k).startswith(negation_prefix):
|
@@ -275,8 +330,15 @@ class Pipe:
|
|
275
330
|
self.metric_key = metric
|
276
331
|
self.location_key = location
|
277
332
|
self.temporary = temporary
|
333
|
+
self.cache = cache if cache is not None else (not temporary)
|
334
|
+
self.cache_connector_keys = (
|
335
|
+
str(cache_connector_keys)
|
336
|
+
if cache_connector_keys is not None
|
337
|
+
else None
|
338
|
+
)
|
339
|
+
self.debug = debug
|
278
340
|
|
279
|
-
self._attributes = {
|
341
|
+
self._attributes: Dict[str, Any] = {
|
280
342
|
'connector_keys': self.connector_keys,
|
281
343
|
'metric_key': self.metric_key,
|
282
344
|
'location_key': self.location_key,
|
@@ -291,11 +353,13 @@ class Pipe:
|
|
291
353
|
warn(f"The provided parameters are of invalid type '{type(parameters)}'.")
|
292
354
|
self._attributes['parameters'] = {}
|
293
355
|
|
294
|
-
columns = columns or self._attributes.get('parameters', {}).get('columns',
|
295
|
-
if isinstance(columns, list):
|
356
|
+
columns = columns or self._attributes.get('parameters', {}).get('columns', None)
|
357
|
+
if isinstance(columns, (list, tuple)):
|
296
358
|
columns = {str(col): str(col) for col in columns}
|
297
359
|
if isinstance(columns, dict):
|
298
360
|
self._attributes['parameters']['columns'] = columns
|
361
|
+
elif isinstance(columns, str) and 'Pipe(' in columns:
|
362
|
+
pass
|
299
363
|
elif columns is not None:
|
300
364
|
warn(f"The provided columns are of invalid type '{type(columns)}'.")
|
301
365
|
|
@@ -334,8 +398,17 @@ class Pipe:
|
|
334
398
|
if isinstance(autoincrement, bool):
|
335
399
|
self._attributes['parameters']['autoincrement'] = autoincrement
|
336
400
|
|
401
|
+
if isinstance(autotime, bool):
|
402
|
+
self._attributes['parameters']['autotime'] = autotime
|
403
|
+
|
404
|
+
if isinstance(precision, dict):
|
405
|
+
self._attributes['parameters']['precision'] = precision
|
406
|
+
elif isinstance(precision, str):
|
407
|
+
self._attributes['parameters']['precision'] = {'unit': precision}
|
408
|
+
|
337
409
|
if isinstance(static, bool):
|
338
410
|
self._attributes['parameters']['static'] = static
|
411
|
+
self._static = static
|
339
412
|
|
340
413
|
if isinstance(enforce, bool):
|
341
414
|
self._attributes['parameters']['enforce'] = enforce
|
@@ -343,6 +416,9 @@ class Pipe:
|
|
343
416
|
if isinstance(null_indices, bool):
|
344
417
|
self._attributes['parameters']['null_indices'] = null_indices
|
345
418
|
|
419
|
+
if isinstance(mixed_numerics, bool):
|
420
|
+
self._attributes['parameters']['mixed_numerics'] = mixed_numerics
|
421
|
+
|
346
422
|
### NOTE: The parameters dictionary is {} by default.
|
347
423
|
### A Pipe may be registered without parameters, then edited,
|
348
424
|
### or a Pipe may be registered with parameters set in-memory first.
|
@@ -353,10 +429,12 @@ class Pipe:
|
|
353
429
|
if not isinstance(_mrsm_instance, str):
|
354
430
|
self._instance_connector = _mrsm_instance
|
355
431
|
self.instance_keys = str(_mrsm_instance)
|
356
|
-
else:
|
432
|
+
else:
|
357
433
|
self.instance_keys = _mrsm_instance
|
358
434
|
|
359
|
-
self.
|
435
|
+
if self.instance_keys == 'sql:memory':
|
436
|
+
self.cache = False
|
437
|
+
|
360
438
|
|
361
439
|
@property
|
362
440
|
def meta(self):
|
@@ -383,9 +461,7 @@ class Pipe:
|
|
383
461
|
@property
|
384
462
|
def instance_connector(self) -> Union[InstanceConnector, None]:
|
385
463
|
"""
|
386
|
-
The connector
|
387
|
-
May either be of type `meerschaum.connectors.sql.SQLConnector` or
|
388
|
-
`meerschaum.connectors.api.APIConnector`.
|
464
|
+
The instance connector on which this pipe resides.
|
389
465
|
"""
|
390
466
|
if '_instance_connector' not in self.__dict__:
|
391
467
|
from meerschaum.connectors.parse import parse_instance_keys
|
@@ -397,7 +473,7 @@ class Pipe:
|
|
397
473
|
return self._instance_connector
|
398
474
|
|
399
475
|
@property
|
400
|
-
def connector(self) -> Union[
|
476
|
+
def connector(self) -> Union['Connector', None]:
|
401
477
|
"""
|
402
478
|
The connector to the data source.
|
403
479
|
"""
|
@@ -416,68 +492,6 @@ class Pipe:
|
|
416
492
|
return None
|
417
493
|
return self._connector
|
418
494
|
|
419
|
-
@property
|
420
|
-
def cache_connector(self) -> Union[meerschaum.connectors.sql.SQLConnector, None]:
|
421
|
-
"""
|
422
|
-
If the pipe was created with `cache=True`, return the connector to the pipe's
|
423
|
-
SQLite database for caching.
|
424
|
-
"""
|
425
|
-
if not self._cache:
|
426
|
-
return None
|
427
|
-
|
428
|
-
if '_cache_connector' not in self.__dict__:
|
429
|
-
from meerschaum.connectors import get_connector
|
430
|
-
from meerschaum.config._paths import DUCKDB_RESOURCES_PATH, SQLITE_RESOURCES_PATH
|
431
|
-
_resources_path = SQLITE_RESOURCES_PATH
|
432
|
-
self._cache_connector = get_connector(
|
433
|
-
'sql', '_cache_' + str(self),
|
434
|
-
flavor='sqlite',
|
435
|
-
database=str(_resources_path / ('_cache_' + str(self) + '.db')),
|
436
|
-
)
|
437
|
-
|
438
|
-
return self._cache_connector
|
439
|
-
|
440
|
-
@property
|
441
|
-
def cache_pipe(self) -> Union['meerschaum.Pipe', None]:
|
442
|
-
"""
|
443
|
-
If the pipe was created with `cache=True`, return another `meerschaum.Pipe` used to
|
444
|
-
manage the local data.
|
445
|
-
"""
|
446
|
-
if self.cache_connector is None:
|
447
|
-
return None
|
448
|
-
if '_cache_pipe' not in self.__dict__:
|
449
|
-
from meerschaum.config._patch import apply_patch_to_config
|
450
|
-
from meerschaum.utils.sql import sql_item_name
|
451
|
-
_parameters = copy.deepcopy(self.parameters)
|
452
|
-
_fetch_patch = {
|
453
|
-
'fetch': ({
|
454
|
-
'definition': (
|
455
|
-
"SELECT * FROM "
|
456
|
-
+ sql_item_name(
|
457
|
-
str(self.target),
|
458
|
-
self.instance_connector.flavor,
|
459
|
-
self.instance_connector.get_pipe_schema(self),
|
460
|
-
)
|
461
|
-
),
|
462
|
-
}) if self.instance_connector.type == 'sql' else ({
|
463
|
-
'connector_keys': self.connector_keys,
|
464
|
-
'metric_key': self.metric_key,
|
465
|
-
'location_key': self.location_key,
|
466
|
-
})
|
467
|
-
}
|
468
|
-
_parameters = apply_patch_to_config(_parameters, _fetch_patch)
|
469
|
-
self._cache_pipe = Pipe(
|
470
|
-
self.instance_keys,
|
471
|
-
(self.connector_keys + '_' + self.metric_key + '_cache'),
|
472
|
-
self.location_key,
|
473
|
-
mrsm_instance = self.cache_connector,
|
474
|
-
parameters = _parameters,
|
475
|
-
cache = False,
|
476
|
-
temporary = True,
|
477
|
-
)
|
478
|
-
|
479
|
-
return self._cache_pipe
|
480
|
-
|
481
495
|
def __str__(self, ansi: bool=False):
|
482
496
|
return pipe_repr(self, ansi=ansi)
|
483
497
|
|
@@ -522,7 +536,7 @@ class Pipe:
|
|
522
536
|
'connector_keys': self.connector_keys,
|
523
537
|
'metric_key': self.metric_key,
|
524
538
|
'location_key': self.location_key,
|
525
|
-
'parameters': self.parameters,
|
539
|
+
'parameters': self._attributes.get('parameters', None),
|
526
540
|
'instance_keys': self.instance_keys,
|
527
541
|
}
|
528
542
|
|
@@ -558,3 +572,19 @@ class Pipe:
|
|
558
572
|
if aliased_key is not None:
|
559
573
|
key = aliased_key
|
560
574
|
return getattr(self, key, None)
|
575
|
+
|
576
|
+
def __copy__(self):
|
577
|
+
"""
|
578
|
+
Return a shallow copy of the current pipe.
|
579
|
+
"""
|
580
|
+
return mrsm.Pipe(
|
581
|
+
self.connector_keys, self.metric_key, self.location_key,
|
582
|
+
instance=self.instance_keys,
|
583
|
+
parameters=self._attributes.get('parameters', None),
|
584
|
+
)
|
585
|
+
|
586
|
+
def __deepcopy__(self, memo):
|
587
|
+
"""
|
588
|
+
Return a deep copy of the current pipe.
|
589
|
+
"""
|
590
|
+
return self.__copy__()
|