meerschaum 3.0.0rc2__py3-none-any.whl → 3.0.0rc4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. meerschaum/_internal/shell/Shell.py +5 -4
  2. meerschaum/actions/bootstrap.py +1 -1
  3. meerschaum/actions/edit.py +6 -3
  4. meerschaum/actions/start.py +1 -1
  5. meerschaum/api/_events.py +5 -0
  6. meerschaum/api/dash/callbacks/__init__.py +1 -0
  7. meerschaum/api/dash/callbacks/dashboard.py +93 -115
  8. meerschaum/api/dash/callbacks/jobs.py +11 -5
  9. meerschaum/api/dash/callbacks/pipes.py +194 -14
  10. meerschaum/api/dash/callbacks/settings/__init__.py +0 -1
  11. meerschaum/api/dash/callbacks/{settings/tokens.py → tokens.py} +3 -2
  12. meerschaum/api/dash/components.py +6 -7
  13. meerschaum/api/dash/jobs.py +1 -1
  14. meerschaum/api/dash/keys.py +17 -1
  15. meerschaum/api/dash/pages/__init__.py +2 -1
  16. meerschaum/api/dash/pages/{job.py → jobs.py} +10 -7
  17. meerschaum/api/dash/pages/pipes.py +16 -5
  18. meerschaum/api/dash/pages/settings/__init__.py +0 -1
  19. meerschaum/api/dash/pages/{settings/tokens.py → tokens.py} +6 -8
  20. meerschaum/api/dash/pipes.py +219 -3
  21. meerschaum/api/dash/tokens.py +27 -30
  22. meerschaum/config/_default.py +5 -4
  23. meerschaum/config/_paths.py +1 -0
  24. meerschaum/config/_version.py +1 -1
  25. meerschaum/connectors/instance/_tokens.py +6 -2
  26. meerschaum/connectors/sql/_SQLConnector.py +14 -0
  27. meerschaum/connectors/sql/_pipes.py +63 -23
  28. meerschaum/connectors/sql/tables/__init__.py +254 -122
  29. meerschaum/core/Pipe/__init__.py +17 -1
  30. meerschaum/core/Pipe/_attributes.py +5 -2
  31. meerschaum/core/Token/_Token.py +1 -1
  32. meerschaum/plugins/bootstrap.py +508 -3
  33. meerschaum/utils/_get_pipes.py +31 -5
  34. meerschaum/utils/dataframe.py +8 -2
  35. meerschaum/utils/dtypes/__init__.py +2 -3
  36. meerschaum/utils/dtypes/sql.py +11 -11
  37. meerschaum/utils/formatting/_pprint.py +1 -0
  38. meerschaum/utils/pipes.py +6 -2
  39. meerschaum/utils/sql.py +1 -1
  40. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/METADATA +1 -1
  41. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/RECORD +47 -47
  42. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/WHEEL +0 -0
  43. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/entry_points.txt +0 -0
  44. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/licenses/LICENSE +0 -0
  45. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/licenses/NOTICE +0 -0
  46. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/top_level.txt +0 -0
  47. {meerschaum-3.0.0rc2.dist-info → meerschaum-3.0.0rc4.dist-info}/zip-safe +0 -0
@@ -9,7 +9,7 @@ Dash utility functions for constructing tokens components.
9
9
  from __future__ import annotations
10
10
 
11
11
  from datetime import datetime, timezone, timedelta
12
- from typing import Any, List
12
+ from typing import Any, List, Optional
13
13
 
14
14
  import meerschaum as mrsm
15
15
  from meerschaum.api import debug, CHECK_UPDATE, get_api_connector
