meerschaum 3.0.0rc3__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.
meerschaum/api/_events.py CHANGED
@@ -98,6 +98,11 @@ async def startup():
98
98
  await shutdown()
99
99
  os._exit(1)
100
100
 
101
+ conn = get_api_connector()
102
+ if conn.type == 'sql':
103
+ from meerschaum.connectors.sql.tables import get_tables
104
+ _ = get_tables(conn, refresh=True, create=True, debug=debug)
105
+
101
106
  start_check_jobs_thread()
102
107
 
103
108
 
@@ -498,13 +498,9 @@ def update_flags(input_flags_dropdown_values, n_clicks, input_flags_texts):
498
498
 
499
499
  @dash_app.callback(
500
500
  Output('connector-keys-dropdown', 'options'),
501
- Output('connector-keys-dropdown', 'value'),
502
501
  Output('metric-keys-dropdown', 'options'),
503
- Output('metric-keys-dropdown', 'value'),
504
502
  Output('location-keys-dropdown', 'options'),
505
- Output('location-keys-dropdown', 'value'),
506
503
  Output('tags-dropdown', 'options'),
507
- Output('tags-dropdown', 'value'),
508
504
  Output('instance-select', 'value'),
509
505
  Output('instance-alert-div', 'children'),
510
506
  Input('connector-keys-dropdown', 'value'),
@@ -546,15 +542,6 @@ def update_keys_options(
546
542
  except Exception as e:
547
543
  instance_alerts += [alert_from_success_tuple((False, str(e)))]
548
544
 
549
- ### Update the keys filters.
550
- if connector_keys is None:
551
- connector_keys = []
552
- if metric_keys is None:
553
- metric_keys = []
554
- if location_keys is None:
555
- location_keys = []
556
- if tags is None:
557
- tags = []
558
545
  num_filter = 0
559
546
  if connector_keys:
560
547
  num_filter += 1
@@ -565,10 +552,6 @@ def update_keys_options(
565
552
  if tags:
566
553
  num_filter += 1
567
554
 
568
- _ck_filter = connector_keys
569
- _mk_filter = metric_keys
570
- _lk_filter = location_keys
571
- _tags_filter = tags
572
555
  _ck_alone = (connector_keys and num_filter == 1) or instance_click
573
556
  _mk_alone = (metric_keys and num_filter == 1) or instance_click
574
557
  _lk_alone = (location_keys and num_filter == 1) or instance_click
@@ -581,101 +564,95 @@ def update_keys_options(
581
564
  _keys = fetch_pipes_keys(
582
565
  'registered',
583
566
  get_web_connector(ctx.states),
584
- connector_keys=_ck_filter,
585
- metric_keys=_mk_filter,
586
- location_keys=_lk_filter,
587
- tags=_tags_filter,
567
+ connector_keys=connector_keys,
568
+ metric_keys=metric_keys,
569
+ location_keys=location_keys,
570
+ tags=tags,
588
571
  )
589
572
  _tags_pipes = mrsm.get_pipes(
590
- connector_keys=_ck_filter,
591
- metric_keys=_mk_filter,
592
- location_keys=_lk_filter,
593
- tags=_tags_filter,
573
+ connector_keys=connector_keys,
574
+ metric_keys=metric_keys,
575
+ location_keys=location_keys,
576
+ tags=tags,
594
577
  instance=get_web_connector(ctx.states),
595
578
  as_tags_dict=True,
596
579
  )
597
580
  _all_tags = list(
598
- mrsm.get_pipes(
599
- instance=get_web_connector(ctx.states),
600
- as_tags_dict=True,
601
- )
581
+ set(
582
+ mrsm.get_pipes(
583
+ instance=get_web_connector(ctx.states),
584
+ as_tags_dict=True,
585
+ )
586
+ ).union(tags or [])
602
587
  ) if _tags_alone else []
603
588
  except Exception as e:
604
589
  instance_alerts += [alert_from_success_tuple((False, str(e)))]
605
- _all_keys, _keys = [], []
606
- _connectors_options = []
607
- _metrics_options = []
608
- _locations_options = []
609
- _tags_options = []
610
-
611
- _seen_keys = {'ck' : set(), 'mk' : set(), 'lk' : set(), 'tags': set()}
612
-
613
- def add_options(options, keys, key_type):
614
- for ck, mk, lk in keys:
615
- k = locals()[key_type]
616
- if k not in _seen_keys[key_type]:
617
- _k = 'None' if k in (None, '[None]', 'None', 'null') else k
618
- options.append({'label': _k, 'value': _k})
619
- _seen_keys[key_type].add(k)
620
-
621
- add_options(_connectors_options, _all_keys if _ck_alone else _keys, 'ck')
622
- add_options(_metrics_options, _all_keys if _mk_alone else _keys, 'mk')
623
- add_options(_locations_options, _all_keys if _lk_alone else _keys, 'lk')
624
-
625
- _tags_options = [
626
- {'label': tag, 'value': tag}
627
- for tag in (_all_tags if _tags_alone else _tags_pipes)
628
- ]
590
+ _all_keys, _all_tags, _keys = [], [], []
591
+
592
+ connectors_options = sorted(
593
+ list(
594
+ set(
595
+ keys_tuple[0] for keys_tuple in (_all_keys if _ck_alone else _keys)
596
+ ).union(set(connector_keys or []))
597
+ ),
598
+ key=(lambda x: str(x).lower()),
599
+ )
600
+ metrics_options = sorted(
601
+ list(
602
+ set(
603
+ keys_tuple[1] for keys_tuple in (_all_keys if _mk_alone else _keys)
604
+ ).union(set(metric_keys or []))
605
+ ),
606
+ key=(lambda x: str(x).lower()),
607
+ )
608
+ locations_options = sorted(
609
+ list(
610
+ set(
611
+ (
612
+ str(keys_tuple[2])
613
+ for keys_tuple in (_all_keys if _lk_alone else _keys)
614
+ )
615
+ ).union(set((str(_lk) for _lk in (location_keys or []))))
616
+ ),
617
+ key=(lambda x: str(x).lower()),
618
+ )
619
+
620
+ tags_options = sorted(
621
+ list(
622
+ set(
623
+ (_all_tags if _tags_alone else _tags_pipes)
624
+ ).union(set(tags or []))
625
+ ),
626
+ key=(lambda x: str(x).lower()),
627
+ )
629
628
 
630
- _connectors_options.sort(key=lambda x: str(x).lower())
631
- _metrics_options.sort(key=lambda x: str(x).lower())
632
- _locations_options.sort(key=lambda x: str(x).lower())
633
- _tags_options.sort(key=lambda x: str(x).lower())
634
- connector_keys = [
635
- ck
636
- for ck in connector_keys
637
- if ck in [
638
- _ck['value']
639
- for _ck in _connectors_options
640
- ]
641
- ]
642
- metric_keys = [
643
- mk
644
- for mk in metric_keys
645
- if mk in [
646
- _mk['value']
647
- for _mk in _metrics_options
648
- ]
649
- ]
650
- location_keys = [
651
- lk
652
- for lk in location_keys
653
- if lk in [
654
- _lk['value']
655
- for _lk in _locations_options
656
- ]
657
- ]
658
- tags = [
659
- tag
660
- for tag in tags
661
- if tag in [
662
- _tag['value']
663
- for _tag in _tags_options
664
- ]
665
- ]
666
629
  return (
667
- _connectors_options,
668
- connector_keys,
669
- _metrics_options,
670
- metric_keys,
671
- _locations_options,
672
- location_keys,
673
- _tags_options,
674
- tags,
630
+ connectors_options,
631
+ metrics_options,
632
+ locations_options,
633
+ tags_options,
675
634
  (instance_keys if update_instance_keys else dash.no_update),
676
635
  instance_alerts,
677
636
  )
678
637
 
638
+
639
+ @dash_app.callback(
640
+ Output('connector-keys-dropdown', 'value'),
641
+ Output('metric-keys-dropdown', 'value'),
642
+ Output('location-keys-dropdown', 'value'),
643
+ Output('tags-dropdown', 'value'),
644
+ Input('clear-all-keys-button', 'n_clicks'),
645
+ prevent_initial_call=True,
646
+ )
647
+ def clear_all_keys_button_click(n_clicks):
648
+ """
649
+ Clear the keys dropdowns when the `Clear all` button is clicked.
650
+ """
651
+ if not n_clicks:
652
+ raise PreventUpdate
653
+
654
+ return [], [], [], []
655
+
679
656
  dash_app.clientside_callback(
680
657
  """
681
658
  function(
@@ -5,28 +5,35 @@
5
5
  Define callbacks for the `/dash/pipes/` page.
6
6
  """
7
7
 
8
- from urllib.parse import parse_qs
8
+ from urllib.parse import parse_qs, quote_plus
9
+ from typing import List, Optional, Dict, Any
9
10
 
11
+ import dash
10
12
  from dash.dependencies import Input, Output, State
11
13
  from dash import no_update
12
14
  from dash.exceptions import PreventUpdate
15
+ import dash_bootstrap_components as dbc
13
16
 
14
17
  import meerschaum as mrsm
15
18
  from meerschaum.api.dash import dash_app
16
- from meerschaum.api.dash.components import alert_from_success_tuple, build_cards_grid
19
+ from meerschaum.api.dash.components import (
20
+ alert_from_success_tuple,
21
+ build_cards_grid,
22
+ )
17
23
  from meerschaum.api.dash.pipes import (
18
24
  build_pipe_card,
19
25
  build_pipes_dropdown_keys_row,
20
26
  build_pipes_tags_dropdown,
27
+ build_pipes_navbar,
21
28
  )
22
29
  from meerschaum.api import CHECK_UPDATE, get_api_connector
23
30
  from meerschaum.utils.packages import import_html, import_dcc
24
31
  from meerschaum.api.dash.sessions import is_session_authenticated
25
- from meerschaum.utils.typing import Optional, Dict, Any
26
32
  html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
27
33
 
28
34
 
29
35
  @dash_app.callback(
36
+ Output('pipes-navbar-div', 'children'),
30
37
  Output('pipe-output-div', 'children'),
31
38
  Input('pipes-location', 'pathname'),
32
39
  State('pipes-location', 'search'),
@@ -38,7 +45,7 @@ def render_pipe_page_from_url(
38
45
  session_data: Optional[Dict[str, Any]],
39
46
  ):
40
47
  if not str(pathname).startswith('/dash/pipes'):
41
- return no_update
48
+ raise PreventUpdate
42
49
 
43
50
  session_id = (session_data or {}).get('session-id', None)
44
51
  authenticated = is_session_authenticated(str(session_id))
@@ -60,63 +67,103 @@ def render_pipe_page_from_url(
60
67
  if isinstance(location_keys, str):
61
68
  location_keys = location_keys.split(',')
62
69
 
70
+ keys = pathname.replace('/dash/pipes', '').lstrip('/').rstrip('/').split('/')
63
71
  instance_connector = mrsm.get_connector(instance)
72
+ viewing_single_pipe = len(keys) in (2, 3)
64
73
  if instance_connector is None:
65
- return [
66
- html.Br(),
67
- alert_from_success_tuple((False, f"Invalid instance keys '{instance}'.")),
68
- html.Br(),
69
- ]
70
-
71
- keys = pathname.replace('/dash/pipes', '').lstrip('/').rstrip('/').split('/')
72
- if len(keys) not in (2, 3):
73
- pipes = mrsm.get_pipes(
74
- as_list=True,
75
- connector_keys=connector_keys,
76
- metric_keys=metric_keys,
77
- location_keys=location_keys,
78
- tags=tags,
79
- instance=instance_connector,
74
+ return (
75
+ build_pipes_navbar(instance, with_instance_select=(not viewing_single_pipe)),
76
+ [
77
+ html.Br(),
78
+ alert_from_success_tuple((False, f"Invalid instance keys '{instance}'.")),
79
+ html.Br(),
80
+ ]
80
81
  )
82
+
83
+ if not viewing_single_pipe:
84
+ try:
85
+ pipes = mrsm.get_pipes(
86
+ as_list=True,
87
+ connector_keys=connector_keys,
88
+ metric_keys=metric_keys,
89
+ location_keys=location_keys,
90
+ tags=tags,
91
+ instance=instance_connector,
92
+ )
93
+ except Exception as e:
94
+ return (
95
+ build_pipes_navbar(instance, with_instance_select=False),
96
+ [
97
+ html.Br(),
98
+ alert_from_success_tuple(
99
+ (False, f"Failed to get pipes for instance '{instance}':\n{e}")
100
+ ),
101
+ html.Br(),
102
+ dbc.Row(
103
+ [
104
+ dbc.Button(
105
+ "Reload",
106
+ id='pipes-reload-button',
107
+ size='lg',
108
+ href=(
109
+ "/dash/pipes"
110
+ if pathname.startswith('/dash/pipes/')
111
+ else "/dash/pipes/"
112
+ )
113
+ ),
114
+ ],
115
+ justify='center',
116
+ align='center',
117
+ className='h-50',
118
+ ),
119
+ ]
120
+ )
121
+
81
122
  cards = [
82
123
  build_pipe_card(pipe, authenticated=authenticated, include_manage=False)
83
124
  for pipe in pipes
84
125
  ]
85
- return [
86
- html.Div([
126
+ return (
127
+ build_pipes_navbar(instance, with_instance_select=True),
128
+ [
129
+ html.Div([
130
+ html.Br(),
131
+ build_pipes_dropdown_keys_row(
132
+ connector_keys,
133
+ metric_keys,
134
+ location_keys,
135
+ tags,
136
+ pipes,
137
+ instance_connector,
138
+ ),
139
+ html.Br(),
140
+ build_pipes_tags_dropdown(
141
+ connector_keys,
142
+ metric_keys,
143
+ location_keys,
144
+ tags,
145
+ instance,
146
+ ),
147
+ ]),
87
148
  html.Br(),
88
- build_pipes_dropdown_keys_row(
89
- connector_keys,
90
- metric_keys,
91
- location_keys,
92
- tags,
93
- pipes,
94
- instance_connector,
95
- ),
149
+ build_cards_grid(cards, 1),
96
150
  html.Br(),
97
- build_pipes_tags_dropdown(
98
- connector_keys,
99
- metric_keys,
100
- location_keys,
101
- tags,
102
- instance,
103
- ),
104
- ]),
105
- html.Br(),
106
- build_cards_grid(cards, 1),
107
- html.Br(),
108
- ]
151
+ ]
152
+ )
109
153
 
110
154
  ck = keys[0]
111
155
  mk = keys[1]
112
156
  lk = keys[2] if len(keys) == 3 else None
113
157
 
114
158
  pipe = mrsm.Pipe(ck, mk, lk, instance=instance)
115
- return [
116
- html.Br(),
117
- build_pipe_card(pipe, authenticated=authenticated, include_manage=False),
118
- html.Br(),
119
- ]
159
+ return (
160
+ build_pipes_navbar(instance, with_instance_select=False),
161
+ [
162
+ html.Br(),
163
+ build_pipe_card(pipe, authenticated=authenticated, include_manage=False),
164
+ html.Br(),
165
+ ]
166
+ )
120
167
 
121
168
 
122
169
  @dash_app.callback(
@@ -125,32 +172,64 @@ def render_pipe_page_from_url(
125
172
  Input('pipes-metric-keys-dropdown', 'value'),
126
173
  Input('pipes-location-keys-dropdown', 'value'),
127
174
  Input('pipes-tags-dropdown', 'value'),
175
+ Input('instance-select', 'value'),
176
+ Input('pipes-clear-all-button', 'n_clicks'),
128
177
  )
129
- def update_location_on_pipes_filter_change(connector_keys, metric_keys, location_keys, tags):
178
+ def update_location_on_pipes_filter_change(
179
+ connector_keys: Optional[List[str]],
180
+ metric_keys: Optional[List[str]],
181
+ location_keys: Optional[List[str]],
182
+ tags: Optional[List[str]],
183
+ instance_keys: str,
184
+ clear_all_button_n_clicks: Optional[int],
185
+ ):
130
186
  """
131
187
  Update the URL parameters when clicking the dropdowns.
132
188
  """
133
- if not any((connector_keys or []) + (metric_keys or []) + (location_keys or []) + (tags or [])):
189
+ ctx = dash.callback_context.triggered
190
+ if len(ctx) != 1:
191
+ raise PreventUpdate
192
+
193
+ if not any(
194
+ (connector_keys or [])
195
+ + (metric_keys or [])
196
+ + (location_keys or [])
197
+ + (tags or [])
198
+ + ([instance_keys] if instance_keys else [])
199
+ ):
134
200
  return ''
135
201
 
136
- search_str = "?"
202
+ if ctx[0].get('prop_id', None) == 'pipes-clear-all-button.n_clicks':
203
+ connector_keys = []
204
+ metric_keys = []
205
+ location_keys = []
206
+ tags = []
207
+
208
+ include_instance_keys = instance_keys and instance_keys != str(get_api_connector())
209
+ search_str = ""
137
210
 
138
211
  if connector_keys:
139
- search_str += "connector_keys=" + ','.join(connector_keys)
140
- if metric_keys or location_keys or tags:
212
+ search_str += "connector_keys=" + ','.join((quote_plus(ck) for ck in connector_keys))
213
+ if metric_keys or location_keys or tags or include_instance_keys:
141
214
  search_str += '&'
142
215
 
143
216
  if metric_keys:
144
- search_str += "metric_keys=" + ','.join(metric_keys)
145
- if location_keys or tags:
217
+ search_str += "metric_keys=" + ','.join((quote_plus(mk) for mk in metric_keys))
218
+ if location_keys or tags or include_instance_keys:
146
219
  search_str += '&'
147
220
 
148
221
  if location_keys:
149
- search_str += "location_keys=" + ','.join(location_keys)
150
- if tags:
222
+ search_str += "location_keys=" + ','.join((quote_plus(str(lk)) for lk in location_keys))
223
+ if tags or include_instance_keys:
151
224
  search_str += '&'
152
225
 
153
226
  if tags:
154
- search_str += "tags=" + ','.join(tags)
227
+ search_str += "tags=" + ','.join((quote_plus(tag) for tag in tags))
228
+ if include_instance_keys:
229
+ search_str += '&'
230
+
231
+ if instance_keys:
232
+ if include_instance_keys:
233
+ search_str += "instance=" + quote_plus(instance_keys)
155
234
 
156
- return search_str
235
+ return ('?' + search_str) if search_str else ''
@@ -54,7 +54,8 @@ def refresh_tokens_button_click(
54
54
  html.H4('No tokens registered.'),
55
55
  html.P('Click the `+` button to register a new token.'),
56
56
  ],
57
- alerts
57
+ build_tokens_register_input_modal(),
58
+ alerts,
58
59
  )
59
60
 
60
61
  return tokens_table, build_tokens_register_input_modal(), alerts
@@ -13,7 +13,7 @@ from meerschaum.utils.typing import SuccessTuple, List
13
13
  from meerschaum._internal.static import STATIC_CONFIG
14
14
  from meerschaum.utils.misc import remove_ansi
15
15
  from meerschaum._internal.shell.Shell import get_shell_intro
16
- from meerschaum.api import endpoints, CHECK_UPDATE, docs_enabled
16
+ from meerschaum.api import endpoints, CHECK_UPDATE, docs_enabled, get_api_connector
17
17
  from meerschaum.connectors import instance_types, _load_builtin_custom_connectors
18
18
  from meerschaum.utils.misc import get_connector_labels
19
19
  from meerschaum.config import __doc__ as doc
@@ -104,7 +104,7 @@ instance_select = dbc.Select(
104
104
  id='instance-select',
105
105
  size='sm',
106
106
  options=[
107
- {'label': i, 'value': i}
107
+ {'label': (i[:32] + '…') if len(i) > 32 else i, 'value': i}
108
108
  for i in get_connector_labels(*instance_types)
109
109
  ],
110
110
  class_name='dbc_dark custom-select custom-select-sm',
@@ -163,6 +163,7 @@ pages_navbar = html.Div(
163
163
  id='pages-navbar-div',
164
164
  )
165
165
 
166
+
166
167
  navbar = dbc.Navbar(
167
168
  dbc.Container(
168
169
  [
@@ -171,13 +172,11 @@ navbar = dbc.Navbar(
171
172
  dbc.Collapse(
172
173
  dbc.Row(
173
174
  [
174
- dbc.Col(instance_select),
175
- dbc.Col(
176
- sign_out_button,
177
- className="ms-auto",
178
- ),
175
+ dbc.Col(instance_select, width="auto"),
176
+ dbc.Col(sign_out_button, width="auto"),
179
177
  ],
180
178
  className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
179
+ align="center",
181
180
  ),
182
181
  id='navbar-collapse',
183
182
  is_open=False,
@@ -227,7 +227,23 @@ dropdown_tab_content = html.Div([
227
227
  [
228
228
  dropdown_keys_row,
229
229
  html.Br(),
230
- tags_dropdown,
230
+ dbc.Row(
231
+ [
232
+ dbc.Col(tags_dropdown, width=True),
233
+ dbc.Col(
234
+ dbc.Button(
235
+ "Clear all",
236
+ id='clear-all-keys-button',
237
+ color='link',
238
+ size='sm',
239
+ style={'text-decoration': 'none'},
240
+ ),
241
+ width='auto',
242
+ ),
243
+ ],
244
+ className='g-0',
245
+ align='center',
246
+ ),
231
247
  ], ### end of card children
232
248
  className='card-text',
233
249
  )
@@ -7,17 +7,27 @@ Display pipes via a shareable URL.
7
7
 
8
8
  from meerschaum.api import CHECK_UPDATE
9
9
  from meerschaum.utils.packages import import_html, import_dcc
10
- from meerschaum.api.dash.components import download_dataframe, pages_navbar, navbar
10
+ from meerschaum.api.dash.components import (
11
+ download_dataframe,
12
+ )
11
13
 
12
14
  html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
13
15
  import dash_bootstrap_components as dbc
14
16
 
15
-
16
17
  layout = [
17
- pages_navbar,
18
+ html.Div(id='pipes-navbar-div'),
18
19
  dcc.Location('pipes-location'),
19
20
  download_dataframe,
20
21
  dbc.Container([
21
- html.Div(id='pipe-output-div'),
22
+ dcc.Loading(
23
+ html.Div(id='pipe-output-div'),
24
+ id='pipes-loading',
25
+ type='circle',
26
+ delay_hide=1000,
27
+ delay_show=1000,
28
+ style={
29
+ 'padding-top': '100px',
30
+ },
31
+ ),
22
32
  ])
23
33
  ]
@@ -14,17 +14,24 @@ from urllib.parse import urlencode
14
14
 
15
15
  from meerschaum.utils import fetch_pipes_keys
16
16
  from meerschaum.utils.typing import List, Optional, Dict, Any, Tuple, Union
17
- from meerschaum.utils.misc import string_to_dict
17
+ from meerschaum.utils.misc import get_connector_labels
18
+ from meerschaum.connectors import instance_types
18
19
  from meerschaum.utils.packages import attempt_import, import_dcc, import_html, import_pandas
19
20
  from meerschaum.utils.sql import get_pd_type
20
21
  from meerschaum.utils.yaml import yaml
21
22
  from meerschaum.utils.warnings import warn
22
23
  from meerschaum.utils.dataframe import to_json, to_simple_lines
23
24
  from meerschaum.connectors.sql._fetch import get_pipe_query
24
- from meerschaum.api import CHECK_UPDATE
25
+ from meerschaum.api import CHECK_UPDATE, get_api_connector
25
26
  from meerschaum.api.dash import debug, _get_pipes
26
27
  from meerschaum.api.dash.connectors import get_web_connector
27
- from meerschaum.api.dash.components import alert_from_success_tuple, build_cards_grid
28
+ from meerschaum.api.dash.components import (
29
+ alert_from_success_tuple,
30
+ build_cards_grid,
31
+ sign_out_button,
32
+ logo_row,
33
+ pages_offcanvas,
34
+ )
28
35
  from meerschaum.api.dash.sessions import is_session_authenticated
29
36
  from meerschaum.config import get_config
30
37
  import meerschaum as mrsm
@@ -835,6 +842,28 @@ def build_pipes_dropdown_keys_row(
835
842
  mk_alone = metric_keys and not any([str(x) for x in (connector_keys + tags + location_keys)])
836
843
  lk_alone = location_keys and not any([str(x) for x in (connector_keys + metric_keys + tags)])
837
844
  all_keys = fetch_pipes_keys('registered', instance_connector)
845
+
846
+ ck_options_source = (
847
+ {keys_tuple[0] for keys_tuple in all_keys}
848
+ if ck_alone
849
+ else {p.connector_keys for p in pipes}
850
+ )
851
+ ck_options = sorted(ck_options_source.union(connector_keys))
852
+
853
+ mk_options_source = (
854
+ {keys_tuple[1] for keys_tuple in all_keys}
855
+ if mk_alone
856
+ else {p.metric_key for p in pipes}
857
+ )
858
+ mk_options = sorted(mk_options_source.union(metric_keys))
859
+
860
+ lk_options_source = (
861
+ {str(keys_tuple[2]) for keys_tuple in all_keys}
862
+ if lk_alone
863
+ else {str(p.location_key) for p in pipes}
864
+ )
865
+ lk_options = sorted(lk_options_source.union({str(lk) for lk in location_keys}))
866
+
838
867
  return dbc.Row(
839
868
  [
840
869
  dbc.Col(
@@ -842,11 +871,7 @@ def build_pipes_dropdown_keys_row(
842
871
  [
843
872
  dcc.Dropdown(
844
873
  id='pipes-connector-keys-dropdown',
845
- options=(
846
- sorted(list({pipe.connector_keys for pipe in pipes}))
847
- if not ck_alone
848
- else sorted(list({ck for ck, _, _ in all_keys}))
849
- ),
874
+ options=ck_options,
850
875
  value=[str(ck) for ck in connector_keys],
851
876
  placeholder='Connectors',
852
877
  multi=True,
@@ -863,11 +888,7 @@ def build_pipes_dropdown_keys_row(
863
888
  [
864
889
  dcc.Dropdown(
865
890
  id='pipes-metric-keys-dropdown',
866
- options=(
867
- sorted(list({pipe.metric_key for pipe in pipes}))
868
- if not mk_alone
869
- else sorted(list({mk for _, mk, _ in all_keys}))
870
- ),
891
+ options=mk_options,
871
892
  value=[str(mk) for mk in metric_keys],
872
893
  placeholder='Metrics',
873
894
  multi=True,
@@ -884,11 +905,7 @@ def build_pipes_dropdown_keys_row(
884
905
  [
885
906
  dcc.Dropdown(
886
907
  id='pipes-location-keys-dropdown',
887
- options=(
888
- sorted(list({str(pipe.location_key) for pipe in pipes}))
889
- if not lk_alone
890
- else sorted(list({str(lk) for _, _, lk in all_keys}))
891
- ),
908
+ options=lk_options,
892
909
  value=[str(lk) for lk in location_keys],
893
910
  placeholder='Locations',
894
911
  multi=True,
@@ -910,7 +927,7 @@ def build_pipes_tags_dropdown(
910
927
  location_keys: List[str],
911
928
  tags: List[str],
912
929
  instance: str,
913
- ) -> html.Div:
930
+ ) -> dbc.Row:
914
931
  """
915
932
  Build the tags dropdown for the dedicated pipes page.
916
933
  """
@@ -935,16 +952,84 @@ def build_pipes_tags_dropdown(
935
952
  str(tag)
936
953
  for tag in (_all_tags if _tags_alone else _tags_pipes)
937
954
  ]
955
+ if tags:
956
+ tags_options += [tag for tag in tags if tag not in tags_options]
938
957
 
958
+ return dbc.Row(
959
+ [
960
+ dbc.Col(
961
+ html.Div(
962
+ dcc.Dropdown(
963
+ id='pipes-tags-dropdown',
964
+ options=tags_options,
965
+ value=tags,
966
+ placeholder='Tags',
967
+ multi=True,
968
+ searchable=True,
969
+ ),
970
+ className="dbc_dark",
971
+ id="pipes-tags-dropdown-div",
972
+ ),
973
+ width=True,
974
+ ),
975
+ dbc.Col(
976
+ dbc.Button(
977
+ "Clear all",
978
+ color='link',
979
+ size='sm',
980
+ style={'text-decoration': 'none'},
981
+ id='pipes-clear-all-button',
982
+ ),
983
+ width='auto',
984
+ ),
985
+ ],
986
+ className='g-0',
987
+ align='center',
988
+ )
989
+
990
+
991
+ def build_pipes_navbar(instance_keys: Optional[str] = None, with_instance_select: bool = True):
992
+ """
993
+ Build the navbar from the selected instance keys.
994
+ """
995
+ instance_select = dbc.Select(
996
+ id='instance-select',
997
+ size='sm',
998
+ value=instance_keys or str(get_api_connector()),
999
+ options=[
1000
+ {'label': (i[:32] + '…') if len(i) > 32 else i, 'value': i}
1001
+ for i in get_connector_labels(*instance_types)
1002
+ ],
1003
+ class_name='dbc_dark custom-select custom-select-sm',
1004
+ )
1005
+ instance_select_div_style = {} if with_instance_select else {'visibility': 'hidden'}
1006
+ instance_select_div = html.Div(instance_select, style=instance_select_div_style)
939
1007
  return html.Div(
940
- dcc.Dropdown(
941
- id='pipes-tags-dropdown',
942
- options=tags_options,
943
- value=tags,
944
- placeholder='Tags',
945
- multi=True,
946
- searchable=True,
947
- ),
948
- className="dbc_dark",
949
- id="pipes-tags-dropdown-div",
1008
+ [
1009
+ pages_offcanvas,
1010
+ dbc.Navbar(
1011
+ dbc.Container(
1012
+ [
1013
+ logo_row,
1014
+ dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
1015
+ dbc.Collapse(
1016
+ dbc.Row(
1017
+ [
1018
+ dbc.Col(instance_select_div, width='auto'),
1019
+ dbc.Col(sign_out_button, width='auto'),
1020
+ ],
1021
+ className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
1022
+ align='center',
1023
+ ),
1024
+ id='navbar-collapse',
1025
+ is_open=False,
1026
+ navbar=True,
1027
+ ),
1028
+ ]
1029
+ ),
1030
+ dark=True,
1031
+ color='dark'
1032
+ ),
1033
+ ],
1034
+ id='pages-navbar-div',
950
1035
  )
@@ -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)},
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "3.0.0rc3"
5
+ __version__ = "3.0.0rc4"
@@ -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
- ) -> 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
 
@@ -174,7 +176,7 @@ def fetch_pipes_keys(
174
176
 
175
177
  Returns
176
178
  -------
177
- A list of tuples of pipes' keys (connector_keys, metric_key, location_key).
179
+ A list of tuples of pipes' keys and parameters (connector_keys, metric_key, location_key, parameters).
178
180
  """
179
181
  from meerschaum.utils.packages import attempt_import
180
182
  from meerschaum.utils.misc import separate_negation_values
@@ -254,6 +256,11 @@ def fetch_pipes_keys(
254
256
  pipes_tbl.c.connector_keys,
255
257
  pipes_tbl.c.metric_key,
256
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
+ ),
257
264
  ]
258
265
  )
259
266
 
@@ -276,7 +283,6 @@ def fetch_pipes_keys(
276
283
  if _in_tags:
277
284
  ors.append(
278
285
  sqlalchemy.and_(
279
- pipes_tbl.c['parameters'].cast(postgresql.JSONB).has_key('tags'),
280
286
  pipes_tbl.c['parameters']['tags'].cast(
281
287
  postgresql.JSONB
282
288
  ).contains(_in_tags)
@@ -286,7 +292,6 @@ def fetch_pipes_keys(
286
292
  nands.append(
287
293
  sqlalchemy.not_(
288
294
  sqlalchemy.and_(
289
- pipes_tbl.c['parameters'].cast(postgresql.JSONB).has_key('tags'),
290
295
  pipes_tbl.c['parameters']['tags'].cast(
291
296
  postgresql.JSONB
292
297
  ).contains([xt])
@@ -340,7 +345,7 @@ def fetch_pipes_keys(
340
345
  except Exception as e:
341
346
  error(str(e))
342
347
 
343
- return [(row[0], row[1], row[2]) for row in rows]
348
+ return rows
344
349
 
345
350
 
346
351
  def create_pipe_indices(
@@ -24,6 +24,7 @@ _skip_index_names_flavors = {'mssql',}
24
24
  def get_tables(
25
25
  mrsm_instance: Optional[Union[str, InstanceConnector]] = None,
26
26
  create: Optional[bool] = None,
27
+ refresh: bool = False,
27
28
  debug: bool = False,
28
29
  ) -> Union[Dict[str, 'sqlalchemy.Table'], bool]:
29
30
  """
@@ -37,6 +38,9 @@ def get_tables(
37
38
  create: Optional[bool], default None
38
39
  If `True`, create the tables if they don't exist.
39
40
 
41
+ refresh: bool, default False
42
+ If `True`, invalidate and rebuild any cache.
43
+
40
44
  debug: bool, default False
41
45
  Verbosity Toggle.
42
46
 
@@ -67,7 +71,15 @@ def get_tables(
67
71
  else: ### NOTE: mrsm_instance MUST BE a SQL Connector for this to work!
68
72
  conn = mrsm_instance
69
73
 
70
- cache_expired = _check_create_cache(conn, debug=debug) if conn.type == 'sql' else False
74
+ cache_expired = refresh or (
75
+ (
76
+ _check_create_cache(conn, debug=debug)
77
+ if conn.flavor != 'sqlite'
78
+ else True
79
+ )
80
+ if conn.type == 'sql'
81
+ else False
82
+ )
71
83
  create = create or cache_expired
72
84
 
73
85
  ### Skip if the connector is not a SQL connector.
@@ -75,6 +87,10 @@ def get_tables(
75
87
  return {}
76
88
 
77
89
  conn_key = str(conn)
90
+
91
+ if refresh:
92
+ _ = connector_tables.pop(conn_key, None)
93
+
78
94
  if conn_key in connector_tables:
79
95
  return connector_tables[conn_key]
80
96
 
@@ -248,8 +264,9 @@ def get_tables(
248
264
 
249
265
  _write_create_cache(mrsm.get_connector(str(mrsm_instance)), debug=debug)
250
266
 
251
- with open(pickle_path, 'wb') as f:
252
- pickle.dump(conn.metadata, f)
267
+ if conn.flavor != 'sqlite':
268
+ with open(pickle_path, 'wb') as f:
269
+ pickle.dump(conn.metadata, f)
253
270
 
254
271
  connector_tables[conn_key] = _tables
255
272
  return connector_tables[conn_key]
@@ -562,7 +562,7 @@ class Pipe:
562
562
  'connector_keys': self.connector_keys,
563
563
  'metric_key': self.metric_key,
564
564
  'location_key': self.location_key,
565
- 'parameters': self.parameters,
565
+ 'parameters': self._attributes.get('parameters', None),
566
566
  'instance_keys': self.instance_keys,
567
567
  }
568
568
 
@@ -598,3 +598,19 @@ class Pipe:
598
598
  if aliased_key is not None:
599
599
  key = aliased_key
600
600
  return getattr(self, key, None)
601
+
602
+ def __copy__(self):
603
+ """
604
+ Return a shallow copy of the current pipe.
605
+ """
606
+ return mrsm.Pipe(
607
+ self.connector_keys, self.metric_key, self.location_key,
608
+ instance=self.instance_keys,
609
+ parameters=self._attributes.get('parameters', None),
610
+ )
611
+
612
+ def __deepcopy__(self, memo):
613
+ """
614
+ Return a deep copy of the current pipe.
615
+ """
616
+ return self.__copy__()
@@ -128,11 +128,12 @@ def get_pipes(
128
128
  ```
129
129
  """
130
130
 
131
+ import json
132
+ from collections import defaultdict
131
133
  from meerschaum.config import get_config
132
134
  from meerschaum.utils.warnings import error
133
135
  from meerschaum.utils.misc import filter_keywords
134
136
  from meerschaum.utils.pool import get_pool
135
- from collections import defaultdict
136
137
 
137
138
  if connector_keys is None:
138
139
  connector_keys = []
@@ -194,19 +195,42 @@ def get_pipes(
194
195
  ### obtained from the chosen `method`.
195
196
  from meerschaum import Pipe
196
197
  pipes = {}
197
- for ck, mk, lk in result:
198
+ for keys_tuple in result:
199
+ ck, mk, lk = keys_tuple[0], keys_tuple[1], keys_tuple[2]
200
+ pipe_tags_or_parameters = keys_tuple[3] if len(keys_tuple) == 4 else None
201
+ pipe_parameters = (
202
+ pipe_tags_or_parameters
203
+ if isinstance(pipe_tags_or_parameters, (dict, str))
204
+ else None
205
+ )
206
+ if isinstance(pipe_parameters, str):
207
+ pipe_parameters = json.loads(pipe_parameters)
208
+ pipe_tags = (
209
+ pipe_tags_or_parameters
210
+ if isinstance(pipe_tags_or_parameters, list)
211
+ else (
212
+ pipe_tags_or_parameters.get('tags', None)
213
+ if isinstance(pipe_tags_or_parameters, dict)
214
+ else None
215
+ )
216
+ )
217
+
198
218
  if ck not in pipes:
199
219
  pipes[ck] = {}
200
220
 
201
221
  if mk not in pipes[ck]:
202
222
  pipes[ck][mk] = {}
203
223
 
204
- pipes[ck][mk][lk] = Pipe(
224
+ pipe = Pipe(
205
225
  ck, mk, lk,
206
226
  mrsm_instance = connector,
227
+ parameters = pipe_parameters,
228
+ tags = pipe_tags,
207
229
  debug = debug,
208
230
  **filter_keywords(Pipe, **kw)
209
231
  )
232
+ pipe.__dict__['_tags'] = pipe_tags
233
+ pipes[ck][mk][lk] = pipe
210
234
 
211
235
  if not as_list and not as_tags_dict:
212
236
  return pipes
@@ -218,7 +242,9 @@ def get_pipes(
218
242
 
219
243
  pool = get_pool(workers=(workers if connector.IS_THREAD_SAFE else 1))
220
244
  def gather_pipe_tags(pipe: mrsm.Pipe) -> Tuple[mrsm.Pipe, List[str]]:
221
- return pipe, (pipe.tags or [])
245
+ _tags = pipe.__dict__.get('_tags', None)
246
+ gathered_tags = _tags if _tags is not None else pipe.tags
247
+ return pipe, (gathered_tags or [])
222
248
 
223
249
  tags_pipes = defaultdict(lambda: [])
224
250
  pipes_tags = dict(pool.map(gather_pipe_tags, pipes_list))
@@ -66,6 +66,7 @@ def pprint(
66
66
  except Exception:
67
67
  args_copy = args
68
68
  modify = False
69
+
69
70
  _args = []
70
71
  for a in args:
71
72
  c = a
meerschaum/utils/pipes.py CHANGED
@@ -165,10 +165,14 @@ def replace_pipes_in_dict(
165
165
  A dictionary where every pipe is replaced with the output of a function.
166
166
 
167
167
  """
168
- def change_dict(d : Dict[Any, Any], func : 'function') -> None:
168
+ def change_dict(d: Dict[Any, Any]) -> None:
169
169
  for k, v in d.items():
170
170
  if isinstance(v, dict):
171
171
  change_dict(v, func)
172
+ elif isinstance(v, list):
173
+ d[k] = [func(i) for i in v]
174
+ elif isinstance(v, tuple):
175
+ d[k] = tuple([func(i) for i in v])
172
176
  else:
173
177
  d[k] = func(v)
174
178
 
@@ -177,5 +181,5 @@ def replace_pipes_in_dict(
177
181
  pipes = get_pipes(debug=debug, **kw)
178
182
 
179
183
  result = copy.deepcopy(pipes)
180
- change_dict(result, func)
184
+ change_dict(result)
181
185
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meerschaum
3
- Version: 3.0.0rc3
3
+ Version: 3.0.0rc4
4
4
  Summary: Sync Time-Series Pipes with Meerschaum
5
5
  Author-email: Bennett Meares <bennett.meares@gmail.com>
6
6
  Maintainer-email: Bennett Meares <bennett.meares@gmail.com>
@@ -51,22 +51,22 @@ meerschaum/actions/verify.py,sha256=yKNqh2T38t3yxqErr2o8i-nNG4ZZuyQUkaImATRdl5M,
51
51
  meerschaum/api/__init__.py,sha256=dRoIuyjkx6I8-LgLa0RbxwJCaAfSiGbgtf8fTbS7-Rw,10756
52
52
  meerschaum/api/_chain.py,sha256=h8-WXUGXX6AqzdALfsBC5uv0FkAcLdHJXCGzqzuq89k,875
53
53
  meerschaum/api/_chunks.py,sha256=rmhz8h4MZDnjkE02fDqDEwbYwwZbnU4gVwy3-QqB5y0,1898
54
- meerschaum/api/_events.py,sha256=fbxR0xNjgrPoflBifYtGFz68KoLM1iGEwzisa03GiEI,3612
54
+ meerschaum/api/_events.py,sha256=LPLXIurprtpWsgjIsDLMOPVT9rZjavkZzKh4dU6CQCE,3804
55
55
  meerschaum/api/_exceptions.py,sha256=xfbWp8F8JYrMUdtDXesn8C8e39_jAXHz51IosIGjkVM,463
56
56
  meerschaum/api/_oauth2.py,sha256=MLwOb-ZnJeBfn3OexdRhcboU39RBMnRt15s5e2d-lUs,5429
57
57
  meerschaum/api/_tokens.py,sha256=t9K0TFzyJ4dOg04_QKOWCINO66rSJkH2Ct03lyXIjEs,3070
58
58
  meerschaum/api/_websockets.py,sha256=EMT9wB3yELu_WyCMqn9ZpgMDh23spUUchouRLCCLVuw,1509
59
59
  meerschaum/api/dash/__init__.py,sha256=-RpTps4ntFNlgSW0mW50ZHAgUd5tN1Ua3F5I3XsLY_0,1914
60
- meerschaum/api/dash/components.py,sha256=_yH-g3eH1xsiIH9n0AOa_B58cQDNBHK2uaq0se9g9Yc,10765
60
+ meerschaum/api/dash/components.py,sha256=PMMLCcRHd0ADa8DjeH1xB2NXnIyl92HKW4LOCtmq55Y,10782
61
61
  meerschaum/api/dash/connectors.py,sha256=-Wd40ieYJI2nOASXi4V1C4bvLekjnN_tj6zp7HgZDl0,791
62
62
  meerschaum/api/dash/graphs.py,sha256=wJUDWzcLN8-C3xko6rj0F2v7Rt8YDkSXoVkkXJjYGIk,2046
63
63
  meerschaum/api/dash/jobs.py,sha256=p0mC30jO7aYS0vUbfn540d66-s19_c-GgjyfNmVXgrs,7682
64
- meerschaum/api/dash/keys.py,sha256=seiZIXay8pMdYn2Ibo6zdDhpeVi_2jS2HGw6nwVDm_g,7936
65
- meerschaum/api/dash/pipes.py,sha256=Yt64E2lwCvDWgU4TGBm-GnNHYmTgxDu9pVffHFFOzMA,33852
64
+ meerschaum/api/dash/keys.py,sha256=pGIbKxp5RsIelzAU4WZMcYGDN835tF4mGhoktydc42M,8561
65
+ meerschaum/api/dash/pipes.py,sha256=C6w8GmQvZcBWZE--Kc9xVLyljkU8Uyl-NiQSrlRLY9g,36391
66
66
  meerschaum/api/dash/plugins.py,sha256=KdfG04f6SsUpBg-nm7MUJegFGuElOj-GAkxDX98hi60,3768
67
67
  meerschaum/api/dash/sessions.py,sha256=jUM0a9CXNZC3j7SF3QkZim-8ZAbDom-V1iXklvMyBZE,5382
68
68
  meerschaum/api/dash/sync.py,sha256=9lt7IRdG-fe9gf_ZO_viPiGlerX7ic6r_VFocv3I51A,504
69
- meerschaum/api/dash/tokens.py,sha256=njIWTxJHTTH-U1LgIOxEcCjQZxWf6h6a-q6DcOX73CU,20832
69
+ meerschaum/api/dash/tokens.py,sha256=7_4k45drB6uoL1izDFo6TezzSQ6v1DP_aHw7orYk4ZU,20832
70
70
  meerschaum/api/dash/users.py,sha256=3wq3ZG51DxOjNeF-X5HdlXD1MYQ1nQ9oowYSvFEY7hs,1050
71
71
  meerschaum/api/dash/websockets.py,sha256=L6e7Ved7Osh9JRJitS4wMbVGPrrXPD4uB61Yj1Y5aug,927
72
72
  meerschaum/api/dash/webterm.py,sha256=Z7P99RzRQnB11LRWupwFpzyyZxouNbpFpXk0nYSGvwI,4503
@@ -78,13 +78,13 @@ meerschaum/api/dash/assets/logo_48x48.png,sha256=hTR5BHUHEN4yP2xiqAcDciuigoII9T3
78
78
  meerschaum/api/dash/assets/logo_500x500.png,sha256=9EUtf6wQcEZTXHKfQ2kjNXod6Rn_4DTB_BkTgxggq00,67702
79
79
  meerschaum/api/dash/callbacks/__init__.py,sha256=flHWiTSjrdgVNLgFutSnaqYogVUgnqRFWy3K0-n0wFo,651
80
80
  meerschaum/api/dash/callbacks/custom.py,sha256=8nUCZ-AhCTJ079r8eZ6nBE3bVZlkrvvC-bwP0U9zuv8,1791
81
- meerschaum/api/dash/callbacks/dashboard.py,sha256=87lNxEVf-rsRndFec1kB6k44-kkATgWfcFvNIlYCEDM,38816
81
+ meerschaum/api/dash/callbacks/dashboard.py,sha256=ghm_B6n0BtEbH8dL2xEbYKCnYjGf0_Iy50eNVXHSzZw,38057
82
82
  meerschaum/api/dash/callbacks/jobs.py,sha256=9MlHePZJ8sGSC2Sfo9BKyTix4-_7AP69njuM8k5Wmus,8749
83
83
  meerschaum/api/dash/callbacks/login.py,sha256=mEvMgV-f85H6DvqNdTvJPoiwHqTnhWY2nf_zLB26ipE,2876
84
- meerschaum/api/dash/callbacks/pipes.py,sha256=z0HF3ymuOZakuPf4YNdliARCksQSIW9fQzVmPPse2nk,4955
84
+ meerschaum/api/dash/callbacks/pipes.py,sha256=mK9d2A789fsMkT8BF6FIrxWpzPDzfa9VgAgeTZv05G8,7801
85
85
  meerschaum/api/dash/callbacks/plugins.py,sha256=GhhA8GZBCNcz65pBE8hn8BNBEiHjXfcTiqvBNeox4XQ,2759
86
86
  meerschaum/api/dash/callbacks/register.py,sha256=FFl5-PDILOfm-Vu1uouzSLYIncDLFgC4fDirsE16q54,3669
87
- meerschaum/api/dash/callbacks/tokens.py,sha256=V-q9zqDkTXcSAbBFW-lj85jQo-r4dJCsUHwl7ZzmWxA,11673
87
+ meerschaum/api/dash/callbacks/tokens.py,sha256=zkmqDenGjCrzQjNA5HyTOjcKDk2wYG4qE3xhjRDlTaE,11723
88
88
  meerschaum/api/dash/callbacks/settings/__init__.py,sha256=pttbJMJGfd5I_oCWfbpbbVtXZp7pyerl9ESgY9xwUwI,157
89
89
  meerschaum/api/dash/callbacks/settings/password_reset.py,sha256=GLvp5yTcmH6BFPCnj-P7nbMivKVK7yRFSubq2mAEUSI,2500
90
90
  meerschaum/api/dash/pages/__init__.py,sha256=rMrk5U8vDQTNg4mIhBfVldcq0r6wCZUOvSrS3eUFrEE,432
@@ -92,7 +92,7 @@ meerschaum/api/dash/pages/dashboard.py,sha256=fviwgh8QaKU1rKPrO4Pjk-Eya2xhKVC2rd
92
92
  meerschaum/api/dash/pages/error.py,sha256=-uCrASuIBrceHcc-leLeEoLos2ibSBWG0XMFQzFwtbw,595
93
93
  meerschaum/api/dash/pages/jobs.py,sha256=lKUE5iiKG37bOEGDpQ5JRWysMwn-_SRhZOHoj8e_q-c,605
94
94
  meerschaum/api/dash/pages/login.py,sha256=Qjc-kDL9wW4D1cN48x0MrmWCME4igHDt0VkX9JSipjY,4603
95
- meerschaum/api/dash/pages/pipes.py,sha256=_oYef5Bt8STHznkXV0xJA44uLBcggZb0MMAzfFJe39A,563
95
+ meerschaum/api/dash/pages/pipes.py,sha256=Dqxh76XWjHqjSNfQ99mFtX39Xi6fmVlNQRX0uy0_9-8,796
96
96
  meerschaum/api/dash/pages/plugins.py,sha256=EX-M99bxvRSrI-9bIBocj-tmBpf6NgPQ813sJ_HSXS8,1731
97
97
  meerschaum/api/dash/pages/register.py,sha256=dqhsiu2OhrXhs4RL41_CpqipdrWo1-_roASvZIDBAq8,2364
98
98
  meerschaum/api/dash/pages/tokens.py,sha256=cqscrKcU1ODO8mo2xBeevQnNhSUZYjgU3o7QNMZ7Cik,1332
@@ -150,7 +150,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
150
150
  meerschaum/config/_read_config.py,sha256=BVGZbaS_bFcLb6fQNbwXIAS2sjLVg5wfuLs1ghVtK9g,15798
151
151
  meerschaum/config/_shell.py,sha256=46_m49Txc5q1rGfCgO49ca48BODx45DQJi8D0zz1R18,4245
152
152
  meerschaum/config/_sync.py,sha256=nN5bLCHU8sFDdlPi7pQXuRVFcX457rZjOiALTvqRS_E,4332
153
- meerschaum/config/_version.py,sha256=lhKZ78RGzDxFyBpVlBLwYgW2MBE57Dcp0EbvuK87-Fo,74
153
+ meerschaum/config/_version.py,sha256=Q8imWbF1NIK8GFKpklTRimzU-PqJRTShxG3q0jm90X8,74
154
154
  meerschaum/config/paths.py,sha256=JjibeGN3YAdSNceRwsd42aNmeUrIgM6ndzC8qZAmNI0,621
155
155
  meerschaum/config/static.py,sha256=92fSGxoHFDOK9GEsN8NVbAEh9W7-eZ1BS6thyEqcjeI,359
156
156
  meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -190,13 +190,13 @@ meerschaum/connectors/sql/_cli.py,sha256=D4c_S-xTmhLRxl2dMhNSF0bMb1fDrMwWP2SVRBm
190
190
  meerschaum/connectors/sql/_create_engine.py,sha256=vAoM8oBZHLikF7gVCMMOfe19MF-xw3kFj1mL0HUOD7o,7531
191
191
  meerschaum/connectors/sql/_fetch.py,sha256=eJIqVAc4qI0xrbkZedO85sfB1-Hd3_Jkk12D6-OuzRU,12208
192
192
  meerschaum/connectors/sql/_instance.py,sha256=xCc8M0xWMzF5Tu_1uWIFivAoHey5N1ccFhN_Z7u04zk,6304
193
- meerschaum/connectors/sql/_pipes.py,sha256=u2gE2hT-XETSLz4wq-y3085Q7E22yqXB5fV6jcl0H4k,130035
193
+ meerschaum/connectors/sql/_pipes.py,sha256=3gVhXUrBAo90GOKxnvSVNiKqkh6NaLT8cHSJ6tVRE2A,130040
194
194
  meerschaum/connectors/sql/_plugins.py,sha256=SubR5HUJaetoUCv83YNEMwhv4wTTBCMcxSOEUgyMML4,8747
195
195
  meerschaum/connectors/sql/_sql.py,sha256=7x54ED3WYNASBBb50JKX37-d-LLQsp2fqR59S7qK6HQ,44490
196
196
  meerschaum/connectors/sql/_uri.py,sha256=BFzu5pjlbL3kxLH13vHWlpKGYTPfg8wuA2j58O9NsCM,3440
197
197
  meerschaum/connectors/sql/_users.py,sha256=Gzsy2JDowdmJ2oiZlq07MmrZx2mfU3NLMUSSdO7blIg,10593
198
198
  meerschaum/connectors/sql/tools.py,sha256=jz8huOaRCwGlYdtGfAqAh7SoK8uydYBrasKQba9FT38,187
199
- meerschaum/connectors/sql/tables/__init__.py,sha256=JTNyCenggCoFfCWPhWJWTnAl0YeSyjjM-CGfb-MEuyE,12992
199
+ meerschaum/connectors/sql/tables/__init__.py,sha256=DphdLWgztzNGIDDZcjq8c8YO-mqq6q4nDKEN5k0DQG4,13345
200
200
  meerschaum/connectors/sql/tables/types.py,sha256=Jc_MTHIBM-KHpQt__Lckp39CeOo7tGOiAk5faDx-znY,1573
201
201
  meerschaum/connectors/valkey/_ValkeyConnector.py,sha256=QkhfipUHl5bN0sTmG-m90sr_RD4ukUmW9MY3COCv3Mw,15820
202
202
  meerschaum/connectors/valkey/__init__.py,sha256=jkVutsygQCvGPLN17cP6wHAjHajxVycnQJbm2eVMuY0,187
@@ -205,7 +205,7 @@ meerschaum/connectors/valkey/_pipes.py,sha256=G1kHIll1sEUiCPGvTodDYrfplJ4ixHlJ0l
205
205
  meerschaum/connectors/valkey/_plugins.py,sha256=KjNE2RDJ90b96ynoPz30iOiWU86bfJjFX70bhkXDcGM,5774
206
206
  meerschaum/connectors/valkey/_users.py,sha256=AS1vLarrkDA9yPK644GWwRiQiTZVa9x3nlLpyntq40g,7730
207
207
  meerschaum/core/__init__.py,sha256=Qx0s4KANuYCjTCHEaE70cfgCPxiYPPkr9DnmCTw33Z0,291
208
- meerschaum/core/Pipe/__init__.py,sha256=FSc1hAvl9OEYslB74eM-MGnTx79a-FTHERktYlxF5_M,20790
208
+ meerschaum/core/Pipe/__init__.py,sha256=7b0uZmtyOuqWWcraRBHZuR-oh1oT97vzvt-8GawOByo,21264
209
209
  meerschaum/core/Pipe/_attributes.py,sha256=bXPvGwKfpCukmma2g6G_q2TILRvPu-s4mq-DLpQbIes,32451
210
210
  meerschaum/core/Pipe/_bootstrap.py,sha256=4RLDD25BvqyukHhejTIJFaECOvCgZk6tjtNQfS9qgA8,8150
211
211
  meerschaum/core/Pipe/_clear.py,sha256=LghXabgyyc1tD7FNQrh9ExT71ipcg2poM9FDA3k9e4M,2230
@@ -239,13 +239,13 @@ meerschaum/models/users.py,sha256=E1ambl2g6f2tdnLkwAquyqjvflrb2AMiVhI9nXXHYR0,68
239
239
  meerschaum/plugins/__init__.py,sha256=Kf9Z7aiyNkEpR6M9f3pXWiOJ8u1hiLknpQqISgzBmMI,27362
240
240
  meerschaum/plugins/bootstrap.py,sha256=sSvdh2g78AYwTTNMTdHw62Nj2v95pmbd77HFznuErUE,27728
241
241
  meerschaum/utils/__init__.py,sha256=QrK1K9hIbPCRCM5k2nZGFqGnrqhA0Eh-iSmCU7FG6Cs,612
242
- meerschaum/utils/_get_pipes.py,sha256=CaxBWzF_JBY9PNiCOy_ca3bUNl2Obtzew4KkPNuGtkQ,12291
242
+ meerschaum/utils/_get_pipes.py,sha256=TbV77VjQ9qqCLOy06-hlnfQI_hS6PTcXkbO7aQ2csdM,13275
243
243
  meerschaum/utils/dataframe.py,sha256=JDf8Gus9ZrCKdOrcHcefsPxudbKinuadD9rH9LocLEg,67612
244
244
  meerschaum/utils/debug.py,sha256=WqVBG0J5q0GckvuQNTKhFcqbEm0BuXP5v6PZq4osaCc,3635
245
245
  meerschaum/utils/interactive.py,sha256=t-6jWozXSqL7lYGDHuwiOjTgr-UKhdcg61q_eR5mikI,3196
246
246
  meerschaum/utils/misc.py,sha256=rHNvwg55V3iGxRaPog2X3uLbv_s_UR5mG3tRcVX-v44,50766
247
247
  meerschaum/utils/networking.py,sha256=Sr_eYUGW8_UV9-k9LqRFf7xLtbUcsDucODyLCRsFRUc,1006
248
- meerschaum/utils/pipes.py,sha256=_6Beat23v9cz10yMgzqN1U7oK3TjEW4jYPat-1i_I3k,5501
248
+ meerschaum/utils/pipes.py,sha256=SVIOXNg_YTTDfPssVIJKjMDJKZlCmDnALBvIRHhNuMI,5647
249
249
  meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
250
250
  meerschaum/utils/process.py,sha256=7iObszskRYLCf35GZGRigLLPDo5dugtzjM_SwSDX_uk,8219
251
251
  meerschaum/utils/prompt.py,sha256=yTx03RXL5nsGtHrj7bjK72g1cA1inplLsw1vMSCtzPo,19444
@@ -266,18 +266,18 @@ meerschaum/utils/dtypes/sql.py,sha256=bVBzpagFLPJKYvW3EaQyPa6WkpBEHtllVL38r4CUBI
266
266
  meerschaum/utils/formatting/__init__.py,sha256=UKQoCMtAWolpBtXVFHCKcCKfH9iKa1GaTbpy0wCYyB8,15531
267
267
  meerschaum/utils/formatting/_jobs.py,sha256=izsqPJhTtUkXUUtWnbXtReYsUYwulXtci3pBj72Ne64,6637
268
268
  meerschaum/utils/formatting/_pipes.py,sha256=4nrDkfwoEq434TbEChG0v1HuRZ8Pn1EKPhTJL64ez-Y,19555
269
- meerschaum/utils/formatting/_pprint.py,sha256=wyTmjHFnsHbxfyuytjTWzH-D42Z65GuIisQ_W6UnRPg,3096
269
+ meerschaum/utils/formatting/_pprint.py,sha256=DCwopIQUu2xsCETsmbfSYVupG6Uz95gyZ63pa_nDMPo,3097
270
270
  meerschaum/utils/formatting/_shell.py,sha256=kCxvO3NJ5COWVRSKfOXXeuMiyxTloe0OhEtglzuZKGs,3798
271
271
  meerschaum/utils/packages/__init__.py,sha256=_qa99_yeAHLuXkAys5KCY2XyC-IJtksHl5Nk_GQV4eY,63669
272
272
  meerschaum/utils/packages/_packages.py,sha256=jxTUz9dZOg_fNd19-hliz3zTbmA22VUnk0nxIT7nGyA,9371
273
273
  meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
274
274
  meerschaum/utils/venv/_Venv.py,sha256=dF-FqP7Boq-g-anj2Ps-UkTOL2qJtxY3bdz0HWF2zT8,3726
275
275
  meerschaum/utils/venv/__init__.py,sha256=E2JqbfddMrv1Yrlq-iUiok2grgzW5gUQt9y4EG68gm8,27265
276
- meerschaum-3.0.0rc3.dist-info/licenses/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
277
- meerschaum-3.0.0rc3.dist-info/licenses/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
278
- meerschaum-3.0.0rc3.dist-info/METADATA,sha256=y2tUF_AOjDiFaq5rHlc0Q7B_htVh8QifIMML7JBlrc0,25227
279
- meerschaum-3.0.0rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
280
- meerschaum-3.0.0rc3.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
281
- meerschaum-3.0.0rc3.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
282
- meerschaum-3.0.0rc3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
283
- meerschaum-3.0.0rc3.dist-info/RECORD,,
276
+ meerschaum-3.0.0rc4.dist-info/licenses/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
277
+ meerschaum-3.0.0rc4.dist-info/licenses/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
278
+ meerschaum-3.0.0rc4.dist-info/METADATA,sha256=PwoaKQBKmWrnqpCkFvhMTYN2bSxInQeKm63psANDPPk,25227
279
+ meerschaum-3.0.0rc4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
280
+ meerschaum-3.0.0rc4.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
281
+ meerschaum-3.0.0rc4.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
282
+ meerschaum-3.0.0rc4.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
283
+ meerschaum-3.0.0rc4.dist-info/RECORD,,