meerschaum 2.3.6__py3-none-any.whl → 2.4.0.dev1__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 (53) hide show
  1. meerschaum/actions/bootstrap.py +36 -10
  2. meerschaum/actions/copy.py +3 -3
  3. meerschaum/actions/start.py +13 -14
  4. meerschaum/api/dash/__init__.py +7 -6
  5. meerschaum/api/dash/callbacks/__init__.py +1 -0
  6. meerschaum/api/dash/callbacks/dashboard.py +7 -5
  7. meerschaum/api/dash/callbacks/pipes.py +42 -0
  8. meerschaum/api/dash/pages/__init__.py +1 -0
  9. meerschaum/api/dash/pages/pipes.py +16 -0
  10. meerschaum/api/dash/pipes.py +79 -47
  11. meerschaum/api/dash/users.py +19 -6
  12. meerschaum/api/routes/_login.py +4 -4
  13. meerschaum/api/routes/_pipes.py +3 -3
  14. meerschaum/config/_default.py +9 -1
  15. meerschaum/config/_version.py +1 -1
  16. meerschaum/config/stack/__init__.py +59 -16
  17. meerschaum/connectors/Connector.py +19 -13
  18. meerschaum/connectors/__init__.py +9 -5
  19. meerschaum/connectors/poll.py +30 -24
  20. meerschaum/connectors/sql/_pipes.py +126 -154
  21. meerschaum/connectors/sql/_plugins.py +45 -43
  22. meerschaum/connectors/sql/_users.py +46 -38
  23. meerschaum/connectors/valkey/ValkeyConnector.py +535 -0
  24. meerschaum/connectors/valkey/__init__.py +8 -0
  25. meerschaum/connectors/valkey/_fetch.py +75 -0
  26. meerschaum/connectors/valkey/_pipes.py +839 -0
  27. meerschaum/connectors/valkey/_plugins.py +265 -0
  28. meerschaum/connectors/valkey/_users.py +305 -0
  29. meerschaum/core/Pipe/__init__.py +3 -0
  30. meerschaum/core/Pipe/_attributes.py +1 -2
  31. meerschaum/core/Pipe/_clear.py +16 -13
  32. meerschaum/core/Pipe/_copy.py +106 -0
  33. meerschaum/core/Pipe/_drop.py +4 -4
  34. meerschaum/core/Pipe/_dtypes.py +14 -14
  35. meerschaum/core/Pipe/_edit.py +15 -14
  36. meerschaum/core/Pipe/_sync.py +134 -51
  37. meerschaum/core/Pipe/_verify.py +11 -11
  38. meerschaum/core/User/_User.py +14 -12
  39. meerschaum/plugins/_Plugin.py +17 -13
  40. meerschaum/utils/_get_pipes.py +14 -20
  41. meerschaum/utils/dataframe.py +288 -101
  42. meerschaum/utils/dtypes/__init__.py +31 -6
  43. meerschaum/utils/dtypes/sql.py +4 -4
  44. meerschaum/utils/misc.py +3 -3
  45. meerschaum/utils/packages/_packages.py +1 -0
  46. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/METADATA +3 -1
  47. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/RECORD +53 -44
  48. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/WHEEL +1 -1
  49. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/LICENSE +0 -0
  50. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/NOTICE +0 -0
  51. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/entry_points.txt +0 -0
  52. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/top_level.txt +0 -0
  53. {meerschaum-2.3.6.dist-info → meerschaum-2.4.0.dev1.dist-info}/zip-safe +0 -0
