meerschaum 2.2.1__py3-none-any.whl → 2.2.2__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 (39) hide show
  1. meerschaum/_internal/shell/Shell.py +40 -16
  2. meerschaum/_internal/term/__init__.py +3 -2
  3. meerschaum/_internal/term/tools.py +1 -1
  4. meerschaum/actions/api.py +65 -31
  5. meerschaum/actions/python.py +56 -24
  6. meerschaum/actions/start.py +2 -4
  7. meerschaum/actions/uninstall.py +5 -9
  8. meerschaum/actions/upgrade.py +11 -3
  9. meerschaum/api/__init__.py +1 -0
  10. meerschaum/api/dash/callbacks/__init__.py +4 -0
  11. meerschaum/api/dash/callbacks/custom.py +39 -0
  12. meerschaum/api/dash/callbacks/dashboard.py +39 -6
  13. meerschaum/api/dash/callbacks/login.py +3 -1
  14. meerschaum/api/dash/components.py +5 -2
  15. meerschaum/api/dash/pipes.py +145 -97
  16. meerschaum/config/_default.py +1 -0
  17. meerschaum/config/_paths.py +12 -12
  18. meerschaum/config/_version.py +1 -1
  19. meerschaum/config/paths.py +10 -0
  20. meerschaum/config/static/__init__.py +1 -1
  21. meerschaum/connectors/__init__.py +1 -1
  22. meerschaum/core/Pipe/__init__.py +5 -0
  23. meerschaum/core/Pipe/_sync.py +2 -3
  24. meerschaum/plugins/__init__.py +67 -9
  25. meerschaum/utils/daemon/Daemon.py +7 -2
  26. meerschaum/utils/misc.py +6 -0
  27. meerschaum/utils/packages/__init__.py +212 -53
  28. meerschaum/utils/packages/_packages.py +1 -0
  29. meerschaum/utils/process.py +12 -2
  30. meerschaum/utils/schedule.py +1 -1
  31. meerschaum/utils/venv/__init__.py +46 -11
  32. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/METADATA +5 -1
  33. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/RECORD +39 -37
  34. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/WHEEL +1 -1
  35. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/LICENSE +0 -0
  36. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/NOTICE +0 -0
  37. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/entry_points.txt +0 -0
  38. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/top_level.txt +0 -0
  39. {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/zip-safe +0 -0
@@ -203,6 +203,29 @@ def _check_complete_keys(line: str) -> Optional[List[str]]:
203
203
  return None
204
204
 
205
205
 
206
+ def get_shell_intro(with_color: bool = True) -> str:
207
+ """
208
+ Return the introduction message string.
209
+ """
210
+ from meerschaum.utils.formatting import CHARSET, ANSI, colored
211
+ intro = get_config('shell', CHARSET, 'intro', patch=patch)
212
+ intro += '\n' + ''.join(
213
+ [' '
214
+ for i in range(
215
+ string_width(intro) - len('v' + version)
216
+ )
217
+ ]
218
+ ) + 'v' + version
219
+
220
+ if not with_color or not ANSI:
221
+ return intro
222
+
223
+ return colored(
224
+ intro,
225
+ **get_config('shell', 'ansi', 'intro', 'rich')
226
+ )
227
+
228
+
206
229
  class Shell(cmd.Cmd):
207
230
  def __init__(
208
231
  self,
@@ -277,25 +300,20 @@ class Shell(cmd.Cmd):
277
300
  except Exception as e:
278
301
  pass
279
302
 
280
-
281
303
  def load_config(self, instance: Optional[str] = None):
282
304
  """
283
305
  Set attributes from the shell configuration.
284
306
  """
285
307
  from meerschaum.utils.misc import remove_ansi
286
- from meerschaum.utils.formatting import CHARSET, ANSI, UNICODE, colored
308
+ from meerschaum.utils.formatting import CHARSET, ANSI, colored
287
309
 
288
310
  if shell_attrs.get('intro', None) != '':
289
- self.intro = get_config('shell', CHARSET, 'intro', patch=patch)
290
- self.intro += '\n' + ''.join(
291
- [' '
292
- for i in range(
293
- string_width(self.intro) - len('v' + version)
294
- )
295
- ]
296
- ) + 'v' + version
297
- else:
298
- self.intro = ""
311
+ self.intro = (
312
+ get_shell_intro(with_color=False)
313
+ if shell_attrs.get('intro', None) != ''
314
+ else ""
315
+ )
316
+
299
317
  shell_attrs['intro'] = self.intro
300
318
  shell_attrs['_prompt'] = get_config('shell', CHARSET, 'prompt', patch=patch)
301
319
  self.prompt = shell_attrs['_prompt']
@@ -822,7 +840,7 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
822
840
  """
823
841
  Replace built-in `input()` with prompt_toolkit.prompt.
824
842
  """
825
- from meerschaum.utils.formatting import CHARSET, ANSI, UNICODE, colored
843
+ from meerschaum.utils.formatting import CHARSET, ANSI, colored
826
844
  from meerschaum.connectors import is_connected, connectors
827
845
  from meerschaum.utils.misc import remove_ansi
828
846
  from meerschaum.config import get_config
@@ -849,11 +867,17 @@ def input_with_sigint(_input, session, shell: Optional[Shell] = None):
849
867
  shell_attrs['instance_keys'], 'on ' + get_config(
850
868
  'shell', 'ansi', 'instance', 'rich', 'style'
851
869
  )
852
- ) if ANSI else colored(shell_attrs['instance_keys'], 'on white')
870
+ )
871
+ if ANSI
872
+ else colored(shell_attrs['instance_keys'], 'on white')
853
873
  )