@@ -65,7 +65,7 @@ def get_tokens_table(session_id: Optional[str] = None) -> Tuple[dbc.Table, List[
65
65
  html.Td("✅" if token.is_valid else "❌"),
66
66
  html.Td([
67
67
  dbc.Button(
68
- html.B(""),
68
+ html.B(""),
69
69
  color='link',
70
70
  size='sm',
71
71
  id={'type': 'tokens-context-button', 'index': str(token.id)},
@@ -91,39 +91,36 @@ def build_manage_token_popover(token: Token) -> dbc.Popover:
91
91
  """
92
92
  return dbc.Popover(
93
93
  [
94
- dbc.PopoverHeader(["Manage token"]),
95
- dbc.PopoverBody([
96
- dbc.ButtonGroup(
97
- ([
98
- dbc.Button(
99
- "Edit",
100
- outline=True,
101
- color='light',
102
- id={
103
- 'type': 'tokens-edit-button',
104
- 'index': str(token.id),
105
- },
106
- ),
107
- dbc.Button(
108
- "Invalidate",
109
- outline=True,
110
- color='warning',
111
- id={
112
- 'type': 'tokens-invalidate-button',
113
- 'index': str(token.id),
114
- },
115
- ),
116
- ] if token.is_valid else []) + [
94
+ dbc.ButtonGroup(
95
+ ([
117
96
  dbc.Button(
118
- "Delete",
119
- color='danger',
97
+ "Edit",
120
98
  outline=True,
99
+ color='light',
121
100
  id={
122
- 'type': 'tokens-delete-button',
101
+ 'type': 'tokens-edit-button',
123
102
  'index': str(token.id),
124
103
  },
125
104
  ),
126
- ]),
105
+ dbc.Button(
106
+ "Invalidate",
107
+ outline=True,
108
+ color='warning',
109
+ id={
110
+ 'type': 'tokens-invalidate-button',
111
+ 'index': str(token.id),
112
+ },
113
+ ),
114
+ ] if token.is_valid else []) + [
115
+ dbc.Button(
116
+ "Delete",
117
+ color='danger',
118
+ outline=True,
119
+ id={
120
+ 'type': 'tokens-delete-button',
121
+ 'index': str(token.id),
122
+ },
123
+ ),
127
124
  ]),
128
125
  ],
129
126
  body=True,
@@ -600,7 +597,7 @@ def build_tokens_register_output_modal(token: Token) -> List[Any]:
600
597
  dbc.Button(
601
598
  "Close",
602
599
  id='tokens-close-register-output-modal-button',
603
- disabled=True,
600
+ disabled=success,
604
601
  ),
605
602
  ]),
606
603
  ]
@@ -99,6 +99,7 @@ default_system_config = {
99
99
  'mssql': True,
100
100
  },
101
101
  'instance': {
102
+ 'create_metadata_cache_minutes': 14400,
102
103
  'stale_temporary_tables_minutes': 1440,
103
104
  'temporary_target': {
104
105
  'prefix': '_',
@@ -199,11 +200,11 @@ default_pipes_config = {
199
200
  },
200
201
  },
201
202
  'attributes': {
202
- 'local_cache_timeout_seconds': 60,
203
+ 'local_cache_timeout_seconds': 600.0,
203
204
  },
204
205
  'sync': {
205
206
  'filter_params_index_limit': 250,
206
- 'exists_cache_seconds': 5.0,
207
+ 'exists_cache_seconds': 60.0,
207
208
  },
208
209
  'verify': {
209
210
  'max_chunks_syncs': 3,
@@ -213,10 +214,10 @@ default_pipes_config = {
213
214
  },
214
215
  'dtypes': {
215
216
  'min_ratio_columns_changed_for_full_astype': 0.5,
216
- 'columns_types_cache_seconds': 5.0,
217
+ 'columns_types_cache_seconds': 60.0,
217
218
  },
218
219
  'static': {
219
- 'static_schema_cache_seconds': 60.0,
220
+ 'static_schema_cache_seconds': 3600.0,
220
221
  },
221
222
  }
222
223
  default_plugins_config = {}
@@ -149,6 +149,7 @@ paths = {
149
149
  'PIPES_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'pipes'),
150
150
  'USERS_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'users'),
151
151
  'VENVS_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'venvs'),
152
+ 'SQL_CONN_CACHE_RESOURCES_PATH' : ('{CACHE_RESOURCES_PATH}', 'sql'),
152
153
 
153
154
  'PLUGINS_RESOURCES_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins'),
154
155
  'PLUGINS_INTERNAL_LOCK_PATH' : ('{INTERNAL_RESOURCES_PATH}', 'plugins.lock'),
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "3.0.0rc2"
5
+ __version__ = "3.0.0rc4"
@@ -53,7 +53,11 @@ def get_tokens_pipe(self) -> mrsm.Pipe:
53
53
  )
54
54
 
55
55
 
56
- def register_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple:
56
+ def register_token(
57
+ self,
58
+ token: Token,
59
+ debug: bool = False,
60
+ ) -> mrsm.SuccessTuple:
57
61
  """
58
62
  Register the new token to the tokens table.
59
63
  """
@@ -61,7 +65,7 @@ def register_token(self, token: Token, debug: bool = False) -> mrsm.SuccessTuple
61
65
  tokens_pipe = self.get_tokens_pipe()
62
66
  user_id = self.get_user_id(token.user) if token.user is not None else None
63
67
  if user_id is None:
64
- raise ValueError("Cannot register a token without a user.")
68
+ return False, "Cannot register a token without a user."
65
69
 
66
70
  doc = {
67
71
  'id': token_id,
@@ -7,6 +7,8 @@ Interface with SQL servers using sqlalchemy.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
+
11
+ import pathlib
10
12
  import meerschaum as mrsm
11
13
  from meerschaum.utils.typing import Optional, Any, Union
12
14
 
@@ -376,6 +378,18 @@ class SQLConnector(InstanceConnector):
376
378
  self.__dict__['schema'] = _schema
377
379
  return _schema
378
380
 
381
+ def get_metadata_cache_path(self, kind: str = 'json') -> pathlib.Path:
382
+ """
383
+ Return the path to the file to which to write metadata cache.
384
+ """
385
+ from meerschaum.config.paths import SQL_CONN_CACHE_RESOURCES_PATH
386
+ filename = (
387
+ f'{self.label}-metadata.pkl'
388
+ if kind == 'pkl'
389
+ else f'{self.label}.json'
390
+ )
391
+ return SQL_CONN_CACHE_RESOURCES_PATH / filename
392
+
379
393
  def __getstate__(self):
380
394
  return self.__dict__
381
395
 
@@ -147,7 +147,9 @@ def fetch_pipes_keys(
147
147
  tags: Optional[List[str]] = None,
148
148
  params: Optional[Dict[str, Any]] = None,
149
149
  debug: bool = False
150
- ) -> Optional[List[Tuple[str, str, Optional[str]]]]:
150
+ ) -> List[
151
+ Tuple[str, str, Union[str, None], Dict[str, Any]]
152
+ ]:
151
153
  """
152
154
  Return a list of tuples corresponding to the parameters provided.
153
155
 
@@ -162,16 +164,27 @@ def fetch_pipes_keys(
162
164
  location_keys: Optional[List[str]], default None
163
165
  List of location_keys to search by.
164
166
 
167
+ tags: Optional[List[str]], default None
168
+ List of pipes to search by.
169
+
165
170
  params: Optional[Dict[str, Any]], default None
166
171
  Dictionary of additional parameters to search by.
167
172
  E.g. `--params pipe_id:1`
168
173
 
169
174
  debug: bool, default False
170
175
  Verbosity toggle.
176
+
177
+ Returns
178
+ -------
179
+ A list of tuples of pipes' keys and parameters (connector_keys, metric_key, location_key, parameters).
171
180
  """
172
181
  from meerschaum.utils.packages import attempt_import
173
182
  from meerschaum.utils.misc import separate_negation_values
174
- from meerschaum.utils.sql import OMIT_NULLSFIRST_FLAVORS, table_exists
183
+ from meerschaum.utils.sql import (
184
+ OMIT_NULLSFIRST_FLAVORS,
185
+ table_exists,
186
+ json_flavors,
187
+ )
175
188
  from meerschaum._internal.static import STATIC_CONFIG
176
189
  import json
177
190
  from copy import deepcopy
@@ -243,6 +256,11 @@ def fetch_pipes_keys(
243
256
  pipes_tbl.c.connector_keys,
244
257
  pipes_tbl.c.metric_key,
245
258
  pipes_tbl.c.location_key,
259
+ (
260
+ pipes_tbl.c.parameters['tags']
261
+ if self.flavor in json_flavors
262
+ else pipes_tbl.c.parameters
263
+ ),
246
264
  ]
247
265
  )
248
266
 
@@ -259,25 +277,47 @@ def fetch_pipes_keys(
259
277
  in_ex_tag_groups = [separate_negation_values(tag_group) for tag_group in tag_groups]
260
278
 
261
279
  ors, nands = [], []
262
- for _in_tags, _ex_tags in in_ex_tag_groups:
263
- sub_ands = []
264
- for nt in _in_tags:
265
- sub_ands.append(
266
- sqlalchemy.cast(
267
- pipes_tbl.c['parameters'],
268
- sqlalchemy.String,
269
- ).like(f'%"tags":%"{nt}"%')
270
- )
271
- if sub_ands:
272
- ors.append(sqlalchemy.and_(*sub_ands))
273
-
274
- for xt in _ex_tags:
275
- nands.append(
276
- sqlalchemy.cast(
277
- pipes_tbl.c['parameters'],
278
- sqlalchemy.String,
279
- ).not_like(f'%"tags":%"{xt}"%')
280
- )
280
+ if self.flavor in json_flavors:
281
+ from sqlalchemy.dialects import postgresql
282
+ for _in_tags, _ex_tags in in_ex_tag_groups:
283
+ if _in_tags:
284
+ ors.append(
285
+ sqlalchemy.and_(
286
+ pipes_tbl.c['parameters']['tags'].cast(
287
+ postgresql.JSONB
288
+ ).contains(_in_tags)
289
+ )
290
+ )
291
+ for xt in _ex_tags:
292
+ nands.append(
293
+ sqlalchemy.not_(
294
+ sqlalchemy.and_(
295
+ pipes_tbl.c['parameters']['tags'].cast(
296
+ postgresql.JSONB
297
+ ).contains([xt])
298
+ )
299
+ )
300
+ )
301
+ else:
302
+ for _in_tags, _ex_tags in in_ex_tag_groups:
303
+ sub_ands = []
304
+ for nt in _in_tags:
305
+ sub_ands.append(
306
+ sqlalchemy.cast(
307
+ pipes_tbl.c['parameters'],
308
+ sqlalchemy.String,
309
+ ).like(f'%"tags":%"{nt}"%')
310
+ )
311
+ if sub_ands:
312
+ ors.append(sqlalchemy.and_(*sub_ands))
313
+
314
+ for xt in _ex_tags:
315
+ nands.append(
316
+ sqlalchemy.cast(
317
+ pipes_tbl.c['parameters'],
318
+ sqlalchemy.String,
319
+ ).not_like(f'%"tags":%"{xt}"%')
320
+ )
281
321
 
282
322
  q = q.where(sqlalchemy.and_(*nands)) if nands else q
283
323
  q = q.where(sqlalchemy.or_(*ors)) if ors else q
@@ -292,7 +332,7 @@ def fetch_pipes_keys(
292
332
 
293
333
  ### execute the query and return a list of tuples
294
334
  if debug:
295
- dprint(q.compile(compile_kwargs={'literal_binds': True}))
335
+ dprint(q)
296
336
  try:
297
337
  rows = (
298
338
  self.execute(q).fetchall()
@@ -305,7 +345,7 @@ def fetch_pipes_keys(
305
345
  except Exception as e:
306
346
  error(str(e))
307
347
 
308
- return [(row[0], row[1], row[2]) for row in rows]
348
+ return rows
309
349
 
310
350
 
311
351
  def create_pipe_indices(