@@ -234,7 +234,13 @@ def _bootstrap_connectors(
234
234
  Prompt the user for the details necessary to create a Connector.
235
235
  """
236
236
  from meerschaum.connectors.parse import is_valid_connector_keys
237
- from meerschaum.connectors import connectors, get_connector, types, custom_types
237
+ from meerschaum.connectors import (
238
+ connectors,
239
+ get_connector,
240
+ types,
241
+ custom_types,
242
+ _load_builtin_custom_connectors,
243
+ )
238
244
  from meerschaum.utils.prompt import prompt, yes_no, choose
239
245
  from meerschaum.config import get_config
240
246
  from meerschaum.config._edit import write_config
@@ -246,6 +252,7 @@ def _bootstrap_connectors(
246
252
 
247
253
  abort_tuple = False, "No connectors bootstrapped."
248
254
  _clear = get_config('shell', 'clear_screen', patch=True)
255
+ _load_builtin_custom_connectors()
249
256
 
250
257
  if action is None:
251
258
  action = []
@@ -262,8 +269,8 @@ def _bootstrap_connectors(
262
269
  + ' See https://meerschaum.io/reference/connectors '
263
270
  + 'for documentation on connectors.\n'
264
271
  ),
265
- sorted(list(connectors)),
266
- default = 'sql'
272
+ sorted([k for k in connectors if k != 'plugin']),
273
+ default='sql',
267
274
  )
268
275
  except KeyboardInterrupt:
269
276
  return abort_tuple
@@ -288,21 +295,30 @@ def _bootstrap_connectors(
288
295
  warn(f"Connector '{_type}:{_label}' already exists.", stack=False)
289
296
  overwrite = yes_no(
290
297
  f"Do you want to overwrite connector '{_type}:{_label}'?",
291
- default = 'n',
292
- yes = yes,
293
- noask = noask,
298
+ default='n',
299
+ yes=yes,
300
+ noask=noask,
294
301
  )
295
302
  if not overwrite and not force:
296
- return False, f"No changes made to connector configuration."
303
+ return False, "No changes made to connector configuration."
297
304
  break
298
305
  elif _label == "":
299
- warn(f"Please enter a label.", stack=False)
306
+ warn("Please enter a label.", stack=False)
300
307
  else:
301
308
  break
302
309
 
303
310
  cls = types.get(_type)
304
311
  cls_required_attrs = getattr(cls, 'REQUIRED_ATTRIBUTES', [])
305
- type_attributes = connector_attributes.get(_type, {'required': cls_required_attrs})
312
+ cls_optional_attrs = getattr(cls, 'OPTIONAL_ATTRIBUTES', [])
313
+ cls_default_attrs = getattr(cls, 'DEFAULT_ATTRIBUTES', {})
314
+ type_attributes = connector_attributes.get(
315
+ _type,
316
+ {
317
+ 'required': cls_required_attrs,
318
+ 'optional': cls_optional_attrs,
319
+ 'default': cls_default_attrs,
320
+ }
321
+ )
306
322
 
307
323
  new_attributes = {}
308
324
  if 'flavors' in type_attributes:
@@ -323,6 +339,7 @@ def _bootstrap_connectors(
323
339
  default = type_attributes['flavors'][flavor].get('defaults', {})
324
340
  else:
325
341
  required = sorted(list(type_attributes.get('required', {})))
342
+ optional = sorted(list(type_attributes.get('optional', {})))
326
343
  default = type_attributes.get('default', {})
327
344
  info(
328
345
  f"Please answer the following questions to configure the new connector '{_type}:{_label}'."
@@ -330,13 +347,22 @@ def _bootstrap_connectors(
330
347
  )
331
348
  for r in required:
332
349
  try:
333
- val = prompt(f"Value for {r}:")
350
+ default_val = str(default.get(r)) if r in default else None
351
+ val = prompt(f"Value for {r}:", default=default_val)
334
352
  except KeyboardInterrupt:
335
353
  continue
336
354
  if is_int(val):
337
355
  val = int(val)
338
356
  new_attributes[r] = val
339
357
 
358
+ for o in optional:
359
+ try:
360
+ val = prompt(f"Value for {o} (optional; empty to omit):")
361
+ except KeyboardInterrupt:
362
+ continue
363
+ if val:
364
+ new_attributes[o] = val
365
+
340
366
  for k, v in default.items():
341
367
  ### skip already configured attributes, (e.g. flavor or from required)
342
368
  if k in new_attributes:
@@ -115,11 +115,11 @@ def _copy_pipes(
115
115
  ):
116
116
  _new_pipe.sync(
117
117
  p.get_data(
118
- debug = debug,
119
- as_iterator = True,
118
+ debug=debug,
119
+ as_iterator=True,
120
120
  **kw
121
121
  ),
122
- debug = debug,
122
+ debug=debug,
123
123
  **kw
124
124
  )
125
125
 
@@ -455,12 +455,12 @@ def _start_webterm(
455
455
 
456
456
 
457
457
  def _start_connectors(
458
- action: Optional[List[str]] = None,
459
- connector_keys: Optional[List[str]] = None,
460
- min_seconds: int = 3,
461
- debug: bool = False,
462
- **kw
463
- ) -> SuccessTuple:
458
+ action: Optional[List[str]] = None,
459
+ connector_keys: Optional[List[str]] = None,
460
+ min_seconds: int = 3,
461
+ debug: bool = False,
462
+ **kw
463
+ ) -> SuccessTuple:
464
464
  """
465
465
  Start polling connectors to verify a connection can be made.
466
466
  """
@@ -480,7 +480,7 @@ def _start_connectors(
480
480
  for keys in unique_keys:
481
481
  try:
482
482
  conn = parse_instance_keys(keys)
483
- except Exception as e:
483
+ except Exception:
484
484
  warn(f"Invalid connector keys: '{keys}'. Skipping...", stack=False)
485
485
  continue
486
486
  valid_conns.append(conn)
@@ -488,20 +488,19 @@ def _start_connectors(
488
488
  if not valid_conns:
489
489
  return False, "No valid connector keys were provided."
490
490
 
491
-
492
491
  connected = {}
493
492
  def connect(conn):
494
493
  success = retry_connect(
495
494
  conn,
496
- retry_wait = min_seconds,
497
- enforce_chaining = False,
498
- enforce_login = False,
499
- print_on_connect = True,
500
- debug = debug,
495
+ retry_wait=min_seconds,
496
+ enforce_chaining=False,
497
+ enforce_login=False,
498
+ print_on_connect=True,
499
+ debug=debug,
501
500
  )
502
501
  connected[conn] = success
503
502
  return success
504
-
503
+
505
504
  pool = get_pool()
506
505
  try:
507
506
  pool.map(connect, valid_conns)
@@ -50,16 +50,17 @@ stylesheets = [
50
50
  '/static/css/bootstrap.min.css',
51
51
  '/static/css/dbc_dark.css',
52
52
  '/static/css/dash.css',
53
+ '/static/css/bootstrap-icons/font/bootstrap-icons.min.css',
53
54
  ]
54
55
  scripts = ['/static/js/node_modules/xterm/lib/xterm.js']
55
56
  dash_app = enrich.DashProxy(
56
57
  __name__,
57
- title = 'Meerschaum Web',
58
- requests_pathname_prefix = endpoints['dash'] + '/',
59
- external_stylesheets = stylesheets,
60
- update_title = None,
61
- suppress_callback_exceptions = True,
62
- transforms = [
58
+ title='Meerschaum Web',
59
+ requests_pathname_prefix=endpoints['dash'] + '/',
60
+ external_stylesheets=stylesheets,
61
+ update_title=None,
62
+ suppress_callback_exceptions=True,
63
+ transforms=[
63
64
  enrich.TriggerTransform(),
64
65
  enrich.MultiplexerTransform(),
65
66
  ],
@@ -11,6 +11,7 @@ import meerschaum.api.dash.callbacks.login
11
11
  import meerschaum.api.dash.callbacks.plugins
12
12
  import meerschaum.api.dash.callbacks.jobs
13
13
  import meerschaum.api.dash.callbacks.register
14
+ import meerschaum.api.dash.callbacks.pipes
14
15
  from meerschaum.api.dash.callbacks.custom import init_dash_plugins, add_plugin_pages
15
16
 
16
17
  init_dash_plugins()
@@ -101,6 +101,7 @@ _paths = {
101
101
  '' : pages.dashboard.layout,
102
102
  'plugins' : pages.plugins.layout,
103
103
  'register': pages.register.layout,
104
+ 'pipes' : pages.pipes.layout,
104
105
  }
105
106
  _required_login = {''}
106
107
 
@@ -113,10 +114,10 @@ _required_login = {''}
113
114
  State('location', 'href'),
114
115
  )
115
116
  def update_page_layout_div(
116
- pathname: str,
117
- session_store_data: Dict[str, Any],
118
- location_href: str,
119
- ) -> Tuple[List[Any], Dict[str, Any]]:
117
+ pathname: str,
118
+ session_store_data: Dict[str, Any],
119
+ location_href: str,
120
+ ) -> Tuple[List[Any], Dict[str, Any]]:
120
121
  """
121
122
  Route the user to the correct page.
122
123
 
@@ -135,7 +136,7 @@ def update_page_layout_div(
135
136
  ctx = dash.callback_context
136
137
  dash_endpoint = endpoints['dash']
137
138
  try:
138
- session_id = session_store_data.get('session-id', None)
139
+ session_id = session_store_data.get('session-id', None)
139
140
  except AttributeError:
140
141
  session_id = None
141
142
 
@@ -760,6 +761,7 @@ def update_pipe_accordion(item, session_store_data):
760
761
  raise PreventUpdate
761
762
 
762
763
  session_id = session_store_data.get('session-id', None)
764
+ print(f"{session_id=}")
763
765
  authenticated = is_session_authenticated(str(session_id))
764
766
  return accordion_items_from_pipe(pipe, active_items=[item], authenticated=authenticated)
765
767
 
@@ -0,0 +1,42 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Define callbacks for the `/dash/pipes/` page.
6
+ """
7
+
8
+ from dash.exceptions import PreventUpdate
9
+ from dash.dependencies import Input, Output, State
10
+ from dash import no_update
11
+
12
+ import meerschaum as mrsm
13
+ from meerschaum.api.dash import dash_app, debug, active_sessions
14
+ from meerschaum.api.dash.pipes import build_pipe_card
15
+ from meerschaum.api import get_api_connector, CHECK_UPDATE
16
+ from meerschaum.utils.packages import import_html, import_dcc
17
+ html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
18
+
19
+
20
+ @dash_app.callback(
21
+ Output('pipe-output-div', 'children'),
22
+ Input('pipes-location', 'pathname'),
23
+ )
24
+ def render_page_from_url(pathname):
25
+ if not str(pathname).startswith('/dash/pipes'):
26
+ return no_update
27
+
28
+ keys = pathname.replace('/dash/pipes', '').lstrip('/').rstrip('/').split('/')
29
+ if len(keys) not in (2, 3):
30
+ return no_update
31
+
32
+ ck = keys[0]
33
+ mk = keys[1]
34
+ lk = keys[2] if len(keys) == 3 else None
35
+
36
+ pipe = mrsm.Pipe(ck, mk, lk)
37
+ ### TODO Check if logged in
38
+ return [
39
+ html.Br(),
40
+ build_pipe_card(pipe, authenticated=False),
41
+ html.Br(),
42
+ ]
@@ -10,3 +10,4 @@ import meerschaum.api.dash.pages.login
10
10
  import meerschaum.api.dash.pages.dashboard
11
11
  import meerschaum.api.dash.pages.plugins
12
12
  import meerschaum.api.dash.pages.register
13
+ import meerschaum.api.dash.pages.pipes
@@ -0,0 +1,16 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Display pipes via a shareable URL.
6
+ """
7
+
8
+ from meerschaum.api import get_api_connector, CHECK_UPDATE
9
+ from meerschaum.utils.packages import import_html, import_dcc
10
+ html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
11
+ import dash_bootstrap_components as dbc
12
+
13
+ layout = dbc.Container([
14
+ dcc.Location('pipes-location'),
15
+ html.Div(id='pipe-output-div'),
16
+ ])
@@ -48,13 +48,14 @@ def pipe_from_ctx(ctx, trigger_property: str = 'n_clicks') -> Union[mrsm.Pipe, N
48
48
  return None
49
49
  return mrsm.Pipe(**meta)
50
50
 
51
+
51
52
  def keys_from_state(
52
- state: Dict[str, Any],
53
- with_params: bool = False
54
- ) -> Union[
55
- Tuple[List[str], List[str], List[str]],
56
- Tuple[List[str], List[str], List[str], str],
57
- ]:
53
+ state: Dict[str, Any],
54
+ with_params: bool = False
55
+ ) -> Union[
56
+ Tuple[List[str], List[str], List[str]],
57
+ Tuple[List[str], List[str], List[str], str],
58
+ ]:
58
59
  """
59
60
  Read the current state and return the selected keys lists.
60
61
  """
@@ -85,10 +86,11 @@ def keys_from_state(
85
86
  keys.append(params)
86
87
  return tuple(keys)
87
88
 
89
+
88
90
  def pipes_from_state(
89
- state: Dict[str, Any],
90
- **kw
91
- ):
91
+ state: Dict[str, Any],
92
+ **kw
93
+ ):
92
94
  _ck, _mk, _lk, _params = keys_from_state(state, with_params=True)
93
95
  try:
94
96
  _pipes = _get_pipes(
@@ -103,10 +105,10 @@ def pipes_from_state(
103
105
 
104
106
 
105
107
  def build_pipe_card(
106
- pipe: mrsm.Pipe,
107
- authenticated: bool = False,
108
- _build_children_num: int = 10,
109
- ) -> 'dbc.Card':
108
+ pipe: mrsm.Pipe,
109
+ authenticated: bool = False,
110
+ _build_children_num: int = 10,
111
+ ) -> 'dbc.Card':
110
112
  """
111
113
  Return a card for the given pipe.
112
114
 
@@ -128,11 +130,11 @@ def build_pipe_card(
128
130
  dbc.Col(
129
131
  (
130
132
  dbc.DropdownMenu(
131
- label = "Manage",
132
- children = [
133
+ label="Manage",
134
+ children=[
133
135
  dbc.DropdownMenuItem(
134
136
  'Open in Python',
135
- id = {
137
+ id={
136
138
  'type': 'manage-pipe-button',
137
139
  'index': meta_str,
138
140
  'action': 'python',
@@ -140,7 +142,7 @@ def build_pipe_card(
140
142
  ),
141
143
  dbc.DropdownMenuItem(
142
144
  'Delete',
143
- id = {
145
+ id={
144
146
  'type': 'manage-pipe-button',
145
147
  'index': meta_str,
146
148
  'action': 'delete',
@@ -148,7 +150,7 @@ def build_pipe_card(
148
150
  ),
149
151
  dbc.DropdownMenuItem(
150
152
  'Drop',
151
- id = {
153
+ id={
152
154
  'type': 'manage-pipe-button',
153
155
  'index': meta_str,
154
156
  'action': 'drop',
@@ -156,7 +158,7 @@ def build_pipe_card(
156
158
  ),
157
159
  dbc.DropdownMenuItem(
158
160
  'Clear',
159
- id = {
161
+ id={
160
162
  'type': 'manage-pipe-button',
161
163
  'index': meta_str,
162
164
  'action': 'clear',
@@ -164,7 +166,7 @@ def build_pipe_card(
164
166
  ),
165
167
  dbc.DropdownMenuItem(
166
168
  'Verify',
167
- id = {
169
+ id={
168
170
  'type': 'manage-pipe-button',
169
171
  'index': meta_str,
170
172
  'action': 'verify',
@@ -172,56 +174,86 @@ def build_pipe_card(
172
174
  ),
173
175
  dbc.DropdownMenuItem(
174
176
  'Sync',
175
- id = {
177
+ id={
176
178
  'type': 'manage-pipe-button',
177
179
  'index': meta_str,
178
180
  'action': 'sync',
179
181
  },
180
182
  ),
181
183
  ],
182
- direction = "up",
183
- menu_variant = "dark",
184
- size = 'sm',
185
- color = 'secondary',
184
+ direction="up",
185
+ menu_variant="dark",
186
+ size='sm',
187
+ color='secondary',
186
188
  )
187
189
  ) if authenticated else [],
188
- width = 2,
190
+ width=2,
189
191
  ),
190
192
  dbc.Col(width=6),
191
193
  dbc.Col(
192
194
  dbc.Button(
193
195
  'Download CSV',
194
- size = 'sm',
195
- color = 'link',
196
- style = {'float': 'right'},
197
- id = {'type': 'pipe-download-csv-button', 'index': meta_str},
196
+ size='sm',
197
+ color='link',
198
+ style={'float': 'right'},
199
+ id={'type': 'pipe-download-csv-button', 'index': meta_str},
198
200
  ),
199
- width = 4,
201
+ width=4,
200
202
  ),
201
203
  ],
202
- justify = 'start',
204
+ justify='start',
203
205
  )
204
206
  card_body_children = [
205
- html.H5(
206
- html.B(str(pipe)),
207
- className = 'card-title',
208
- style = {'font-family': ['monospace']}
209
- ),
210
207
  html.Div(
211
208
  dbc.Accordion(
212
209
  accordion_items_from_pipe(
213
210
  pipe,
214
- authenticated = authenticated,
215
- _build_children_num = _build_children_num,
211
+ authenticated=authenticated,
212
+ _build_children_num=_build_children_num,
216
213
  ),
217
- flush = True,
218
- start_collapsed = True,
219
- id = {'type': 'pipe-accordion', 'index': meta_str},
214
+ flush=True,
215
+ start_collapsed=True,
216
+ id={'type': 'pipe-accordion', 'index': meta_str},
220
217
  )
221
218
  )
222
219
 
223
220
  ]
221
+
222
+ pipe_url = (
223
+ f"/dash/pipes/{pipe.connector_keys}/{pipe.metric_key}/{pipe.location_key}"
224
+ )
225
+
226
+ card_header_children = dbc.Row(
227
+ [
228
+ dbc.Col(
229
+ html.H5(
230
+ html.B(str(pipe)),
231
+ className='card-title',
232
+ style={'font-family': ['monospace']}
233
+ ),
234
+ width=11,
235
+ ),
236
+ dbc.Col(
237
+ dbc.Button(
238
+ [
239
+ html.I(
240
+ className="bi bi-share",
241
+ ),
242
+ ],
243
+ # href=pipe_url,
244
+ style={'float': 'right'},
245
+ outline=True,
246
+ color='link',
247
+ id={'type': 'share-pipe-button', 'index': meta_str},
248
+ ),
249
+ width=1,
250
+ ),
251
+ ],
252
+ justify='start',
253
+ )
254
+
224
255
  return dbc.Card([
256
+ dbc.CardHeader(children=card_header_children),
225
257
  dbc.CardBody(children=card_body_children),
226
258
  dbc.CardFooter(children=footer_children),
227
259
  ])
@@ -270,11 +302,11 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
270
302
 
271
303
 
272
304
  def accordion_items_from_pipe(
273
- pipe: mrsm.Pipe,
274
- active_items: Optional[List[str]] = None,
275
- authenticated: bool = False,
276
- _build_children_num: int = 10,
277
- ) -> 'List[dbc.AccordionItem]':
305
+ pipe: mrsm.Pipe,
306
+ active_items: Optional[List[str]] = None,
307
+ authenticated: bool = False,
308
+ _build_children_num: int = 10,
309
+ ) -> 'List[dbc.AccordionItem]':
278
310
  """
279
311
  Build the accordion items for a given pipe.
280
312
  """
@@ -18,6 +18,7 @@ from meerschaum.core import User
18
18
  dcc, html = import_dcc(check_update=CHECK_UPDATE), import_html(check_update=CHECK_UPDATE)
19
19
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
20
20
 
21
+
21
22
  def get_users_cards(state: WebState) -> Tuple[List[dbc.Card], List[SuccessTuple]]:
22
23
  """
23
24
  Return the cards and alerts for users.
@@ -52,21 +53,33 @@ def is_session_authenticated(session_id: str) -> bool:
52
53
  """
53
54
  if no_auth:
54
55
  return True
56
+ if session_id not in active_sessions:
57
+ return False
55
58
  if session_id in unauthenticated_sessions:
56
59
  return False
57
60
  if session_id in authenticated_sessions:
58
61
  return True
62
+
59
63
  permissions = get_config('system', 'api', 'permissions')
60
64
  allow_non_admin = permissions.get('actions', {}).get('non_admin', False)
61
- if allow_non_admin:
62
- return True
63
- conn = get_api_connector()
65
+
66
+ is_auth = True if allow_non_admin else session_is_admin(session_id)
64
67
  username = active_sessions.get(session_id, {}).get('username', None)
65
- user = User(username, instance=conn)
66
- user_type = conn.get_user_type(user, debug=debug)
67
- is_auth = user_type == 'admin'
68
+
68
69
  if is_auth:
69
70
  authenticated_sessions[session_id] = username
70
71
  else:
71
72
  unauthenticated_sessions[session_id] = username
73
+
72
74
  return is_auth
75
+
76
+
77
+ def session_is_admin(session_id: str) -> bool:
78
+ """
79
+ Check whether a session ID corresponds to an admin user.
80
+ """
81
+ conn = get_api_connector()
82
+ username = active_sessions.get(session_id, {}).get('username', None)
83
+ user = User(username, instance=conn)
84
+ user_type = conn.get_user_type(user, debug=debug)
85
+ return user_type == 'admin'
@@ -23,8 +23,8 @@ from meerschaum.api._oauth2 import CustomOAuth2PasswordRequestForm
23
23
 
24
24
  @manager.user_loader()
25
25
  def load_user(
26
- username: str
27
- ) -> User:
26
+ username: str
27
+ ) -> User:
28
28
  """
29
29
  Create the `meerschaum.core.User` object from the username.
30
30
  """
@@ -33,8 +33,8 @@ def load_user(
33
33
 
34
34
  @app.post(endpoints['login'], tags=['Users'])
35
35
  def login(
36
- data: CustomOAuth2PasswordRequestForm = fastapi.Depends()
37
- ) -> Dict[str, Any]:
36
+ data: CustomOAuth2PasswordRequestForm = fastapi.Depends()
37
+ ) -> Dict[str, Any]:
38
38
  """
39
39
  Login and set the session token.
40
40
  """
@@ -474,9 +474,9 @@ def get_pipe_data(
474
474
  df[col] = df[col].apply(lambda x: f'{x:f}' if isinstance(x, Decimal) else x)
475
475
 
476
476
  json_content = df.to_json(
477
- date_format = 'iso',
478
- orient = 'records',
479
- date_unit = 'us',
477
+ date_format='iso',
478
+ orient='records',
479
+ date_unit='us',
480
480
  )
481
481
 
482
482
  return fastapi.Response(
@@ -52,6 +52,14 @@ default_meerschaum_config = {
52
52
  'protocol': 'https',
53
53
  },
54
54
  },
55
+ 'valkey': {
56
+ 'main': {
57
+ 'host': 'localhost',
58
+ 'username': 'default',
59
+ 'password': 'mrsm',
60
+ 'port': 6379,
61
+ },
62
+ },
55
63
  },
56
64
  }
57
65
  default_system_config = {
@@ -74,7 +82,7 @@ default_system_config = {
74
82
  },
75
83
  },
76
84
 
77
- 'api' : {
85
+ 'api': {
78
86
  },
79
87
  },
80
88
  ### not to be confused with system_config['connectors']['api'], this is the configuration
@@ -2,4 +2,4 @@
2
2
  Specify the Meerschaum release version.
3
3
  """
4
4
 
5
- __version__ = "2.3.6"
5
+ __version__ = "2.4.0.dev1"