854
874
  repo_colored = (
855
- colored(shell_attrs['repo_keys'], 'on ' + get_config('shell', 'ansi', 'repo', 'rich', 'style'))
856
- if ANSI else colored(shell_attrs['repo_keys'], 'on white')
875
+ colored(
876
+ shell_attrs['repo_keys'],
877
+ 'on ' + get_config('shell', 'ansi', 'repo', 'rich', 'style')
878
+ )
879
+ if ANSI
880
+ else colored(shell_attrs['repo_keys'], 'on white')
857
881
  )
858
882
  try:
859
883
  typ, label = shell_attrs['instance_keys'].split(':')
@@ -14,9 +14,10 @@ from typing import List, Tuple
14
14
  from meerschaum.utils.packages import attempt_import
15
15
  from meerschaum._internal.term.TermPageHandler import TermPageHandler
16
16
  from meerschaum.config._paths import API_TEMPLATES_PATH, API_STATIC_PATH
17
+ from meerschaum.utils.venv import venv_executable
17
18
 
18
19
  tornado, tornado_ioloop, terminado = attempt_import(
19
- 'tornado', 'tornado.ioloop', 'terminado', lazy=False, venv=None,
20
+ 'tornado', 'tornado.ioloop', 'terminado', lazy=False,
20
21
  )
21
22
 
