meerschaum 2.9.4__py3-none-any.whl → 3.0.0rc1__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 +17 -1
- meerschaum/_internal/entry.py +6 -6
- meerschaum/_internal/shell/Shell.py +1 -1
- meerschaum/_internal/static.py +372 -0
- meerschaum/actions/api.py +12 -2
- meerschaum/actions/bootstrap.py +7 -7
- meerschaum/actions/edit.py +142 -18
- meerschaum/actions/register.py +137 -6
- meerschaum/actions/show.py +117 -29
- meerschaum/actions/stop.py +4 -1
- meerschaum/actions/sync.py +1 -1
- meerschaum/actions/tag.py +9 -8
- meerschaum/api/__init__.py +9 -2
- meerschaum/api/_events.py +39 -2
- meerschaum/api/_oauth2.py +118 -8
- meerschaum/api/_tokens.py +102 -0
- meerschaum/api/dash/__init__.py +0 -1
- meerschaum/api/dash/callbacks/custom.py +2 -2
- meerschaum/api/dash/callbacks/dashboard.py +133 -18
- meerschaum/api/dash/callbacks/plugins.py +0 -1
- meerschaum/api/dash/callbacks/register.py +1 -1
- meerschaum/api/dash/callbacks/settings/__init__.py +1 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +2 -2
- meerschaum/api/dash/callbacks/settings/tokens.py +388 -0
- meerschaum/api/dash/components.py +30 -8
- meerschaum/api/dash/keys.py +19 -93
- meerschaum/api/dash/pages/dashboard.py +1 -20
- meerschaum/api/dash/pages/settings/__init__.py +1 -0
- meerschaum/api/dash/pages/settings/password_reset.py +1 -1
- meerschaum/api/dash/pages/settings/tokens.py +55 -0
- meerschaum/api/dash/pipes.py +156 -58
- meerschaum/api/dash/sessions.py +12 -0
- meerschaum/api/dash/tokens.py +606 -0
- meerschaum/api/dash/websockets.py +1 -1
- meerschaum/api/dash/webterm.py +4 -0
- meerschaum/api/models/__init__.py +23 -3
- meerschaum/api/models/_actions.py +22 -0
- meerschaum/api/models/_pipes.py +85 -7
- meerschaum/api/models/_tokens.py +81 -0
- meerschaum/api/resources/static/css/dash.css +16 -0
- meerschaum/api/resources/templates/termpage.html +12 -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 +14 -35
- meerschaum/api/routes/_login.py +49 -12
- meerschaum/api/routes/_misc.py +5 -10
- meerschaum/api/routes/_pipes.py +134 -111
- 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/config/__init__.py +43 -20
- meerschaum/config/_default.py +32 -5
- meerschaum/config/_edit.py +28 -24
- meerschaum/config/_environment.py +1 -1
- meerschaum/config/_patch.py +6 -6
- meerschaum/config/_paths.py +5 -1
- meerschaum/config/_read_config.py +65 -34
- meerschaum/config/_sync.py +6 -3
- meerschaum/config/_version.py +1 -1
- meerschaum/config/stack/__init__.py +24 -5
- meerschaum/config/static.py +18 -0
- meerschaum/connectors/_Connector.py +10 -4
- meerschaum/connectors/__init__.py +4 -20
- meerschaum/connectors/api/_APIConnector.py +34 -6
- meerschaum/connectors/api/_actions.py +2 -2
- meerschaum/connectors/api/_jobs.py +1 -1
- meerschaum/connectors/api/_login.py +33 -7
- meerschaum/connectors/api/_misc.py +2 -2
- meerschaum/connectors/api/_pipes.py +15 -14
- 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 +151 -0
- meerschaum/connectors/instance/_tokens.py +296 -0
- meerschaum/connectors/instance/_users.py +181 -0
- meerschaum/connectors/parse.py +4 -1
- meerschaum/connectors/sql/_SQLConnector.py +8 -5
- meerschaum/connectors/sql/_cli.py +12 -11
- meerschaum/connectors/sql/_create_engine.py +6 -154
- meerschaum/connectors/sql/_fetch.py +2 -18
- meerschaum/connectors/sql/_pipes.py +42 -31
- meerschaum/connectors/sql/_plugins.py +29 -0
- meerschaum/connectors/sql/_sql.py +9 -2
- meerschaum/connectors/sql/_users.py +29 -2
- meerschaum/connectors/sql/tables/__init__.py +1 -1
- meerschaum/connectors/valkey/_ValkeyConnector.py +2 -4
- meerschaum/connectors/valkey/_pipes.py +9 -10
- meerschaum/connectors/valkey/_plugins.py +2 -26
- meerschaum/core/Pipe/__init__.py +31 -14
- meerschaum/core/Pipe/_attributes.py +156 -58
- meerschaum/core/Pipe/_bootstrap.py +54 -24
- meerschaum/core/Pipe/_data.py +41 -1
- meerschaum/core/Pipe/_dtypes.py +29 -14
- meerschaum/core/Pipe/_edit.py +12 -4
- meerschaum/core/Pipe/_show.py +5 -5
- meerschaum/core/Pipe/_sync.py +48 -53
- meerschaum/core/Pipe/_verify.py +1 -1
- meerschaum/{plugins → core/Plugin}/_Plugin.py +9 -11
- meerschaum/core/Plugin/__init__.py +1 -1
- meerschaum/core/Token/_Token.py +221 -0
- meerschaum/core/Token/__init__.py +12 -0
- meerschaum/core/User/_User.py +34 -8
- meerschaum/core/User/__init__.py +9 -1
- meerschaum/core/__init__.py +1 -0
- meerschaum/jobs/_Job.py +3 -2
- meerschaum/jobs/__init__.py +3 -2
- meerschaum/jobs/systemd.py +1 -1
- 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 +22 -7
- meerschaum/plugins/bootstrap.py +2 -1
- meerschaum/utils/_get_pipes.py +68 -27
- meerschaum/utils/daemon/Daemon.py +2 -1
- meerschaum/utils/daemon/__init__.py +30 -2
- meerschaum/utils/dataframe.py +96 -15
- meerschaum/utils/dtypes/__init__.py +93 -21
- meerschaum/utils/dtypes/sql.py +44 -0
- meerschaum/utils/formatting/__init__.py +1 -1
- meerschaum/utils/formatting/_pipes.py +5 -4
- meerschaum/utils/formatting/_shell.py +11 -9
- meerschaum/utils/misc.py +237 -80
- meerschaum/utils/packages/__init__.py +3 -6
- meerschaum/utils/packages/_packages.py +34 -32
- meerschaum/utils/pipes.py +181 -0
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +3 -1
- meerschaum/utils/schedule.py +1 -0
- meerschaum/utils/sql.py +115 -39
- meerschaum/utils/typing.py +1 -4
- meerschaum/utils/venv/_Venv.py +2 -2
- meerschaum/utils/venv/__init__.py +5 -7
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0rc1.dist-info}/METADATA +88 -80
- meerschaum-3.0.0rc1.dist-info/RECORD +282 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0rc1.dist-info}/WHEEL +1 -1
- meerschaum/api/models/_interfaces.py +0 -15
- meerschaum/api/models/_locations.py +0 -15
- meerschaum/api/models/_metrics.py +0 -15
- 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.0rc1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0rc1.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0rc1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.4.dist-info → meerschaum-3.0.0rc1.dist-info}/zip-safe +0 -0
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,6 +111,7 @@ class Pipe:
|
|
104
111
|
indexes,
|
105
112
|
dtypes,
|
106
113
|
autoincrement,
|
114
|
+
autotime,
|
107
115
|
upsert,
|
108
116
|
static,
|
109
117
|
tzinfo,
|
@@ -113,6 +121,8 @@ class Pipe:
|
|
113
121
|
get_columns_types,
|
114
122
|
get_columns_indices,
|
115
123
|
get_indices,
|
124
|
+
get_parameters,
|
125
|
+
update_parameters,
|
116
126
|
tags,
|
117
127
|
get_id,
|
118
128
|
id,
|
@@ -168,6 +178,7 @@ class Pipe:
|
|
168
178
|
temporary: bool = False,
|
169
179
|
upsert: Optional[bool] = None,
|
170
180
|
autoincrement: Optional[bool] = None,
|
181
|
+
autotime: Optional[bool] = None,
|
171
182
|
static: Optional[bool] = None,
|
172
183
|
enforce: Optional[bool] = None,
|
173
184
|
null_indices: Optional[bool] = None,
|
@@ -226,6 +237,9 @@ class Pipe:
|
|
226
237
|
autoincrement: Optional[bool], default None
|
227
238
|
If `True`, set `autoincrement` in the parameters.
|
228
239
|
|
240
|
+
autotime: Optional[bool], default None
|
241
|
+
If `True`, set `autotime` in the parameters.
|
242
|
+
|
229
243
|
static: Optional[bool], default None
|
230
244
|
If `True`, set `static` in the parameters.
|
231
245
|
|
@@ -264,7 +278,7 @@ class Pipe:
|
|
264
278
|
if location in ('[None]', 'None'):
|
265
279
|
location = None
|
266
280
|
|
267
|
-
from meerschaum.
|
281
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
268
282
|
negation_prefix = STATIC_CONFIG['system']['fetch_pipes_keys']['negation_prefix']
|
269
283
|
for k in (connector, metric, location, *(tags or [])):
|
270
284
|
if str(k).startswith(negation_prefix):
|
@@ -291,11 +305,13 @@ class Pipe:
|
|
291
305
|
warn(f"The provided parameters are of invalid type '{type(parameters)}'.")
|
292
306
|
self._attributes['parameters'] = {}
|
293
307
|
|
294
|
-
columns = columns or self._attributes.get('parameters', {}).get('columns',
|
295
|
-
if isinstance(columns, list):
|
308
|
+
columns = columns or self._attributes.get('parameters', {}).get('columns', None)
|
309
|
+
if isinstance(columns, (list, tuple)):
|
296
310
|
columns = {str(col): str(col) for col in columns}
|
297
311
|
if isinstance(columns, dict):
|
298
312
|
self._attributes['parameters']['columns'] = columns
|
313
|
+
elif isinstance(columns, str) and 'Pipe(' in columns:
|
314
|
+
pass
|
299
315
|
elif columns is not None:
|
300
316
|
warn(f"The provided columns are of invalid type '{type(columns)}'.")
|
301
317
|
|
@@ -334,6 +350,9 @@ class Pipe:
|
|
334
350
|
if isinstance(autoincrement, bool):
|
335
351
|
self._attributes['parameters']['autoincrement'] = autoincrement
|
336
352
|
|
353
|
+
if isinstance(autotime, bool):
|
354
|
+
self._attributes['parameters']['autotime'] = autotime
|
355
|
+
|
337
356
|
if isinstance(static, bool):
|
338
357
|
self._attributes['parameters']['static'] = static
|
339
358
|
|
@@ -383,9 +402,7 @@ class Pipe:
|
|
383
402
|
@property
|
384
403
|
def instance_connector(self) -> Union[InstanceConnector, None]:
|
385
404
|
"""
|
386
|
-
The connector
|
387
|
-
May either be of type `meerschaum.connectors.sql.SQLConnector` or
|
388
|
-
`meerschaum.connectors.api.APIConnector`.
|
405
|
+
The instance connector on which this pipe resides.
|
389
406
|
"""
|
390
407
|
if '_instance_connector' not in self.__dict__:
|
391
408
|
from meerschaum.connectors.parse import parse_instance_keys
|
@@ -397,7 +414,7 @@ class Pipe:
|
|
397
414
|
return self._instance_connector
|
398
415
|
|
399
416
|
@property
|
400
|
-
def connector(self) -> Union[
|
417
|
+
def connector(self) -> Union['Connector', None]:
|
401
418
|
"""
|
402
419
|
The connector to the data source.
|
403
420
|
"""
|
@@ -417,7 +434,7 @@ class Pipe:
|
|
417
434
|
return self._connector
|
418
435
|
|
419
436
|
@property
|
420
|
-
def cache_connector(self) -> Union[
|
437
|
+
def cache_connector(self) -> Union['Connector', None]:
|
421
438
|
"""
|
422
439
|
If the pipe was created with `cache=True`, return the connector to the pipe's
|
423
440
|
SQLite database for caching.
|
@@ -438,7 +455,7 @@ class Pipe:
|
|
438
455
|
return self._cache_connector
|
439
456
|
|
440
457
|
@property
|
441
|
-
def cache_pipe(self) -> Union[
|
458
|
+
def cache_pipe(self) -> Union[mrsm.Pipe, None]:
|
442
459
|
"""
|
443
460
|
If the pipe was created with `cache=True`, return another `meerschaum.Pipe` used to
|
444
461
|
manage the local data.
|
@@ -470,10 +487,10 @@ class Pipe:
|
|
470
487
|
self.instance_keys,
|
471
488
|
(self.connector_keys + '_' + self.metric_key + '_cache'),
|
472
489
|
self.location_key,
|
473
|
-
mrsm_instance
|
474
|
-
parameters
|
475
|
-
cache
|
476
|
-
temporary
|
490
|
+
mrsm_instance=self.cache_connector,
|
491
|
+
parameters=_parameters,
|
492
|
+
cache=False,
|
493
|
+
temporary=True,
|
477
494
|
)
|
478
495
|
|
479
496
|
return self._cache_pipe
|
@@ -8,6 +8,7 @@ Fetch and manipulate Pipes' attributes
|
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
10
|
|
11
|
+
import uuid
|
11
12
|
from datetime import timezone
|
12
13
|
|
13
14
|
import meerschaum as mrsm
|
@@ -48,21 +49,74 @@ def attributes(self) -> Dict[str, Any]:
|
|
48
49
|
return self._attributes
|
49
50
|
|
50
51
|
|
52
|
+
def get_parameters(
|
53
|
+
self,
|
54
|
+
apply_symlinks: bool = True,
|
55
|
+
_visited: 'Optional[set[mrsm.Pipe]]' = None,
|
56
|
+
) -> Dict[str, Any]:
|
57
|
+
"""
|
58
|
+
Return the `parameters` dictionary of the pipe.
|
59
|
+
"""
|
60
|
+
from meerschaum.config._patch import apply_patch_to_config
|
61
|
+
from meerschaum.utils.warnings import warn
|
62
|
+
from meerschaum.config._read_config import search_and_substitute_config
|
63
|
+
|
64
|
+
if _visited is None:
|
65
|
+
_visited = {self}
|
66
|
+
|
67
|
+
raw_parameters = self.attributes.get('parameters', {})
|
68
|
+
ref_keys = raw_parameters.get('reference')
|
69
|
+
if not apply_symlinks:
|
70
|
+
return raw_parameters
|
71
|
+
|
72
|
+
if ref_keys:
|
73
|
+
try:
|
74
|
+
ref_pipe = mrsm.Pipe(**ref_keys)
|
75
|
+
if ref_pipe in _visited:
|
76
|
+
warn(f"Circular reference detected in {self}: chain involves {ref_pipe}.")
|
77
|
+
return search_and_substitute_config(raw_parameters)
|
78
|
+
|
79
|
+
_visited.add(ref_pipe)
|
80
|
+
base_params = ref_pipe.get_parameters(_visited=_visited)
|
81
|
+
except Exception as e:
|
82
|
+
warn(f"Failed to resolve reference pipe for {self}: {e}")
|
83
|
+
base_params = {}
|
84
|
+
|
85
|
+
params_to_apply = {k: v for k, v in raw_parameters.items() if k != 'reference'}
|
86
|
+
parameters = apply_patch_to_config(base_params, params_to_apply)
|
87
|
+
else:
|
88
|
+
parameters = raw_parameters
|
89
|
+
|
90
|
+
from meerschaum.utils.pipes import replace_pipes_syntax
|
91
|
+
self._symlinks = {}
|
92
|
+
|
93
|
+
def recursive_replace(obj: Any, path: tuple) -> Any:
|
94
|
+
if isinstance(obj, dict):
|
95
|
+
return {k: recursive_replace(v, path + (k,)) for k, v in obj.items()}
|
96
|
+
if isinstance(obj, list):
|
97
|
+
return [recursive_replace(elem, path + (i,)) for i, elem in enumerate(obj)]
|
98
|
+
if isinstance(obj, str):
|
99
|
+
substituted_val = replace_pipes_syntax(obj)
|
100
|
+
if substituted_val != obj:
|
101
|
+
self._symlinks[path] = {
|
102
|
+
'original': obj,
|
103
|
+
'substituted': substituted_val,
|
104
|
+
}
|
105
|
+
return substituted_val
|
106
|
+
return obj
|
107
|
+
|
108
|
+
return search_and_substitute_config(recursive_replace(parameters, tuple()))
|
109
|
+
|
110
|
+
|
51
111
|
@property
|
52
112
|
def parameters(self) -> Optional[Dict[str, Any]]:
|
53
113
|
"""
|
54
114
|
Return the parameters dictionary of the pipe.
|
55
115
|
"""
|
56
|
-
if '
|
57
|
-
|
58
|
-
_parameters = self.
|
59
|
-
|
60
|
-
dt_typ = _parameters.get('dtypes', {}).get(dt_col, None) if dt_col else None
|
61
|
-
if dt_col and not dt_typ:
|
62
|
-
if 'dtypes' not in _parameters:
|
63
|
-
self.attributes['parameters']['dtypes'] = {}
|
64
|
-
self.attributes['parameters']['dtypes'][dt_col] = 'datetime'
|
65
|
-
return self.attributes['parameters']
|
116
|
+
if (_parameters := self.__dict__.get('_parameters', None)) is not None:
|
117
|
+
return _parameters
|
118
|
+
self._parameters = self.get_parameters()
|
119
|
+
return self._parameters
|
66
120
|
|
67
121
|
|
68
122
|
@parameters.setter
|
@@ -71,7 +125,9 @@ def parameters(self, parameters: Dict[str, Any]) -> None:
|
|
71
125
|
Set the parameters dictionary of the in-memory pipe.
|
72
126
|
Call `meerschaum.Pipe.edit()` to persist changes.
|
73
127
|
"""
|
74
|
-
self.
|
128
|
+
self._attributes['parameters'] = parameters
|
129
|
+
if '_parameters' in self.__dict__:
|
130
|
+
del self.__dict__['_parameters']
|
75
131
|
|
76
132
|
|
77
133
|
@property
|
@@ -79,12 +135,9 @@ def columns(self) -> Union[Dict[str, str], None]:
|
|
79
135
|
"""
|
80
136
|
Return the `columns` dictionary defined in `meerschaum.Pipe.parameters`.
|
81
137
|
"""
|
82
|
-
|
83
|
-
self.parameters['columns'] = {}
|
84
|
-
cols = self.parameters['columns']
|
138
|
+
cols = self.parameters.get('columns', {})
|
85
139
|
if not isinstance(cols, dict):
|
86
|
-
|
87
|
-
self.parameters['columns'] = cols
|
140
|
+
return {}
|
88
141
|
return {col_ix: col for col_ix, col in cols.items() if col}
|
89
142
|
|
90
143
|
|
@@ -99,7 +152,7 @@ def columns(self, _columns: Union[Dict[str, str], List[str]]) -> None:
|
|
99
152
|
if not isinstance(_columns, dict):
|
100
153
|
warn(f"{self}.columns must be a dictionary, received {type(_columns)}.")
|
101
154
|
return
|
102
|
-
self.
|
155
|
+
self.update_parameters({'columns': _columns}, persist=False)
|
103
156
|
|
104
157
|
|
105
158
|
@property
|
@@ -158,7 +211,7 @@ def indices(self, _indices: Union[Dict[str, Union[str, List[str]]], List[str]])
|
|
158
211
|
if 'indexes' in self.parameters
|
159
212
|
else 'indices'
|
160
213
|
)
|
161
|
-
self.
|
214
|
+
self.update_parameters({indices_key: _indices}, persist=False)
|
162
215
|
|
163
216
|
|
164
217
|
@indexes.setter
|
@@ -174,24 +227,22 @@ def tags(self) -> Union[List[str], None]:
|
|
174
227
|
"""
|
175
228
|
If defined, return the `tags` list defined in `meerschaum.Pipe.parameters`.
|
176
229
|
"""
|
177
|
-
|
178
|
-
self.parameters['tags'] = []
|
179
|
-
return self.parameters['tags']
|
230
|
+
return self.parameters.get('tags', [])
|
180
231
|
|
181
232
|
|
182
233
|
@tags.setter
|
183
|
-
def tags(self, _tags: List[str
|
234
|
+
def tags(self, _tags: List[str]) -> None:
|
184
235
|
"""
|
185
236
|
Override the tags list of the in-memory pipe.
|
186
237
|
Call `meerschaum.Pipe.edit` to persist changes.
|
187
238
|
"""
|
188
239
|
from meerschaum.utils.warnings import error
|
189
|
-
from meerschaum.
|
240
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
190
241
|
negation_prefix = STATIC_CONFIG['system']['fetch_pipes_keys']['negation_prefix']
|
191
242
|
for t in _tags:
|
192
243
|
if t.startswith(negation_prefix):
|
193
244
|
error(f"Tags cannot begin with '{negation_prefix}'.")
|
194
|
-
self.
|
245
|
+
self.update_parameters({'tags': _tags}, persist=False)
|
195
246
|
|
196
247
|
|
197
248
|
@property
|
@@ -204,11 +255,18 @@ def dtypes(self) -> Union[Dict[str, Any], None]:
|
|
204
255
|
configured_dtypes = self.parameters.get('dtypes', {})
|
205
256
|
remote_dtypes = self.infer_dtypes(persist=False)
|
206
257
|
patched_dtypes = apply_patch_to_config(remote_dtypes, configured_dtypes)
|
207
|
-
|
258
|
+
dt_col = self.columns.get('datetime', None)
|
259
|
+
primary_col = self.columns.get('primary', None)
|
260
|
+
_dtypes = {
|
208
261
|
col: MRSM_ALIAS_DTYPES.get(typ, typ)
|
209
262
|
for col, typ in patched_dtypes.items()
|
210
263
|
if col and typ
|
211
264
|
}
|
265
|
+
if dt_col and dt_col not in configured_dtypes:
|
266
|
+
_dtypes[dt_col] = 'datetime'
|
267
|
+
if primary_col and self.autoincrement and primary_col not in _dtypes:
|
268
|
+
_dtypes[primary_col] = 'int'
|
269
|
+
return _dtypes
|
212
270
|
|
213
271
|
|
214
272
|
@dtypes.setter
|
@@ -217,7 +275,7 @@ def dtypes(self, _dtypes: Dict[str, Any]) -> None:
|
|
217
275
|
Override the dtypes dictionary of the in-memory pipe.
|
218
276
|
Call `meerschaum.Pipe.edit()` to persist changes.
|
219
277
|
"""
|
220
|
-
self.
|
278
|
+
self.update_parameters({'dtypes': _dtypes}, persist=False)
|
221
279
|
|
222
280
|
|
223
281
|
@property
|
@@ -225,9 +283,7 @@ def upsert(self) -> bool:
|
|
225
283
|
"""
|
226
284
|
Return whether `upsert` is set for the pipe.
|
227
285
|
"""
|
228
|
-
|
229
|
-
self.parameters['upsert'] = False
|
230
|
-
return self.parameters['upsert']
|
286
|
+
return self.parameters.get('upsert', False)
|
231
287
|
|
232
288
|
|
233
289
|
@upsert.setter
|
@@ -235,7 +291,7 @@ def upsert(self, _upsert: bool) -> None:
|
|
235
291
|
"""
|
236
292
|
Set the `upsert` parameter for the pipe.
|
237
293
|
"""
|
238
|
-
self.
|
294
|
+
self.update_parameters({'upsert': _upsert}, persist=False)
|
239
295
|
|
240
296
|
|
241
297
|
@property
|
@@ -243,9 +299,7 @@ def static(self) -> bool:
|
|
243
299
|
"""
|
244
300
|
Return whether `static` is set for the pipe.
|
245
301
|
"""
|
246
|
-
|
247
|
-
self.parameters['static'] = False
|
248
|
-
return self.parameters['static']
|
302
|
+
return self.parameters.get('static', False)
|
249
303
|
|
250
304
|
|
251
305
|
@static.setter
|
@@ -253,7 +307,7 @@ def static(self, _static: bool) -> None:
|
|
253
307
|
"""
|
254
308
|
Set the `static` parameter for the pipe.
|
255
309
|
"""
|
256
|
-
self.
|
310
|
+
self.update_parameters({'static': _static}, persist=False)
|
257
311
|
|
258
312
|
|
259
313
|
@property
|
@@ -261,10 +315,7 @@ def autoincrement(self) -> bool:
|
|
261
315
|
"""
|
262
316
|
Return the `autoincrement` parameter for the pipe.
|
263
317
|
"""
|
264
|
-
|
265
|
-
self.parameters['autoincrement'] = False
|
266
|
-
|
267
|
-
return self.parameters['autoincrement']
|
318
|
+
return self.parameters.get('autoincrement', False)
|
268
319
|
|
269
320
|
|
270
321
|
@autoincrement.setter
|
@@ -272,7 +323,23 @@ def autoincrement(self, _autoincrement: bool) -> None:
|
|
272
323
|
"""
|
273
324
|
Set the `autoincrement` parameter for the pipe.
|
274
325
|
"""
|
275
|
-
self.
|
326
|
+
self.update_parameters({'autoincrement': _autoincrement}, persist=False)
|
327
|
+
|
328
|
+
|
329
|
+
@property
|
330
|
+
def autotime(self) -> bool:
|
331
|
+
"""
|
332
|
+
Return the `autotime` parameter for the pipe.
|
333
|
+
"""
|
334
|
+
return self.parameters.get('autotime', False)
|
335
|
+
|
336
|
+
|
337
|
+
@autotime.setter
|
338
|
+
def autotime(self, _autotime: bool) -> None:
|
339
|
+
"""
|
340
|
+
Set the `autotime` parameter for the pipe.
|
341
|
+
"""
|
342
|
+
self.update_parameters({'autotime': _autotime}, persist=False)
|
276
343
|
|
277
344
|
|
278
345
|
@property
|
@@ -299,10 +366,7 @@ def enforce(self) -> bool:
|
|
299
366
|
"""
|
300
367
|
Return the `enforce` parameter for the pipe.
|
301
368
|
"""
|
302
|
-
|
303
|
-
self.parameters['enforce'] = True
|
304
|
-
|
305
|
-
return self.parameters['enforce']
|
369
|
+
return self.parameters.get('enforce', True)
|
306
370
|
|
307
371
|
|
308
372
|
@enforce.setter
|
@@ -310,7 +374,7 @@ def enforce(self, _enforce: bool) -> None:
|
|
310
374
|
"""
|
311
375
|
Set the `enforce` parameter for the pipe.
|
312
376
|
"""
|
313
|
-
self.
|
377
|
+
self.update_parameters({'enforce': _enforce}, persist=False)
|
314
378
|
|
315
379
|
|
316
380
|
@property
|
@@ -318,10 +382,7 @@ def null_indices(self) -> bool:
|
|
318
382
|
"""
|
319
383
|
Return the `null_indices` parameter for the pipe.
|
320
384
|
"""
|
321
|
-
|
322
|
-
self.parameters['null_indices'] = True
|
323
|
-
|
324
|
-
return self.parameters['null_indices']
|
385
|
+
return self.parameters.get('null_indices', True)
|
325
386
|
|
326
387
|
|
327
388
|
@null_indices.setter
|
@@ -329,7 +390,7 @@ def null_indices(self, _null_indices: bool) -> None:
|
|
329
390
|
"""
|
330
391
|
Set the `null_indices` parameter for the pipe.
|
331
392
|
"""
|
332
|
-
self.
|
393
|
+
self.update_parameters({'null_indices': _null_indices}, persist=False)
|
333
394
|
|
334
395
|
|
335
396
|
def get_columns(self, *args: str, error: bool = False) -> Union[str, Tuple[str]]:
|
@@ -357,7 +418,7 @@ def get_columns(self, *args: str, error: bool = False) -> Union[str, Tuple[str]]
|
|
357
418
|
>>> pipe.get_columns('value', error=True)
|
358
419
|
Exception: 🛑 Missing 'value' column for Pipe('test', 'test').
|
359
420
|
"""
|
360
|
-
from meerschaum.utils.warnings import error as _error
|
421
|
+
from meerschaum.utils.warnings import error as _error
|
361
422
|
if not args:
|
362
423
|
args = tuple(self.columns.keys())
|
363
424
|
col_names = []
|
@@ -367,7 +428,7 @@ def get_columns(self, *args: str, error: bool = False) -> Union[str, Tuple[str]]
|
|
367
428
|
col_name = self.columns[col]
|
368
429
|
if col_name is None and error:
|
369
430
|
_error(f"Please define the name of the '{col}' column for {self}.")
|
370
|
-
except Exception
|
431
|
+
except Exception:
|
371
432
|
col_name = None
|
372
433
|
if col_name is None and error:
|
373
434
|
_error(f"Missing '{col}'" + f" column for {self}.")
|
@@ -409,7 +470,7 @@ def get_columns_types(
|
|
409
470
|
"""
|
410
471
|
import time
|
411
472
|
from meerschaum.connectors import get_connector_plugin
|
412
|
-
from meerschaum.
|
473
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
413
474
|
from meerschaum.utils.warnings import dprint
|
414
475
|
|
415
476
|
now = time.perf_counter()
|
@@ -454,7 +515,7 @@ def get_columns_indices(
|
|
454
515
|
"""
|
455
516
|
import time
|
456
517
|
from meerschaum.connectors import get_connector_plugin
|
457
|
-
from meerschaum.
|
518
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
458
519
|
from meerschaum.utils.warnings import dprint
|
459
520
|
|
460
521
|
now = time.perf_counter()
|
@@ -509,7 +570,7 @@ def get_id(self, **kw: Any) -> Union[int, None]:
|
|
509
570
|
|
510
571
|
|
511
572
|
@property
|
512
|
-
def id(self) -> Union[int, None]:
|
573
|
+
def id(self) -> Union[int, str, uuid.UUID, None]:
|
513
574
|
"""
|
514
575
|
Fetch and cache a pipe's ID.
|
515
576
|
"""
|
@@ -539,7 +600,7 @@ def get_val_column(self, debug: bool = False) -> Union[str, None]:
|
|
539
600
|
dprint('Attempting to determine the value column...')
|
540
601
|
try:
|
541
602
|
val_name = self.get_columns('value')
|
542
|
-
except Exception
|
603
|
+
except Exception:
|
543
604
|
val_name = None
|
544
605
|
if val_name is not None:
|
545
606
|
if debug:
|
@@ -553,11 +614,11 @@ def get_val_column(self, debug: bool = False) -> Union[str, None]:
|
|
553
614
|
return None
|
554
615
|
try:
|
555
616
|
dt_name = self.get_columns('datetime', error=False)
|
556
|
-
except Exception
|
617
|
+
except Exception:
|
557
618
|
dt_name = None
|
558
619
|
try:
|
559
620
|
id_name = self.get_columns('id', errors=False)
|
560
|
-
except Exception
|
621
|
+
except Exception:
|
561
622
|
id_name = None
|
562
623
|
|
563
624
|
if debug:
|
@@ -714,7 +775,7 @@ def target(self, _target: str) -> None:
|
|
714
775
|
Override the target of the in-memory pipe.
|
715
776
|
Call `meerschaum.Pipe.edit` to persist changes.
|
716
777
|
"""
|
717
|
-
self.
|
778
|
+
self.update_parameters({'target': _target}, persist=False)
|
718
779
|
|
719
780
|
|
720
781
|
def guess_datetime(self) -> Union[str, None]:
|
@@ -755,3 +816,40 @@ def get_indices(self) -> Dict[str, str]:
|
|
755
816
|
result = {}
|
756
817
|
|
757
818
|
return result
|
819
|
+
|
820
|
+
|
821
|
+
def update_parameters(
|
822
|
+
self,
|
823
|
+
parameters_patch: Dict[str, Any],
|
824
|
+
persist: bool = True,
|
825
|
+
debug: bool = False,
|
826
|
+
) -> mrsm.SuccessTuple:
|
827
|
+
"""
|
828
|
+
Apply a patch to a pipe's `parameters` dictionary.
|
829
|
+
|
830
|
+
Parameters
|
831
|
+
----------
|
832
|
+
parameters_patch: Dict[str, Any]
|
833
|
+
The patch to be applied to `Pipe.parameters`.
|
834
|
+
|
835
|
+
persist: bool, default True
|
836
|
+
If `True`, call `Pipe.edit()` to persist the new parameters.
|
837
|
+
"""
|
838
|
+
from meerschaum.config import apply_patch_to_config
|
839
|
+
if '_parameters' in self.__dict__:
|
840
|
+
del self.__dict__['_parameters']
|
841
|
+
if 'parameters' not in self._attributes:
|
842
|
+
self._attributes['parameters'] = {}
|
843
|
+
|
844
|
+
self._attributes['parameters'] = apply_patch_to_config(
|
845
|
+
self._attributes['parameters'],
|
846
|
+
parameters_patch,
|
847
|
+
)
|
848
|
+
|
849
|
+
if self.temporary:
|
850
|
+
persist = False
|
851
|
+
|
852
|
+
if not persist:
|
853
|
+
return True, "Success"
|
854
|
+
|
855
|
+
return self.edit(debug=debug)
|
@@ -7,6 +7,8 @@ Attempt to create a pipe's requirements in one method.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
11
|
+
import meerschaum as mrsm
|
10
12
|
from meerschaum.utils.typing import SuccessTuple, Dict, Any
|
11
13
|
|
12
14
|
|
@@ -207,28 +209,56 @@ def _ask_for_columns(pipe, debug: bool=False) -> Dict[str, str]:
|
|
207
209
|
"""
|
208
210
|
Prompt the user for the column names.
|
209
211
|
"""
|
210
|
-
|
211
|
-
from meerschaum.utils.
|
212
|
+
import json
|
213
|
+
from meerschaum.utils.warnings import info
|
214
|
+
from meerschaum.utils.prompt import prompt, yes_no
|
215
|
+
from meerschaum.utils.formatting import get_console
|
216
|
+
from meerschaum.utils.formatting._shell import clear_screen
|
217
|
+
from meerschaum.utils.misc import to_snake_case
|
218
|
+
from meerschaum.config import get_config
|
219
|
+
rich_json = mrsm.attempt_import('rich.json')
|
212
220
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
'
|
233
|
-
|
234
|
-
|
221
|
+
do_clear = get_config('shell', 'clear_screen')
|
222
|
+
|
223
|
+
cols = {}
|
224
|
+
|
225
|
+
info(f"Please enter index columns for {pipe}:")
|
226
|
+
try:
|
227
|
+
datetime_name = prompt("Datetime column (empty to omit):", icon=False)
|
228
|
+
except KeyboardInterrupt:
|
229
|
+
datetime_name = None
|
230
|
+
|
231
|
+
if datetime_name:
|
232
|
+
cols['datetime'] = datetime_name
|
233
|
+
|
234
|
+
try:
|
235
|
+
id_name = prompt("ID column (empty to omit):", icon=False)
|
236
|
+
except KeyboardInterrupt:
|
237
|
+
id_name = None
|
238
|
+
|
239
|
+
if id_name:
|
240
|
+
cols['id'] = id_name
|
241
|
+
|
242
|
+
if yes_no("Add more columns?"):
|
243
|
+
while True:
|
244
|
+
if do_clear:
|
245
|
+
clear_screen(debug=debug)
|
246
|
+
|
247
|
+
cols_text = json.dumps(cols, indent=4)
|
248
|
+
info("Current index columns:")
|
249
|
+
get_console().print(rich_json.JSON(cols_text))
|
250
|
+
|
251
|
+
col_name = prompt("Enter index column (empty to stop):")
|
252
|
+
if not col_name:
|
253
|
+
break
|
254
|
+
|
255
|
+
if col_name in cols.values():
|
256
|
+
continue
|
257
|
+
|
258
|
+
col_ix = to_snake_case(col_name)
|
259
|
+
if col_ix in cols:
|
260
|
+
col_ix = col_ix + '_'
|
261
|
+
|
262
|
+
cols[col_ix] = col_name
|
263
|
+
|
264
|
+
return cols
|