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.
- meerschaum/_internal/shell/Shell.py +40 -16
- meerschaum/_internal/term/__init__.py +3 -2
- meerschaum/_internal/term/tools.py +1 -1
- meerschaum/actions/api.py +65 -31
- meerschaum/actions/python.py +56 -24
- meerschaum/actions/start.py +2 -4
- meerschaum/actions/uninstall.py +5 -9
- meerschaum/actions/upgrade.py +11 -3
- meerschaum/api/__init__.py +1 -0
- meerschaum/api/dash/callbacks/__init__.py +4 -0
- meerschaum/api/dash/callbacks/custom.py +39 -0
- meerschaum/api/dash/callbacks/dashboard.py +39 -6
- meerschaum/api/dash/callbacks/login.py +3 -1
- meerschaum/api/dash/components.py +5 -2
- meerschaum/api/dash/pipes.py +145 -97
- meerschaum/config/_default.py +1 -0
- meerschaum/config/_paths.py +12 -12
- meerschaum/config/_version.py +1 -1
- meerschaum/config/paths.py +10 -0
- meerschaum/config/static/__init__.py +1 -1
- meerschaum/connectors/__init__.py +1 -1
- meerschaum/core/Pipe/__init__.py +5 -0
- meerschaum/core/Pipe/_sync.py +2 -3
- meerschaum/plugins/__init__.py +67 -9
- meerschaum/utils/daemon/Daemon.py +7 -2
- meerschaum/utils/misc.py +6 -0
- meerschaum/utils/packages/__init__.py +212 -53
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/process.py +12 -2
- meerschaum/utils/schedule.py +1 -1
- meerschaum/utils/venv/__init__.py +46 -11
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/METADATA +5 -1
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/RECORD +39 -37
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/WHEEL +1 -1
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.1.dist-info → meerschaum-2.2.2.dist-info}/top_level.txt +0 -0
- {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,
|
308
|
+
from meerschaum.utils.formatting import CHARSET, ANSI, colored
|
287
309
|
|
288
310
|
if shell_attrs.get('intro', None) != '':
|
289
|
-
self.intro =
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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,
|
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
|
-
)
|
870
|
+
)
|
871
|
+
if ANSI
|
872
|
+
else colored(shell_attrs['instance_keys'], 'on white')
|
853
873
|
)
|
854
874
|
repo_colored = (
|
855
|
-
colored(
|
856
|
-
|
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,
|
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
|
-
|
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',
|
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
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
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()
|
meerschaum/actions/python.py
CHANGED
@@ -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.
|
18
|
-
|
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
|
-
|
24
|
-
|
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.
|
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
|
-
|
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
|
-
|
59
|
-
|
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
|
-
|
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}."
|
meerschaum/actions/start.py
CHANGED
@@ -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,
|
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)
|
meerschaum/actions/uninstall.py
CHANGED
@@ -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:
|
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 '
|
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)
|
meerschaum/actions/upgrade.py
CHANGED
@@ -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 = '
|
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}'."
|
meerschaum/api/__init__.py
CHANGED
@@ -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
|
-
|
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
|
-
|
158
|
-
if no_auth or
|
159
|
-
|
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:
|
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,
|
74
|
+
return session_data, form_class, dash.no_update
|