22
23
  def get_webterm_app_and_manager() -> Tuple[
@@ -31,7 +32,7 @@ def get_webterm_app_and_manager() -> Tuple[
31
32
  A tuple of the Tornado web application and term manager.
32
33
  """
33
34
  commands = [
34
- sys.executable,
35
+ venv_executable('mrsm'),
35
36
  '-c',
36
37
  "import os; _ = os.environ.pop('COLUMNS', None); _ = os.environ.pop('LINES', None); "
37
38
  "from meerschaum._internal.entry import get_shell; "
@@ -17,7 +17,7 @@ def is_webterm_running(host: str, port: int, protocol: str = 'http') -> int:
17
17
  requests = attempt_import('requests')
18
18
  url = f'{protocol}://{host}:{port}'
19
19
  try:
20
- r = requests.get(url)
20
+ r = requests.get(url, timeout=3)
21
21
  except Exception as e:
22
22
  return False
23
23
  if not r:
meerschaum/actions/api.py CHANGED
@@ -156,6 +156,7 @@ def _api_start(
156
156
  from meerschaum.config.static import STATIC_CONFIG, SERVER_ID
157
157
  from meerschaum.connectors.parse import parse_instance_keys
158
158
  from meerschaum.utils.pool import get_pool
159
+ from meerschaum.utils.venv import get_module_venv
159
160
  import shutil
160
161
  from copy import deepcopy
161
162
 
@@ -169,7 +170,10 @@ def _api_start(
169
170
  ### `check_update` must be False, because otherwise Uvicorn's hidden imports will break things.
170
171
  dotenv = attempt_import('dotenv', lazy=False)
171
172
  uvicorn, gunicorn = attempt_import(
172
- 'uvicorn', 'gunicorn', venv=None, lazy=False, check_update=False,
173
+ 'uvicorn', 'gunicorn',
174
+ lazy = False,
175
+ check_update = False,
176
+ venv = 'mrsm',
173
177
  )
174
178
 
175
179
  uvicorn_config_path = API_UVICORN_RESOURCES_PATH / SERVER_ID / 'config.json'
@@ -305,19 +309,51 @@ def _api_start(
305
309
  ### remove custom keys before calling uvicorn
306
310
 
307
311
  def _run_uvicorn():
308
- try:
309
- uvicorn.run(
310
- **filter_keywords(
311
- uvicorn.run,
312
- **{
313
- k: v
314
- for k, v in uvicorn_config.items()
315
- if k not in custom_keys
316
- }
317
- )
318
- )
319
- except KeyboardInterrupt:
320
- pass
312
+ uvicorn_flags = [
313
+ '--host', host,
314
+ '--port', str(port),
315
+ (
316
+ '--proxy-headers'
317
+ if uvicorn_config.get('proxy_headers')
318
+ else '--no-proxy-headers'
319
+ ),
320
+ (
321
+ '--use-colors'
322
+ if uvicorn_config.get('use_colors')
323
+ else '--no-use-colors'
324
+ ),
325
+ '--env-file', uvicorn_config['env_file'],
326
+ ]
327
+ if uvicorn_reload := uvicorn_config.get('reload'):
328
+ uvicorn_flags.append('--reload')
329
+ if (
330
+ uvicorn_reload
331
+ and (reload_dirs := uvicorn_config.get('reload_dirs'))
332
+ ):
333
+ if not isinstance(reload_dirs, list):
334
+ reload_dirs = [reload_dirs]
335
+ for reload_dir in reload_dirs:
336
+ uvicorn_flags += ['--reload-dir', reload_dir]
337
+ if (
338
+ uvicorn_reload
339
+ and (reload_excludes := uvicorn_config.get('reload_excludes'))
340
+ ):
341
+ if not isinstance(reload_excludes, list):
342
+ reload_excludes = [reload_excludes]
343
+ for reload_exclude in reload_excludes:
344
+ uvicorn_flags += ['--reload-exclude', reload_exclude]
345
+ if (uvicorn_workers := uvicorn_config.get('workers')) is not None:
346
+ uvicorn_flags += ['--workers', str(uvicorn_workers)]
347
+
348
+ uvicorn_args = uvicorn_flags + ['meerschaum.api:app']
349
+ run_python_package(
350
+ 'uvicorn',
351
+ uvicorn_args,
352
+ venv = get_module_venv(uvicorn),
353
+ as_proc = False,
354
+ foreground = True,
355
+ debug = debug,
356
+ )
321
357
 
322
358
  def _run_gunicorn():
323
359
  gunicorn_args = [
@@ -338,23 +374,21 @@ def _api_start(
338
374
  ]
339
375
  if debug:
340
376
  gunicorn_args += ['--log-level=debug', '--enable-stdio-inheritance', '--reload']
341
- try:
342
- run_python_package(
343
- 'gunicorn',
344
- gunicorn_args,
345
- env = {
346
- k: (
347
- json.dumps(v)
348
- if isinstance(v, (dict, list))
349
- else v
350
- )
351
- for k, v in env_dict.items()
352
- },
353
- venv = None,
354
- debug = debug,
355
- )
356
- except KeyboardInterrupt:
357
- pass
377
+
378
+ run_python_package(
379
+ 'gunicorn',
380
+ gunicorn_args,
381
+ env = {
382
+ k: (
383
+ json.dumps(v)
384
+ if isinstance(v, (dict, list))
385
+ else v
386
+ )
387
+ for k, v in env_dict.items()
388
+ },
389
+ venv = get_module_venv(gunicorn),
390
+ debug = debug,
391
+ )
358
392
 
359
393
 
360
394
  _run_uvicorn() if not production else _run_gunicorn()
@@ -10,37 +10,39 @@ from meerschaum.utils.typing import SuccessTuple, Any, List, Optional
10
10
 
11
11
  def python(
12
12
  action: Optional[List[str]] = None,
13
+ venv: Optional[str] = 'mrsm',
14
+ sub_args: Optional[List[str]] = None,
13
15
  debug: bool = False,
14
16
  **kw: Any
15
17
  ) -> SuccessTuple:
16
18
  """
17
- Launch a Python interpreter with Meerschaum imported. Commands are optional.
18
- Note that quotes must be escaped and commands must be separated by semicolons
19
+ Launch a virtual environment's Python interpreter with Meerschaum imported.
20
+ You may pass flags to the Python binary by surrounding each flag with `[]`.
19
21
 
20
22
  Usage:
21
23
  `python {commands}`
22
24
 
23
- Example:
24
- `python print(\\'Hello, World!\\'); pipes = mrsm.get_pipes()`
25
-
26
- ```
27
- Hello, World!
28
-
29
- >>> import meerschaum as mrsm
30
- >>> print('Hello, World!')
31
- >>> pipes = mrsm.get_pipes()
32
- ```
25
+ Examples:
26
+ mrsm python
27
+ mrsm python --venv noaa
28
+ mrsm python [-i] [-c 'print("hi")']
33
29
  """
34
- import sys, subprocess
30
+ import sys, subprocess, os
35
31
  from meerschaum.utils.debug import dprint
36
32
  from meerschaum.utils.warnings import warn, error
37
- from meerschaum.utils.process import run_process
33
+ from meerschaum.utils.venv import venv_executable
34
+ from meerschaum.utils.misc import generate_password
38
35
  from meerschaum.config import __version__ as _version
36
+ from meerschaum.config.paths import VIRTENV_RESOURCES_PATH, PYTHON_RESOURCES_PATH
37
+ from meerschaum.utils.packages import run_python_package, attempt_import
39
38
 
40
39
  if action is None:
41
40
  action = []
42
41
 
43
- joined_actions = ['import meerschaum as mrsm']
42
+ if venv == 'None':
43
+ venv = None
44
+
45
+ joined_actions = ["import meerschaum as mrsm"]
44
46
  line = ""
45
47
  for i, a in enumerate(action):
46
48
  if a == '':
@@ -51,34 +53,64 @@ def python(
51
53
  line = ""
52
54
 
53
55
  ### ensure meerschaum is imported
54
- # joined_actions = ['import meerschaum as mrsm;'] + joined_actions
55
56
  if debug:
56
- dprint(joined_actions)
57
+ dprint(str(joined_actions))
57
58
 
58
- print_command = 'import sys; print("""'
59
- ps1 = ">>> "
59
+ ### TODO: format the pre-executed code using the pygments lexer.
60
+ print_command = (
61
+ 'from meerschaum.utils.packages import attempt_import; '
62
+ + 'ptft = attempt_import("prompt_toolkit.formatted_text", lazy=False); '
63
+ + 'pts = attempt_import("prompt_toolkit.shortcuts"); '
64
+ + 'ansi = ptft.ANSI("""'
65
+ )
66
+ ps1 = "\\033[1m>>> \\033[0m"
60
67
  for i, a in enumerate(joined_actions):
61
68
  line = ps1 + f"{a}".replace(';', '\n')
62
69
  if '\n' not in line and i != len(joined_actions) - 1:
63
70
  line += "\n"
64
71
  print_command += line
65
- print_command += '""")'
72
+ print_command += (
73
+ '"""); '
74
+ + 'pts.print_formatted_text(ansi); '
75
+ )
66
76
 
67
- command = ""
77
+ command = print_command
68
78
  for a in joined_actions:
69
79
  command += a
70
80
  if not a.endswith(';'):
71
81
  command += ';'
72
82
  command += ' '
73
83
 
74
- command += print_command
75
-
76
84
  if debug:
77
85
  dprint(f"command:\n{command}")
86
+
87
+ init_script_path = PYTHON_RESOURCES_PATH / (generate_password(8) + '.py')
88
+ with open(init_script_path, 'w', encoding='utf-8') as f:
89
+ f.write(command)
90
+
91
+ env_dict = os.environ.copy()
92
+ venv_path = (VIRTENV_RESOURCES_PATH / venv) if venv is not None else None
93
+ if venv_path is not None:
94
+ env_dict.update({'VIRTUAL_ENV': venv_path.as_posix()})
95
+
78
96
  try:
79
- return_code = run_process([sys.executable, '-i', '-c', command], foreground=True)
97
+ ptpython = attempt_import('ptpython', venv=venv, allow_outside_venv=False)
98
+ return_code = run_python_package(
99
+ 'ptpython',
100
+ sub_args or ['--dark-bg', '-i', init_script_path.as_posix()],
101
+ venv = venv,
102
+ foreground = True,
103
+ env = env_dict,
104
+ )
80
105
  except KeyboardInterrupt:
81
106
  return_code = 1
107
+
108
+ try:
109
+ if init_script_path.exists():
110
+ init_script_path.unlink()
111
+ except Exception as e:
112
+ warn(f"Failed to clean up tempory file '{init_script_path}'.")
113
+
82
114
  return return_code == 0, (
83
115
  "Success" if return_code == 0
84
116
  else f"Python interpreter returned {return_code}."
@@ -333,8 +333,7 @@ def _start_gui(
333
333
  from meerschaum.connectors.parse import parse_instance_keys
334
334
  from meerschaum._internal.term.tools import is_webterm_running
335
335
  import platform
336
- webview = attempt_import('webview')
337
- requests = attempt_import('requests')
336
+ webview, requests = attempt_import('webview', 'requests')
338
337
  import json
339
338
  import time
340
339
 
@@ -365,7 +364,7 @@ def _start_gui(
365
364
  base_url = 'http://' + api_kw['host'] + ':' + str(api_kw['port'])
366
365
 
367
366
  process = venv_exec(
368
- start_tornado_code, as_proc=True, venv=None, debug=debug, capture_output=(not debug)
367
+ start_tornado_code, as_proc=True, debug=debug, capture_output=(not debug)
369
368
  )
370
369
  timeout = 10
371
370
  start = time.perf_counter()
@@ -446,7 +445,6 @@ def _start_webterm(
446
445
  + " Include `-f` to start another server on a new port\n"
447
446
  + " or specify a different port with `-p`."
448
447
  )
449
-
450
448
  if not nopretty:
451
449
  info(f"Starting the webterm at http://{host}:{port} ...\n Press CTRL+C to quit.")
452
450
  tornado_app.listen(port, host)
@@ -7,7 +7,7 @@ Uninstall plugins and pip packages.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.typing import List, Any, SuccessTuple, Optional
10
+ from meerschaum.utils.typing import List, Any, SuccessTuple, Optional, Union
11
11
 
12
12
  def uninstall(
13
13
  action: Optional[List[str]] = None,
@@ -145,13 +145,10 @@ def _complete_uninstall_plugins(action: Optional[List[str]] = None, **kw) -> Lis
145
145
  possibilities.append(name)
146
146
  return possibilities
147
147
 
148
- class NoVenv:
149
- pass
150
-
151
148
  def _uninstall_packages(
152
149
  action: Optional[List[str]] = None,
153
150
  sub_args: Optional[List[str]] = None,
154
- venv: Union[str, None, NoVenv] = NoVenv,
151
+ venv: Optional[str] = 'mrsm',
155
152
  yes: bool = False,
156
153
  force: bool = False,
157
154
  noask: bool = False,
@@ -169,9 +166,7 @@ def _uninstall_packages(
169
166
 
170
167
  from meerschaum.utils.warnings import info
171
168
  from meerschaum.utils.packages import pip_uninstall
172
-
173
- if venv is NoVenv:
174
- venv = 'mrsm'
169
+ from meerschaum.utils.misc import items_str
175
170
 
176
171
  if not (yes or force) and noask:
177
172
  return False, "Skipping uninstallation. Add `-y` or `-f` to agree to the uninstall prompt."
@@ -183,7 +178,8 @@ def _uninstall_packages(
183
178
  debug = debug,
184
179
  ):
185
180
  return True, (
186
- f"Successfully removed packages from virtual environment 'mrsm':\n" + ', '.join(action)
181
+ f"Successfully removed packages from virtual environment '{venv}':\n"
182
+ + items_str(action)
187
183
  )
188
184
 
189
185
  return False, f"Failed to uninstall packages:\n" + ', '.join(action)
@@ -130,7 +130,7 @@ def _upgrade_packages(
130
130
  upgrade packages docs
131
131
  ```
132
132
  """
133
- from meerschaum.utils.packages import packages, pip_install
133
+ from meerschaum.utils.packages import packages, pip_install, get_prerelease_dependencies
134
134
  from meerschaum.utils.warnings import info, warn
135
135
  from meerschaum.utils.prompt import yes_no
136
136
  from meerschaum.utils.formatting import make_header, pprint
@@ -140,7 +140,7 @@ def _upgrade_packages(
140
140
  if venv is NoVenv:
141
141
  venv = 'mrsm'
142
142
  if len(action) == 0:
143
- group = 'full'
143
+ group = 'api'
144
144
  else:
145
145
  group = action[0]
146
146
 
@@ -148,7 +148,7 @@ def _upgrade_packages(
148
148
  invalid_msg = f"Invalid dependency group '{group}'."
149
149
  avail_msg = make_header("Available groups:")
150
150
  for k in packages:
151
- avail_msg += "\n - {k}"
151
+ avail_msg += f"\n - {k}"
152
152
 
153
153
  warn(invalid_msg + "\n\n" + avail_msg, stack=False)
154
154
  return False, invalid_msg
@@ -160,10 +160,18 @@ def _upgrade_packages(
160
160
  f"(dependency group '{group}')?"
161
161
  )
162
162
  to_install = [install_name for import_name, install_name in packages[group].items()]
163
+ prereleases_to_install = get_prerelease_dependencies(to_install)
164
+ to_install = [
165
+ install_name
166
+ for install_name in to_install
167
+ if install_name not in prereleases_to_install
168
+ ]
163
169
 
164
170
  success, msg = False, f"Nothing installed."
165
171
  if force or yes_no(question, noask=noask, yes=yes):
166
172
  success = pip_install(*to_install, debug=debug)
173
+ if success and prereleases_to_install:
174
+ success = pip_install(*prereleases_to_install, debug=debug)
167
175
  msg = (
168
176
  f"Successfully installed {len(packages[group])} packages." if success
169
177
  else f"Failed to install packages in dependency group '{group}'."
@@ -31,6 +31,7 @@ CHECK_UPDATE = os.environ.get(STATIC_CONFIG['environment']['runtime'], None) !=
31
31
 
32
32
  endpoints = STATIC_CONFIG['api']['endpoints']
33
33
 
34
+ uv = attempt_import('uv', lazy=False, check_update=CHECK_UPDATE)
34
35
  (
35
36
  fastapi,
36
37
  aiofiles,
@@ -11,3 +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
+ from meerschaum.api.dash.callbacks.custom import init_dash_plugins, add_plugin_pages
15
+
16
+ init_dash_plugins()
17
+ add_plugin_pages()
@@ -0,0 +1,39 @@
1
+ #! /usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # vim:fenc=utf-8
4
+
5
+ """
6
+ Import custom callbacks created by plugins.
7
+ """
8
+
9
+ import traceback
10
+ from meerschaum.api.dash import dash_app
11
+ from meerschaum.plugins import _dash_plugins, _plugin_endpoints_to_pages
12
+ from meerschaum.utils.warnings import warn
13
+ from meerschaum.api.dash.callbacks.dashboard import _paths, _required_login
14
+
15
+
16
+ def init_dash_plugins():
17
+ """
18
+ Fire the initial callbacks for Dash plugins.
19
+ """
20
+ for _module_name, _functions in _dash_plugins.items():
21
+ for _function in _functions:
22
+ try:
23
+ _function(dash_app)
24
+ except Exception as e:
25
+ warn(
26
+ f"Failed to load function '{_function.__name__}' "
27
+ + f"from plugin '{_module_name}':\n"
28
+ + traceback.format_exc()
29
+ )
30
+
31
+
32
+ def add_plugin_pages():
33
+ """
34
+ Allow users to add pages via the `@web_page` decorator.
35
+ """
36
+ for _endpoint, _page_dict in _plugin_endpoints_to_pages.items():
37
+ _paths[_endpoint] = _page_dict['function']()
38
+ if _page_dict['login_required']:
39
+ _required_login.add(_endpoint)
@@ -94,6 +94,8 @@ omit_actions = {
94
94
  'repo',
95
95
  'instance',
96
96
  }
97
+
98
+ ### Map endpoints to page layouts.
97
99
  _paths = {
98
100
  'login' : pages.login.layout,
99
101
  '' : pages.dashboard.layout,
@@ -101,7 +103,8 @@ _paths = {
101
103
  'register': pages.register.layout,
102
104
  }
103
105
  _required_login = {''}
104
-
106
+
107
+
105
108
  @dash_app.callback(
106
109
  Output('page-layout-div', 'children'),
107
110
  Output('session-store', 'data'),
@@ -147,16 +150,31 @@ def update_page_layout_div(
147
150
  else:
148
151
  session_store_to_return = dash.no_update
149
152
 
150
- _path = (
153
+ base_path = (
151
154
  pathname.rstrip('/') + '/'
152
155
  ).replace(
153
156
  (dash_endpoint + '/'),
154
157
  ''
155
158
  ).rstrip('/').split('/')[0]
159
+
160
+ complete_path = (
161
+ pathname.rstrip('/') + '/'
162
+ ).replace(
163
+ dash_endpoint + '/',
164
+ ''
165
+ ).rstrip('/')
166
+
167
+ if complete_path in _paths:
168
+ path_str = complete_path
169
+ elif base_path in _paths:
170
+ path_str = base_path
171
+ else:
172
+ path_str = ''
173
+
156
174
  path = (
157
- _path
158
- if no_auth or _path not in _required_login else (
159
- _path
175
+ path_str
176
+ if no_auth or path_str not in _required_login else (
177
+ path_str
160
178
  if session_id in active_sessions
161
179
  else 'login'
162
180
  )
@@ -868,10 +886,25 @@ dash_app.clientside_callback(
868
886
  location = "None";
869
887
  }
870
888
 
889
+ var subaction = "pipes";
890
+ if (action == "python"){
891
+ subaction = (
892
+ '"' + "pipe = mrsm.Pipe('"
893
+ + pipe_meta.connector
894
+ + "', '"
895
+ + pipe_meta.metric
896
+ + "'"
897
+ );
898
+ if (location != "None"){
899
+ subaction += ", '" + location + "'";
900
+ }
901
+ subaction += ", instance='" + pipe_meta.instance + "')" + '"';
902
+ }
903
+
871
904
  iframe.contentWindow.postMessage(
872
905
  {
873
906
  action: action,
874
- subaction: "pipes",
907
+ subaction: subaction,
875
908
  connector_keys: [pipe_meta.connector],
876
909
  metric_keys: [pipe_meta.metric],
877
910
  location_keys: [location],
@@ -45,6 +45,7 @@ def show_registration_disabled_collapse(n_clicks, is_open):
45
45
  State('username-input', 'value'),
46
46
  State('password-input', 'value'),
47
47
  State('location', 'href'),
48
+ State('location', 'pathname'),
48
49
  )
49
50
  def login_button_click(
50
51
  username_submit,
@@ -53,6 +54,7 @@ def login_button_click(
53
54
  username,
54
55
  password,
55
56
  location_href,
57
+ location_pathname,
56
58
  ):
57
59
  """
58
60
  When the user submits the login form, check the login.
@@ -69,4 +71,4 @@ def login_button_click(
69
71
  except HTTPException:
70
72
  form_class += ' is-invalid'
71
73
  session_data = None
72
- return session_data, form_class, (dash.no_update if not session_data else endpoints['dash'])
74
+ return session_data, form_class, dash.no_update