meerschaum 2.2.5.dev0__py3-none-any.whl → 2.2.5.dev2__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/arguments/_parse_arguments.py +23 -14
- meerschaum/_internal/arguments/_parser.py +4 -1
- meerschaum/_internal/shell/Shell.py +0 -3
- meerschaum/actions/bootstrap.py +14 -235
- meerschaum/actions/edit.py +98 -15
- meerschaum/actions/uninstall.py +24 -29
- meerschaum/config/__init__.py +16 -6
- meerschaum/config/_version.py +1 -1
- meerschaum/core/Pipe/_fetch.py +25 -21
- meerschaum/core/Pipe/_sync.py +89 -59
- meerschaum/plugins/bootstrap.py +333 -0
- meerschaum/utils/formatting/__init__.py +22 -10
- meerschaum/utils/prompt.py +11 -4
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/METADATA +1 -1
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/RECORD +21 -20
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/WHEEL +0 -0
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.5.dev0.dist-info → meerschaum-2.2.5.dev2.dist-info}/zip-safe +0 -0
@@ -80,8 +80,9 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
|
|
80
80
|
|
81
81
|
### rebuild sysargs without sub_arguments
|
82
82
|
filtered_sysargs = [
|
83
|
-
word
|
84
|
-
|
83
|
+
word
|
84
|
+
for i, word in enumerate(sysargs)
|
85
|
+
if i not in sub_arg_indices
|
85
86
|
]
|
86
87
|
|
87
88
|
try:
|
@@ -99,7 +100,6 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
|
|
99
100
|
except Exception as _e:
|
100
101
|
args_dict['text'] = ' '.join(sysargs)
|
101
102
|
args_dict[STATIC_CONFIG['system']['arguments']['failure_key']] = e
|
102
|
-
unknown = []
|
103
103
|
|
104
104
|
false_flags = [arg for arg, val in args_dict.items() if val is False]
|
105
105
|
for arg in false_flags:
|
@@ -126,17 +126,26 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
|
|
126
126
|
|
127
127
|
### remove None (but not False) args
|
128
128
|
none_args = []
|
129
|
+
none_args_keep = []
|
129
130
|
for a, v in args_dict.items():
|
130
131
|
if v is None:
|
131
132
|
none_args.append(a)
|
133
|
+
elif v == 'None':
|
134
|
+
none_args_keep.append(a)
|
132
135
|
for a in none_args:
|
133
136
|
del args_dict[a]
|
137
|
+
for a in none_args_keep:
|
138
|
+
args_dict[a] = None
|
134
139
|
|
135
140
|
### location_key '[None]' or 'None' -> None
|
136
141
|
if 'location_keys' in args_dict:
|
137
142
|
args_dict['location_keys'] = [
|
138
|
-
|
139
|
-
|
143
|
+
(
|
144
|
+
None
|
145
|
+
if lk in ('[None]', 'None')
|
146
|
+
else lk
|
147
|
+
)
|
148
|
+
for lk in args_dict['location_keys']
|
140
149
|
]
|
141
150
|
|
142
151
|
return parse_synonyms(args_dict)
|
@@ -145,7 +154,7 @@ def parse_arguments(sysargs: List[str]) -> Dict[str, Any]:
|
|
145
154
|
def parse_line(line: str) -> Dict[str, Any]:
|
146
155
|
"""
|
147
156
|
Parse a line of text into standard Meerschaum arguments.
|
148
|
-
|
157
|
+
|
149
158
|
Parameters
|
150
159
|
----------
|
151
160
|
line: str
|
@@ -165,12 +174,12 @@ def parse_line(line: str) -> Dict[str, Any]:
|
|
165
174
|
try:
|
166
175
|
return parse_arguments(shlex.split(line))
|
167
176
|
except Exception as e:
|
168
|
-
return {'action': [], 'text': line
|
177
|
+
return {'action': [], 'text': line}
|
169
178
|
|
170
179
|
|
171
180
|
def parse_synonyms(
|
172
|
-
|
173
|
-
|
181
|
+
args_dict: Dict[str, Any]
|
182
|
+
) -> Dict[str, Any]:
|
174
183
|
"""Check for synonyms (e.g. `async` = `True` -> `unblock` = `True`)"""
|
175
184
|
if args_dict.get('async', None):
|
176
185
|
args_dict['unblock'] = True
|
@@ -194,8 +203,8 @@ def parse_synonyms(
|
|
194
203
|
|
195
204
|
|
196
205
|
def parse_dict_to_sysargs(
|
197
|
-
|
198
|
-
|
206
|
+
args_dict: Dict[str, Any]
|
207
|
+
) -> List[str]:
|
199
208
|
"""Revert an arguments dictionary back to a command line list."""
|
200
209
|
from meerschaum._internal.arguments._parser import get_arguments_triggers
|
201
210
|
sysargs = []
|
@@ -230,9 +239,9 @@ def parse_dict_to_sysargs(
|
|
230
239
|
|
231
240
|
|
232
241
|
def remove_leading_action(
|
233
|
-
|
234
|
-
|
235
|
-
|
242
|
+
action: List[str],
|
243
|
+
_actions: Optional[Dict[str, Callable[[Any], SuccessTuple]]] = None,
|
244
|
+
) -> List[str]:
|
236
245
|
"""
|
237
246
|
Remove the leading strings in the `action` list.
|
238
247
|
|
@@ -37,12 +37,15 @@ class ArgumentParser(argparse.ArgumentParser):
|
|
37
37
|
return result
|
38
38
|
|
39
39
|
|
40
|
-
def parse_datetime(dt_str: str) -> datetime:
|
40
|
+
def parse_datetime(dt_str: str) -> Union[datetime, int, str]:
|
41
41
|
"""Parse a string into a datetime."""
|
42
42
|
from meerschaum.utils.misc import is_int
|
43
43
|
if is_int(dt_str):
|
44
44
|
return int(dt_str)
|
45
45
|
|
46
|
+
if dt_str in ('None', '[None]'):
|
47
|
+
return 'None'
|
48
|
+
|
46
49
|
from meerschaum.utils.packages import attempt_import
|
47
50
|
dateutil_parser = attempt_import('dateutil.parser')
|
48
51
|
|
@@ -182,7 +182,6 @@ def _check_complete_keys(line: str) -> Optional[List[str]]:
|
|
182
182
|
is_trigger = True
|
183
183
|
elif line.endswith(' '):
|
184
184
|
### return empty list so we don't try to parse an incomplete line.
|
185
|
-
# print('ABORT')
|
186
185
|
return []
|
187
186
|
|
188
187
|
from meerschaum.utils.misc import get_connector_labels
|
@@ -196,8 +195,6 @@ def _check_complete_keys(line: str) -> Optional[List[str]]:
|
|
196
195
|
if line.rstrip(' ').endswith(trigger):
|
197
196
|
return get_connector_labels()
|
198
197
|
|
199
|
-
# args = parse_line(line.rstrip(' '))
|
200
|
-
# search_term = args[var] if var != 'connector_keys' else args[var][0]
|
201
198
|
return get_connector_labels(search_term=last_word.rstrip(' '))
|
202
199
|
|
203
200
|
return None
|
meerschaum/actions/bootstrap.py
CHANGED
@@ -103,12 +103,14 @@ def _bootstrap_pipes(
|
|
103
103
|
)
|
104
104
|
try:
|
105
105
|
ck = choose(
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
(
|
107
|
+
"Where are the data coming from?\n\n" +
|
108
|
+
f" Please type the keys of a connector or enter '{new_label}'\n" +
|
109
|
+
" to register a new connector.\n\n" +
|
110
|
+
f" {get_config('formatting', 'emoji', 'connector')} Connector:"
|
111
|
+
),
|
110
112
|
get_connector_labels() + [new_label],
|
111
|
-
numeric = False
|
113
|
+
numeric = False,
|
112
114
|
)
|
113
115
|
except KeyboardInterrupt:
|
114
116
|
return abort_tuple
|
@@ -258,8 +260,8 @@ def _bootstrap_connectors(
|
|
258
260
|
_type = choose(
|
259
261
|
(
|
260
262
|
'Please choose a connector type.\n'
|
261
|
-
+ '
|
262
|
-
+ '
|
263
|
+
+ ' See https://meerschaum.io/reference/connectors '
|
264
|
+
+ 'for documentation on connectors.\n'
|
263
265
|
),
|
264
266
|
sorted(list(connectors)),
|
265
267
|
default = 'sql'
|
@@ -391,239 +393,16 @@ def _bootstrap_plugins(
|
|
391
393
|
"""
|
392
394
|
Launch an interactive wizard to guide the user to creating a new plugin.
|
393
395
|
"""
|
394
|
-
import
|
395
|
-
|
396
|
-
from meerschaum.utils.warnings import info, warn
|
397
|
-
from meerschaum.utils.prompt import prompt, choose, yes_no
|
398
|
-
from meerschaum.utils.formatting._shell import clear_screen
|
399
|
-
from meerschaum.utils.misc import edit_file
|
400
|
-
from meerschaum.config.paths import PLUGINS_DIR_PATHS
|
401
|
-
from meerschaum._internal.entry import entry
|
396
|
+
from meerschaum.utils.prompt import prompt
|
397
|
+
from meerschaum.plugins.bootstrap import bootstrap_plugin
|
402
398
|
|
403
399
|
if not action:
|
404
400
|
action = [prompt("Enter the name of your new plugin:")]
|
405
401
|
|
406
|
-
if len(PLUGINS_DIR_PATHS) > 1:
|
407
|
-
plugins_dir_path = pathlib.Path(
|
408
|
-
choose(
|
409
|
-
"In which directory do you want to write your plugin?",
|
410
|
-
[path.as_posix() for path in PLUGINS_DIR_PATHS],
|
411
|
-
numeric = True,
|
412
|
-
multiple = False,
|
413
|
-
default = PLUGINS_DIR_PATHS[0].as_posix(),
|
414
|
-
)
|
415
|
-
)
|
416
|
-
else:
|
417
|
-
plugins_dir_path = PLUGINS_DIR_PATHS[0]
|
418
|
-
|
419
|
-
clear_screen(debug=debug)
|
420
|
-
info(
|
421
|
-
"Answer the questions below to pick out features.\n"
|
422
|
-
+ " See the Writing Plugins guide for documentation:\n"
|
423
|
-
+ " https://meerschaum.io/reference/plugins/writing-plugins/ for documentation.\n"
|
424
|
-
)
|
425
|
-
|
426
|
-
imports_lines = {
|
427
|
-
'default': (
|
428
|
-
"import meerschaum as mrsm\n"
|
429
|
-
),
|
430
|
-
'action': (
|
431
|
-
"from meerschaum.actions import make_action\n"
|
432
|
-
),
|
433
|
-
'api': (
|
434
|
-
"from meerschaum.plugins import api_plugin\n"
|
435
|
-
),
|
436
|
-
'web': (
|
437
|
-
"from meerschaum.plugins import web_page, dash_plugin\n"
|
438
|
-
),
|
439
|
-
'api+web': (
|
440
|
-
"from meerschaum.plugins import api_plugin, web_page, dash_plugin\n"
|
441
|
-
),
|
442
|
-
}
|
443
|
-
|
444
|
-
### TODO: Add feature for custom connectors.
|
445
|
-
feature_lines = {
|
446
|
-
'header': (
|
447
|
-
"# {plugin_name}.py\n\n"
|
448
|
-
),
|
449
|
-
'default': (
|
450
|
-
"__version__ = '0.0.1'\n"
|
451
|
-
"\n# Add any depedencies to `required` (similar to `requirements.txt`).\n"
|
452
|
-
"required = []\n\n"
|
453
|
-
),
|
454
|
-
'setup': (
|
455
|
-
"def setup(**kwargs) -> mrsm.SuccessTuple:\n"
|
456
|
-
" \"\"\"Executed during installation and `mrsm setup plugin {plugin_name}`.\"\"\"\n"
|
457
|
-
" return True, \"Success\"\n\n\n"
|
458
|
-
),
|
459
|
-
'register': (
|
460
|
-
"def register(pipe: mrsm.Pipe):\n"
|
461
|
-
" \"\"\"Return the default parameters for a new pipe.\"\"\"\n"
|
462
|
-
" return {\n"
|
463
|
-
" 'columns': {\n"
|
464
|
-
" 'datetime': None,\n"
|
465
|
-
" }\n"
|
466
|
-
" }\n\n\n"
|
467
|
-
),
|
468
|
-
'fetch': (
|
469
|
-
"def fetch(pipe: mrsm.Pipe, **kwargs):\n"
|
470
|
-
" \"\"\"Return or yield dataframe-like objects.\"\"\"\n"
|
471
|
-
" docs = []\n"
|
472
|
-
" # populate docs with dictionaries (rows).\n"
|
473
|
-
" return docs\n\n\n"
|
474
|
-
),
|
475
|
-
'action': (
|
476
|
-
"@make_action\n"
|
477
|
-
"def {action_name}(**kwargs) -> mrsm.SuccessTuple:\n"
|
478
|
-
" \"\"\"Run `mrsm {action_spaces}` to trigger.\"\"\"\n"
|
479
|
-
" return True, \"Success\"\n\n\n"
|
480
|
-
),
|
481
|
-
'api': (
|
482
|
-
"@api_plugin\n"
|
483
|
-
"def init_app(fastapi_app):\n"
|
484
|
-
" \"\"\"Add new endpoints to the FastAPI app.\"\"\"\n\n"
|
485
|
-
" import fastapi\n"
|
486
|
-
" from meerschaum.api import manager\n\n"
|
487
|
-
" @fastapi_app.get('/my/endpoint')\n"
|
488
|
-
" def get_my_endpoint(curr_user=fastapi.Depends(manager)):\n"
|
489
|
-
" return {'message': 'Hello, World!'}\n\n\n"
|
490
|
-
),
|
491
|
-
'web': (
|
492
|
-
"@dash_plugin\n"
|
493
|
-
"def init_dash(dash_app):\n"
|
494
|
-
" \"\"\"Initialize the Plotly Dash application.\"\"\"\n"
|
495
|
-
" import dash.html as html\n"
|
496
|
-
" import dash.dcc as dcc\n"
|
497
|
-
" from dash import Input, Output, State, no_update\n"
|
498
|
-
" import dash_bootstrap_components as dbc\n\n"
|
499
|
-
" # Create a new page at the path `/dash/{plugin_name}`.\n"
|
500
|
-
" @web_page('{plugin_name}', login_required=False)\n"
|
501
|
-
" def page_layout():\n"
|
502
|
-
" \"\"\"Return the layout objects for this page.\"\"\"\n"
|
503
|
-
" return dbc.Container([\n"
|
504
|
-
" dcc.Location(id='{plugin_name}-location'),\n"
|
505
|
-
" html.Div(id='output-div'),\n"
|
506
|
-
" ])\n\n"
|
507
|
-
" @dash_app.callback(\n"
|
508
|
-
" Output('output-div', 'children'),\n"
|
509
|
-
" Input('{plugin_name}-location', 'pathname'),\n"
|
510
|
-
" )\n"
|
511
|
-
" def render_page_on_url_change(pathname: str):\n"
|
512
|
-
" \"\"\"Reload page contents when the URL path changes.\"\"\"\n"
|
513
|
-
" return html.H1(\"Hello from plugin '{plugin_name}'!\")\n\n\n"
|
514
|
-
),
|
515
|
-
}
|
516
|
-
|
517
402
|
for plugin_name in action:
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
warn(f"Plugin '{plugin_name}' is already installed!", stack=False)
|
522
|
-
uninstall_plugin = yes_no(
|
523
|
-
f"Do you want to first uninstall '{plugin}'?",
|
524
|
-
default = 'n',
|
525
|
-
**kwargs
|
526
|
-
)
|
527
|
-
if not uninstall_plugin:
|
528
|
-
return False, f"Plugin '{plugin_name}' already exists."
|
529
|
-
|
530
|
-
uninstall_success, uninstall_msg = entry(['uninstall', 'plugin', plugin_name, '-f'])
|
531
|
-
if not uninstall_success:
|
532
|
-
return uninstall_success, uninstall_msg
|
533
|
-
clear_screen(debug=debug)
|
534
|
-
|
535
|
-
features = choose(
|
536
|
-
"Which of the following features would you like to add to your plugin?",
|
537
|
-
[
|
538
|
-
(
|
539
|
-
'fetch',
|
540
|
-
'Fetch data\n (e.g. extracting from a remote API)\n'
|
541
|
-
),
|
542
|
-
(
|
543
|
-
'action',
|
544
|
-
'New actions\n (e.g. `mrsm sing song`)\n'
|
545
|
-
),
|
546
|
-
(
|
547
|
-
'api',
|
548
|
-
'New API endpoints\n (e.g. `POST /my/new/endpoint`)\n',
|
549
|
-
),
|
550
|
-
(
|
551
|
-
'web',
|
552
|
-
'New web console page\n (e.g. `/dash/my-web-app`)\n',
|
553
|
-
),
|
554
|
-
],
|
555
|
-
default = 'fetch',
|
556
|
-
multiple = True,
|
557
|
-
as_indices = True,
|
558
|
-
**kwargs
|
559
|
-
)
|
560
|
-
|
561
|
-
action_name = ''
|
562
|
-
if 'action' in features:
|
563
|
-
while True:
|
564
|
-
try:
|
565
|
-
action_name = prompt(
|
566
|
-
"What is name of your action?\n "
|
567
|
-
+ "(separate subactions with spaces, e.g. `sing song`):"
|
568
|
-
).replace(' ', '_')
|
569
|
-
except KeyboardInterrupt as e:
|
570
|
-
return False, "Aborted plugin creation."
|
571
|
-
|
572
|
-
if action_name:
|
573
|
-
break
|
574
|
-
warn("Please enter an action.", stack=False)
|
575
|
-
|
576
|
-
action_spaces = action_name.replace('_', ' ')
|
577
|
-
|
578
|
-
plugin_labels = {
|
579
|
-
'plugin_name': plugin_name,
|
580
|
-
'action_name': action_name,
|
581
|
-
'action_spaces': action_spaces,
|
582
|
-
}
|
583
|
-
|
584
|
-
body_text = ""
|
585
|
-
body_text += feature_lines['header'].format(**plugin_labels)
|
586
|
-
body_text += imports_lines['default'].format(**plugin_labels)
|
587
|
-
if 'action' in features:
|
588
|
-
body_text += imports_lines['action']
|
589
|
-
if 'api' in features and 'web' in features:
|
590
|
-
body_text += imports_lines['api+web']
|
591
|
-
elif 'api' in features:
|
592
|
-
body_text += imports_lines['api']
|
593
|
-
elif 'web' in features:
|
594
|
-
body_text += imports_lines['web']
|
595
|
-
|
596
|
-
body_text += "\n"
|
597
|
-
body_text += feature_lines['default'].format(**plugin_labels)
|
598
|
-
body_text += feature_lines['setup'].format(**plugin_labels)
|
599
|
-
|
600
|
-
if 'fetch' in features:
|
601
|
-
body_text += feature_lines['register']
|
602
|
-
body_text += feature_lines['fetch']
|
603
|
-
|
604
|
-
if 'action' in features:
|
605
|
-
body_text += feature_lines['action'].format(**plugin_labels)
|
606
|
-
|
607
|
-
if 'api' in features:
|
608
|
-
body_text += feature_lines['api']
|
609
|
-
|
610
|
-
if 'web' in features:
|
611
|
-
body_text += feature_lines['web'].format(**plugin_labels)
|
612
|
-
|
613
|
-
try:
|
614
|
-
with open(plugin_path, 'w+', encoding='utf-8') as f:
|
615
|
-
f.write(body_text.rstrip())
|
616
|
-
except Exception as e:
|
617
|
-
error_msg = f"Failed to write file '{plugin_path}':\n{e}"
|
618
|
-
return False, error_msg
|
619
|
-
|
620
|
-
mrsm.pprint((True, f"Successfully created file '{plugin_path}'."))
|
621
|
-
try:
|
622
|
-
_ = prompt(f"Press [Enter] to edit plugin '{plugin_name}', [CTRL+C] to skip.")
|
623
|
-
except (KeyboardInterrupt, Exception):
|
624
|
-
continue
|
625
|
-
|
626
|
-
edit_file(plugin_path, debug=debug)
|
403
|
+
bootstrap_success, bootstrap_msg = bootstrap_plugin(plugin_name)
|
404
|
+
if not bootstrap_success:
|
405
|
+
return bootstrap_success, bootstrap_msg
|
627
406
|
|
628
407
|
return True, "Success"
|
629
408
|
|
meerschaum/actions/edit.py
CHANGED
@@ -7,6 +7,7 @@ Functions for editing elements belong here.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
import meerschaum as mrsm
|
10
11
|
from meerschaum.utils.typing import List, Any, SuccessTuple, Optional, Dict
|
11
12
|
|
12
13
|
def edit(
|
@@ -22,19 +23,22 @@ def edit(
|
|
22
23
|
'pipes' : _edit_pipes,
|
23
24
|
'definition': _edit_definition,
|
24
25
|
'users' : _edit_users,
|
26
|
+
'plugins' : _edit_plugins,
|
25
27
|
}
|
26
28
|
return choose_subaction(action, options, **kw)
|
27
29
|
|
28
30
|
|
29
31
|
def _complete_edit(
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
action: Optional[List[str]] = None,
|
33
|
+
**kw: Any
|
34
|
+
) -> List[str]:
|
33
35
|
"""
|
34
36
|
Override the default Meerschaum `complete_` function.
|
35
37
|
"""
|
36
38
|
options = {
|
37
39
|
'config': _complete_edit_config,
|
40
|
+
'plugin': _complete_edit_plugins,
|
41
|
+
'plugins': _complete_edit_plugins,
|
38
42
|
}
|
39
43
|
|
40
44
|
if action is None:
|
@@ -78,7 +82,7 @@ def _edit_config(action : Optional[List[str]] = None, **kw : Any) -> SuccessTupl
|
|
78
82
|
action.append('meerschaum')
|
79
83
|
return edit_config(keys=action, **kw)
|
80
84
|
|
81
|
-
def _complete_edit_config(action: Optional[List[str]] = None, **kw
|
85
|
+
def _complete_edit_config(action: Optional[List[str]] = None, **kw: Any) -> List[str]:
|
82
86
|
from meerschaum.config._read_config import get_possible_keys
|
83
87
|
keys = get_possible_keys()
|
84
88
|
if not action:
|
@@ -172,9 +176,9 @@ def _edit_pipes(
|
|
172
176
|
|
173
177
|
|
174
178
|
def _edit_definition(
|
175
|
-
|
176
|
-
|
177
|
-
|
179
|
+
action: Optional[List[str]] = None,
|
180
|
+
**kw
|
181
|
+
) -> SuccessTuple:
|
178
182
|
"""
|
179
183
|
Edit pipes' definitions.
|
180
184
|
Alias for `edit pipes definition`.
|
@@ -183,13 +187,13 @@ def _edit_definition(
|
|
183
187
|
|
184
188
|
|
185
189
|
def _edit_users(
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
190
|
+
action: Optional[List[str]] = None,
|
191
|
+
mrsm_instance: Optional[str] = None,
|
192
|
+
yes: bool = False,
|
193
|
+
noask: bool = False,
|
194
|
+
debug: bool = False,
|
195
|
+
**kw: Any
|
196
|
+
) -> SuccessTuple:
|
193
197
|
"""
|
194
198
|
Edit users' registration information.
|
195
199
|
"""
|
@@ -262,7 +266,7 @@ def _edit_users(
|
|
262
266
|
if not action:
|
263
267
|
return False, "No users to edit."
|
264
268
|
|
265
|
-
success =
|
269
|
+
success = {}
|
266
270
|
for username in action:
|
267
271
|
try:
|
268
272
|
user = build_user(username)
|
@@ -289,6 +293,85 @@ def _edit_users(
|
|
289
293
|
info(msg)
|
290
294
|
return True, msg
|
291
295
|
|
296
|
+
|
297
|
+
def _edit_plugins(
|
298
|
+
action: Optional[List[str]] = None,
|
299
|
+
debug: bool = False,
|
300
|
+
**kwargs: Any
|
301
|
+
):
|
302
|
+
"""
|
303
|
+
Edit a plugin's source code.
|
304
|
+
"""
|
305
|
+
import pathlib
|
306
|
+
from meerschaum.utils.warnings import warn
|
307
|
+
from meerschaum.utils.prompt import prompt, yes_no
|
308
|
+
from meerschaum.utils.misc import edit_file
|
309
|
+
from meerschaum.utils.packages import reload_meerschaum
|
310
|
+
from meerschaum.actions import actions
|
311
|
+
|
312
|
+
if not action:
|
313
|
+
return False, "Specify which plugin to edit."
|
314
|
+
|
315
|
+
for plugin_name in action:
|
316
|
+
plugin = mrsm.Plugin(plugin_name)
|
317
|
+
|
318
|
+
if not plugin.is_installed():
|
319
|
+
warn(f"Plugin '{plugin_name}' is not installed.", stack=False)
|
320
|
+
|
321
|
+
if not yes_no(
|
322
|
+
f"Would you like to create a new plugin '{plugin_name}'?",
|
323
|
+
**kwargs
|
324
|
+
):
|
325
|
+
return False, f"Plugin '{plugin_name}' does not exist."
|
326
|
+
|
327
|
+
actions['bootstrap'](
|
328
|
+
['plugins', plugin_name],
|
329
|
+
debug = debug,
|
330
|
+
**kwargs
|
331
|
+
)
|
332
|
+
continue
|
333
|
+
|
334
|
+
plugin_file_path = pathlib.Path(plugin.__file__).resolve()
|
335
|
+
|
336
|
+
try:
|
337
|
+
_ = prompt(f"Press [Enter] to open '{plugin_file_path}':", icon=False)
|
338
|
+
except (KeyboardInterrupt, Exception):
|
339
|
+
continue
|
340
|
+
|
341
|
+
edit_file(plugin_file_path)
|
342
|
+
reload_meerschaum(debug=debug)
|
343
|
+
|
344
|
+
return True, "Success"
|
345
|
+
|
346
|
+
|
347
|
+
def _complete_edit_plugins(
|
348
|
+
action: Optional[List[str]] = None,
|
349
|
+
line: Optional[str] = None,
|
350
|
+
**kw: Any
|
351
|
+
) -> List[str]:
|
352
|
+
from meerschaum.plugins import get_plugins_names
|
353
|
+
plugins_names = get_plugins_names(try_import=False)
|
354
|
+
if not action:
|
355
|
+
return plugins_names
|
356
|
+
|
357
|
+
last_word = action[-1]
|
358
|
+
if last_word in plugins_names and (line or '')[-1] == ' ':
|
359
|
+
return [
|
360
|
+
plugin_name
|
361
|
+
for plugin_name in plugins_names
|
362
|
+
if plugin_name not in action
|
363
|
+
]
|
364
|
+
|
365
|
+
possibilities = []
|
366
|
+
for plugin_name in plugins_names:
|
367
|
+
if (
|
368
|
+
plugin_name.startswith(last_word)
|
369
|
+
and plugin_name not in action
|
370
|
+
):
|
371
|
+
possibilities.append(plugin_name)
|
372
|
+
return possibilities
|
373
|
+
|
374
|
+
|
292
375
|
### NOTE: This must be the final statement of the module.
|
293
376
|
### Any subactions added below these lines will not
|
294
377
|
### be added to the `help` docstring.
|
meerschaum/actions/uninstall.py
CHANGED
@@ -25,9 +25,9 @@ def uninstall(
|
|
25
25
|
|
26
26
|
|
27
27
|
def _complete_uninstall(
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
action: Optional[List[str]] = None,
|
29
|
+
**kw: Any
|
30
|
+
) -> List[str]:
|
31
31
|
"""
|
32
32
|
Override the default Meerschaum `complete_` function.
|
33
33
|
"""
|
@@ -49,15 +49,16 @@ def _complete_uninstall(
|
|
49
49
|
from meerschaum._internal.shell import default_action_completer
|
50
50
|
return default_action_completer(action=(['uninstall'] + action), **kw)
|
51
51
|
|
52
|
+
|
52
53
|
def _uninstall_plugins(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
action: Optional[List[str]] = None,
|
55
|
+
repository: Optional[str] = None,
|
56
|
+
yes: bool = False,
|
57
|
+
force: bool = False,
|
58
|
+
noask: bool = False,
|
59
|
+
debug: bool = False,
|
60
|
+
**kw: Any
|
61
|
+
) -> SuccessTuple:
|
61
62
|
"""
|
62
63
|
Remove installed plugins. Does not affect repository registrations.
|
63
64
|
"""
|
@@ -135,26 +136,20 @@ def _uninstall_plugins(
|
|
135
136
|
|
136
137
|
|
137
138
|
def _complete_uninstall_plugins(action: Optional[List[str]] = None, **kw) -> List[str]:
|
138
|
-
from meerschaum.
|
139
|
-
|
140
|
-
|
141
|
-
return _plugin_names
|
142
|
-
possibilities = []
|
143
|
-
for name in _plugin_names:
|
144
|
-
if name.startswith(action[0]) and action[0] != name:
|
145
|
-
possibilities.append(name)
|
146
|
-
return possibilities
|
139
|
+
from meerschaum.actions.edit import _complete_edit_plugins
|
140
|
+
return _complete_edit_plugins(action=action, **kw)
|
141
|
+
|
147
142
|
|
148
143
|
def _uninstall_packages(
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
144
|
+
action: Optional[List[str]] = None,
|
145
|
+
sub_args: Optional[List[str]] = None,
|
146
|
+
venv: Optional[str] = 'mrsm',
|
147
|
+
yes: bool = False,
|
148
|
+
force: bool = False,
|
149
|
+
noask: bool = False,
|
150
|
+
debug: bool = False,
|
151
|
+
**kw: Any
|
152
|
+
) -> SuccessTuple:
|
158
153
|
"""
|
159
154
|
Uninstall PyPI packages from the Meerschaum virtual environment.
|
160
155
|
|