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
@@ -0,0 +1,333 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
Define the bootstrapping wizard for creating plugins.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import re
|
10
|
+
import pathlib
|
11
|
+
import meerschaum as mrsm
|
12
|
+
from meerschaum.utils.typing import Any, SuccessTuple, Dict, List
|
13
|
+
from meerschaum.utils.warnings import warn, info
|
14
|
+
from meerschaum.utils.prompt import prompt, choose, yes_no
|
15
|
+
from meerschaum.utils.formatting._shell import clear_screen
|
16
|
+
|
17
|
+
FEATURE_CHOICES: Dict[str, str] = {
|
18
|
+
'fetch' : 'Fetch data\n (e.g. extracting from a remote API)\n',
|
19
|
+
'connector': 'Custom connector\n (e.g. manage credentials)\n',
|
20
|
+
'action' : 'New actions\n (e.g. `mrsm sing song`)\n',
|
21
|
+
'api' : 'New API endpoints\n (e.g. `POST /my/new/endpoint`)\n',
|
22
|
+
'web' : 'New web console page\n (e.g. `/dash/my-web-app`)\n',
|
23
|
+
}
|
24
|
+
|
25
|
+
IMPORTS_LINES: Dict[str, str] = {
|
26
|
+
'stdlib': (
|
27
|
+
"from datetime import datetime, timedelta, timezone\n"
|
28
|
+
),
|
29
|
+
'default': (
|
30
|
+
"import meerschaum as mrsm\n"
|
31
|
+
"from meerschaum.config import get_plugin_config, write_plugin_config\n"
|
32
|
+
),
|
33
|
+
'connector': (
|
34
|
+
"from meerschaum.connectors import Connector, make_connector\n"
|
35
|
+
),
|
36
|
+
'action': (
|
37
|
+
"from meerschaum.actions import make_action\n"
|
38
|
+
),
|
39
|
+
'api': (
|
40
|
+
"from meerschaum.plugins import api_plugin\n"
|
41
|
+
),
|
42
|
+
'web': (
|
43
|
+
"from meerschaum.plugins import web_page, dash_plugin\n"
|
44
|
+
),
|
45
|
+
'api+web': (
|
46
|
+
"from meerschaum.plugins import api_plugin, web_page, dash_plugin\n"
|
47
|
+
),
|
48
|
+
}
|
49
|
+
|
50
|
+
### TODO: Add feature for custom connectors.
|
51
|
+
FEATURE_LINES: Dict[str, str] = {
|
52
|
+
'header': (
|
53
|
+
"#! /usr/bin/env python3\n"
|
54
|
+
"# -*- coding: utf-8 -*-\n\n"
|
55
|
+
"\"\"\"\n"
|
56
|
+
"Implement the plugin '{plugin_name}'.\n\n"
|
57
|
+
"See the Writing Plugins guide for more information:\n"
|
58
|
+
"https://meerschaum.io/reference/plugins/writing-plugins/\n"
|
59
|
+
"\"\"\"\n\n"
|
60
|
+
),
|
61
|
+
'default': (
|
62
|
+
"__version__ = '0.0.1'\n"
|
63
|
+
"\n# Add any dependencies to `required` (similar to `requirements.txt`).\n"
|
64
|
+
"required: list[str] = []\n\n\n"
|
65
|
+
),
|
66
|
+
'setup': (
|
67
|
+
"def setup(**kwargs) -> mrsm.SuccessTuple:\n"
|
68
|
+
" \"\"\"Executed during installation and `mrsm setup plugin {plugin_name}`.\"\"\"\n"
|
69
|
+
" return True, \"Success\"\n\n\n"
|
70
|
+
),
|
71
|
+
'register': (
|
72
|
+
"def register(pipe: mrsm.Pipe):\n"
|
73
|
+
" \"\"\"Return the default parameters for a new pipe.\"\"\"\n"
|
74
|
+
" return {{\n"
|
75
|
+
" 'columns': {{\n"
|
76
|
+
" 'datetime': {dt_col_name},\n"
|
77
|
+
" }}\n"
|
78
|
+
" }}\n\n\n"
|
79
|
+
),
|
80
|
+
'fetch': (
|
81
|
+
"def fetch(\n"
|
82
|
+
" pipe: mrsm.Pipe,\n"
|
83
|
+
" begin: datetime | None = None,\n"
|
84
|
+
" end: datetime | None = None,\n"
|
85
|
+
" **kwargs\n"
|
86
|
+
"):\n"
|
87
|
+
" \"\"\"Return or yield dataframes.\"\"\"\n"
|
88
|
+
" docs = []\n"
|
89
|
+
" # populate docs with dictionaries (rows).\n"
|
90
|
+
" return docs\n\n\n"
|
91
|
+
),
|
92
|
+
'connector': (
|
93
|
+
"@make_connector\n"
|
94
|
+
"class {plugin_name_capitalized}Connector(Connector):\n"
|
95
|
+
" \"\"\"Implement '{plugin_name_lower}' connectors.\"\"\"\n\n"
|
96
|
+
" REQUIRED_ATTRIBUTES: list[str] = []\n"
|
97
|
+
" \n"
|
98
|
+
" def fetch(\n"
|
99
|
+
" self,\n"
|
100
|
+
" pipe: mrsm.Pipe,\n"
|
101
|
+
" begin: datetime | None = None,\n"
|
102
|
+
" end: datetime | None = None,\n"
|
103
|
+
" **kwargs\n"
|
104
|
+
" ):\n"
|
105
|
+
" \"\"\"Return or yield dataframes.\"\"\"\n"
|
106
|
+
" docs = []\n"
|
107
|
+
" # populate docs with dictionaries (rows).\n"
|
108
|
+
" return docs\n\n\n"
|
109
|
+
),
|
110
|
+
'action': (
|
111
|
+
"@make_action\n"
|
112
|
+
"def {action_name}(**kwargs) -> mrsm.SuccessTuple:\n"
|
113
|
+
" \"\"\"Run `mrsm {action_spaces}` to trigger.\"\"\"\n"
|
114
|
+
" return True, \"Success\"\n\n\n"
|
115
|
+
),
|
116
|
+
'api': (
|
117
|
+
"@api_plugin\n"
|
118
|
+
"def init_app(fastapi_app):\n"
|
119
|
+
" \"\"\"Add new endpoints to the FastAPI app.\"\"\"\n\n"
|
120
|
+
" import fastapi\n"
|
121
|
+
" from meerschaum.api import manager\n\n"
|
122
|
+
" @fastapi_app.get('/{plugin_name}')\n"
|
123
|
+
" def get_my_endpoint(curr_user=fastapi.Depends(manager)):\n"
|
124
|
+
" return {{'message': \"Hello from plugin '{plugin_name}'!\"}}\n\n\n"
|
125
|
+
),
|
126
|
+
'web': (
|
127
|
+
"@dash_plugin\n"
|
128
|
+
"def init_dash(dash_app):\n"
|
129
|
+
" \"\"\"Initialize the Plotly Dash application.\"\"\"\n\n"
|
130
|
+
" import dash.html as html\n"
|
131
|
+
" import dash.dcc as dcc\n"
|
132
|
+
" from dash import Input, Output, State, no_update\n"
|
133
|
+
" import dash_bootstrap_components as dbc\n\n"
|
134
|
+
" # Create a new page at the path `/dash/{plugin_name}`.\n"
|
135
|
+
" @web_page('{plugin_name}', login_required=False)\n"
|
136
|
+
" def page_layout():\n"
|
137
|
+
" \"\"\"Return the layout objects for this page.\"\"\"\n"
|
138
|
+
" return dbc.Container([\n"
|
139
|
+
" dcc.Location(id='{plugin_name}-location'),\n"
|
140
|
+
" html.Div(id='output-div'),\n"
|
141
|
+
" ])\n\n"
|
142
|
+
" @dash_app.callback(\n"
|
143
|
+
" Output('output-div', 'children'),\n"
|
144
|
+
" Input('{plugin_name}-location', 'pathname'),\n"
|
145
|
+
" )\n"
|
146
|
+
" def render_page_on_url_change(pathname: str):\n"
|
147
|
+
" \"\"\"Reload page contents when the URL path changes.\"\"\"\n"
|
148
|
+
" return html.H1(\"Hello from plugin '{plugin_name}'!\")\n\n\n"
|
149
|
+
),
|
150
|
+
}
|
151
|
+
|
152
|
+
def bootstrap_plugin(
|
153
|
+
plugin_name: str,
|
154
|
+
debug: bool = False,
|
155
|
+
**kwargs: Any
|
156
|
+
) -> SuccessTuple:
|
157
|
+
"""
|
158
|
+
Prompt the user for features and create a plugin file.
|
159
|
+
"""
|
160
|
+
from meerschaum.utils.misc import edit_file
|
161
|
+
plugins_dir_path = _get_plugins_dir_path()
|
162
|
+
clear_screen(debug=debug)
|
163
|
+
info(
|
164
|
+
"Answer the questions below to pick out features.\n"
|
165
|
+
+ " See the Writing Plugins guide for documentation:\n"
|
166
|
+
+ " https://meerschaum.io/reference/plugins/writing-plugins/ "
|
167
|
+
+ "for documentation.\n"
|
168
|
+
)
|
169
|
+
|
170
|
+
plugin = mrsm.Plugin(plugin_name)
|
171
|
+
if plugin.is_installed():
|
172
|
+
uninstall_success, uninstall_msg = _ask_to_uninstall(plugin)
|
173
|
+
if not uninstall_success:
|
174
|
+
return uninstall_success, uninstall_msg
|
175
|
+
clear_screen(debug=debug)
|
176
|
+
|
177
|
+
features: List[str] = choose(
|
178
|
+
"Which of the following features would you like to add to your plugin?",
|
179
|
+
list(FEATURE_CHOICES.items()),
|
180
|
+
default = 'fetch',
|
181
|
+
multiple = True,
|
182
|
+
as_indices = True,
|
183
|
+
**kwargs
|
184
|
+
)
|
185
|
+
|
186
|
+
clear_screen(debug=debug)
|
187
|
+
|
188
|
+
action_name = ''
|
189
|
+
if 'action' in features:
|
190
|
+
action_name = _get_action_name()
|
191
|
+
clear_screen(debug=debug)
|
192
|
+
action_spaces = action_name.replace('_', ' ')
|
193
|
+
|
194
|
+
dt_col_name = None
|
195
|
+
if 'fetch' in features:
|
196
|
+
dt_col_name = _get_quoted_dt_col_name()
|
197
|
+
clear_screen(debug=debug)
|
198
|
+
|
199
|
+
plugin_labels = {
|
200
|
+
'plugin_name': plugin_name,
|
201
|
+
'plugin_name_capitalized': re.split(
|
202
|
+
r'[-_]', plugin_name.lower()
|
203
|
+
)[0].capitalize(),
|
204
|
+
'plugin_name_lower': plugin_name.lower(),
|
205
|
+
'action_name': action_name,
|
206
|
+
'action_spaces': action_spaces,
|
207
|
+
'dt_col_name': dt_col_name,
|
208
|
+
}
|
209
|
+
|
210
|
+
body_text = ""
|
211
|
+
body_text += FEATURE_LINES['header'].format(**plugin_labels)
|
212
|
+
body_text += IMPORTS_LINES['stdlib'].format(**plugin_labels)
|
213
|
+
body_text += IMPORTS_LINES['default'].format(**plugin_labels)
|
214
|
+
if 'connector' in features:
|
215
|
+
body_text += IMPORTS_LINES['connector'].format(**plugin_labels)
|
216
|
+
if 'action' in features:
|
217
|
+
body_text += IMPORTS_LINES['action'].format(**plugin_labels)
|
218
|
+
if 'api' in features and 'web' in features:
|
219
|
+
body_text += IMPORTS_LINES['api+web'].format(**plugin_labels)
|
220
|
+
elif 'api' in features:
|
221
|
+
body_text += IMPORTS_LINES['api'].format(**plugin_labels)
|
222
|
+
elif 'web' in features:
|
223
|
+
body_text += IMPORTS_LINES['web'].format(**plugin_labels)
|
224
|
+
|
225
|
+
body_text += "\n"
|
226
|
+
body_text += FEATURE_LINES['default'].format(**plugin_labels)
|
227
|
+
body_text += FEATURE_LINES['setup'].format(**plugin_labels)
|
228
|
+
|
229
|
+
if 'fetch' in features:
|
230
|
+
body_text += FEATURE_LINES['register'].format(**plugin_labels)
|
231
|
+
body_text += FEATURE_LINES['fetch'].format(**plugin_labels)
|
232
|
+
|
233
|
+
if 'connector' in features:
|
234
|
+
body_text += FEATURE_LINES['connector'].format(**plugin_labels)
|
235
|
+
|
236
|
+
if 'action' in features:
|
237
|
+
body_text += FEATURE_LINES['action'].format(**plugin_labels)
|
238
|
+
|
239
|
+
if 'api' in features:
|
240
|
+
body_text += FEATURE_LINES['api'].format(**plugin_labels)
|
241
|
+
|
242
|
+
if 'web' in features:
|
243
|
+
body_text += FEATURE_LINES['web'].format(**plugin_labels)
|
244
|
+
|
245
|
+
try:
|
246
|
+
plugin_path = plugins_dir_path / (plugin_name + '.py')
|
247
|
+
with open(plugin_path, 'w+', encoding='utf-8') as f:
|
248
|
+
f.write(body_text.rstrip())
|
249
|
+
except Exception as e:
|
250
|
+
error_msg = f"Failed to write file '{plugin_path}':\n{e}"
|
251
|
+
return False, error_msg
|
252
|
+
|
253
|
+
clear_screen(debug=debug)
|
254
|
+
mrsm.pprint((True, f"Successfully created file '{plugin_path}'."))
|
255
|
+
try:
|
256
|
+
_ = prompt(
|
257
|
+
f"Press [Enter] to edit plugin '{plugin_name}',"
|
258
|
+
+ " [CTRL+C] to skip.",
|
259
|
+
icon = False,
|
260
|
+
)
|
261
|
+
except (KeyboardInterrupt, Exception):
|
262
|
+
return True, "Success"
|
263
|
+
|
264
|
+
edit_file(plugin_path, debug=debug)
|
265
|
+
return True, "Success"
|
266
|
+
|
267
|
+
|
268
|
+
def _get_plugins_dir_path() -> pathlib.Path:
|
269
|
+
from meerschaum.config.paths import PLUGINS_DIR_PATHS
|
270
|
+
|
271
|
+
if not PLUGINS_DIR_PATHS:
|
272
|
+
raise EnvironmentError("No plugin dir path could be found.")
|
273
|
+
|
274
|
+
if len(PLUGINS_DIR_PATHS) == 1:
|
275
|
+
return PLUGINS_DIR_PATHS[0]
|
276
|
+
|
277
|
+
return pathlib.Path(
|
278
|
+
choose(
|
279
|
+
"In which directory do you want to write your plugin?",
|
280
|
+
[path.as_posix() for path in PLUGINS_DIR_PATHS],
|
281
|
+
numeric = True,
|
282
|
+
multiple = False,
|
283
|
+
default = PLUGINS_DIR_PATHS[0].as_posix(),
|
284
|
+
)
|
285
|
+
)
|
286
|
+
|
287
|
+
|
288
|
+
def _ask_to_uninstall(plugin: mrsm.Plugin, **kwargs: Any) -> SuccessTuple:
|
289
|
+
from meerschaum._internal.entry import entry
|
290
|
+
warn(f"Plugin '{plugin}' is already installed!", stack=False)
|
291
|
+
uninstall_plugin = yes_no(
|
292
|
+
f"Do you want to first uninstall '{plugin}'?",
|
293
|
+
default = 'n',
|
294
|
+
**kwargs
|
295
|
+
)
|
296
|
+
if not uninstall_plugin:
|
297
|
+
return False, f"Plugin '{plugin}' already exists."
|
298
|
+
|
299
|
+
return entry(['uninstall', 'plugin', plugin.name, '-f'])
|
300
|
+
|
301
|
+
|
302
|
+
def _get_action_name() -> str:
|
303
|
+
while True:
|
304
|
+
try:
|
305
|
+
action_name = prompt(
|
306
|
+
"What is name of your action?\n "
|
307
|
+
+ "(separate subactions with spaces, e.g. `sing song`):"
|
308
|
+
).replace(' ', '_')
|
309
|
+
except KeyboardInterrupt:
|
310
|
+
return False, "Aborted plugin creation."
|
311
|
+
|
312
|
+
if action_name:
|
313
|
+
break
|
314
|
+
warn("Please enter an action.", stack=False)
|
315
|
+
return action_name
|
316
|
+
|
317
|
+
|
318
|
+
def _get_quoted_dt_col_name() -> str:
|
319
|
+
try:
|
320
|
+
dt_col_name = prompt(
|
321
|
+
"Enter the datetime column name ([CTRL+C] to skip):"
|
322
|
+
)
|
323
|
+
except (Exception, KeyboardInterrupt):
|
324
|
+
dt_col_name = None
|
325
|
+
|
326
|
+
if dt_col_name is None:
|
327
|
+
dt_col_name = 'None'
|
328
|
+
elif '"' in dt_col_name or "'" in dt_col_name:
|
329
|
+
dt_col_name = f"\"\"\"{dt_col_name}\"\"\""
|
330
|
+
else:
|
331
|
+
dt_col_name = f"\"{dt_col_name}\""
|
332
|
+
|
333
|
+
return dt_col_name
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
10
10
|
import platform
|
11
11
|
import os
|
12
12
|
import sys
|
13
|
-
from meerschaum.utils.typing import Optional, Union, Any
|
13
|
+
from meerschaum.utils.typing import Optional, Union, Any, Dict
|
14
14
|
from meerschaum.utils.formatting._shell import make_header
|
15
15
|
from meerschaum.utils.formatting._pprint import pprint
|
16
16
|
from meerschaum.utils.formatting._pipes import (
|
@@ -298,6 +298,7 @@ def print_options(
|
|
298
298
|
header: Optional[str] = None,
|
299
299
|
num_cols: Optional[int] = None,
|
300
300
|
adjust_cols: bool = True,
|
301
|
+
sort_options: bool = False,
|
301
302
|
**kw
|
302
303
|
) -> None:
|
303
304
|
"""
|
@@ -339,6 +340,8 @@ def print_options(
|
|
339
340
|
_options = []
|
340
341
|
for o in options:
|
341
342
|
_options.append(str(o))
|
343
|
+
if sort_options:
|
344
|
+
_options = sorted(_options)
|
342
345
|
_header = f"Available {name}" if header is None else header
|
343
346
|
|
344
347
|
if num_cols is None:
|
@@ -349,7 +352,7 @@ def print_options(
|
|
349
352
|
print()
|
350
353
|
print(make_header(_header))
|
351
354
|
### print actions
|
352
|
-
for option in
|
355
|
+
for option in _options:
|
353
356
|
if not nopretty:
|
354
357
|
print(" - ", end="")
|
355
358
|
print(option)
|
@@ -385,7 +388,7 @@ def print_options(
|
|
385
388
|
|
386
389
|
if _header is not None:
|
387
390
|
table = Table(
|
388
|
-
title = '\n' + _header,
|
391
|
+
title = ('\n' + _header) if header else header,
|
389
392
|
box = box.SIMPLE,
|
390
393
|
show_header = False,
|
391
394
|
show_footer = False,
|
@@ -397,13 +400,22 @@ def print_options(
|
|
397
400
|
for i in range(num_cols):
|
398
401
|
table.add_column()
|
399
402
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
403
|
+
if len(_options) < 12:
|
404
|
+
# If fewer than 12 items, use a single column
|
405
|
+
for option in _options:
|
406
|
+
table.add_row(Text.from_ansi(highlight_pipes(option)))
|
407
|
+
else:
|
408
|
+
# Otherwise, use multiple columns as before
|
409
|
+
num_rows = (len(_options) + num_cols - 1) // num_cols
|
410
|
+
for i in range(num_rows):
|
411
|
+
row = []
|
412
|
+
for j in range(num_cols):
|
413
|
+
index = i + j * num_rows
|
414
|
+
if index < len(_options):
|
415
|
+
row.append(Text.from_ansi(highlight_pipes(_options[index])))
|
416
|
+
else:
|
417
|
+
row.append('')
|
418
|
+
table.add_row(*row)
|
407
419
|
|
408
420
|
get_console().print(table)
|
409
421
|
return None
|
meerschaum/utils/prompt.py
CHANGED
@@ -252,6 +252,7 @@ def choose(
|
|
252
252
|
"""
|
253
253
|
from meerschaum.utils.warnings import warn as _warn
|
254
254
|
from meerschaum.utils.packages import attempt_import
|
255
|
+
from meerschaum.utils.misc import print_options
|
255
256
|
noask = check_noask(noask)
|
256
257
|
|
257
258
|
### Handle empty choices.
|
@@ -333,6 +334,7 @@ def choose(
|
|
333
334
|
choices_indices[i] = new_c
|
334
335
|
default = delimiter.join(default) if isinstance(default, list) else default
|
335
336
|
|
337
|
+
question_options = []
|
336
338
|
if numeric:
|
337
339
|
_choices = [str(i + 1) for i, c in enumerate(choices)]
|
338
340
|
_default = ''
|
@@ -354,16 +356,20 @@ def choose(
|
|
354
356
|
_d = str(choices.index(d) + 1)
|
355
357
|
_default += _d + delimiter
|
356
358
|
_default = _default[:-1 * len(delimiter)]
|
357
|
-
question += '\n'
|
359
|
+
# question += '\n'
|
358
360
|
choices_digits = len(str(len(choices)))
|
359
361
|
for i, c in enumerate(choices_indices.values()):
|
360
|
-
|
362
|
+
question_options.append(
|
363
|
+
f" {i + 1}. "
|
364
|
+
+ (" " * (choices_digits - len(str(i + 1))))
|
365
|
+
+ f"{c}\n"
|
366
|
+
)
|
361
367
|
default_tuple = (_default, default) if default is not None else None
|
362
368
|
else:
|
363
369
|
default_tuple = default
|
364
|
-
question += '\n'
|
370
|
+
# question += '\n'
|
365
371
|
for c in choices_indices.values():
|
366
|
-
|
372
|
+
question_options.append(f"{c}\n")
|
367
373
|
|
368
374
|
if 'completer' not in kw:
|
369
375
|
WordCompleter = attempt_import('prompt_toolkit.completion').WordCompleter
|
@@ -371,6 +377,7 @@ def choose(
|
|
371
377
|
|
372
378
|
valid = False
|
373
379
|
while not valid:
|
380
|
+
print_options(question_options, header='')
|
374
381
|
answer = prompt(
|
375
382
|
question,
|
376
383
|
icon = icon,
|
@@ -3,8 +3,8 @@ meerschaum/__main__.py,sha256=Q43yra6APe5CdhDp9ngaorUjs8ZoabeYnMa6C5kQchA,2763
|
|
3
3
|
meerschaum/_internal/__init__.py,sha256=ilC7utfKtin7GAvuN34fKyUQYfPyqH0Mm3MJF5iyEf4,169
|
4
4
|
meerschaum/_internal/entry.py,sha256=TNqt79kfNgXH-7Pi75Jus4Osi9y776ZVptFuvrs4wWY,5680
|
5
5
|
meerschaum/_internal/arguments/__init__.py,sha256=HFciFQgo2ZOT19Mo6CpLhPYlpLYh2sNn1C9Lo7NMADc,519
|
6
|
-
meerschaum/_internal/arguments/_parse_arguments.py,sha256=
|
7
|
-
meerschaum/_internal/arguments/_parser.py,sha256=
|
6
|
+
meerschaum/_internal/arguments/_parse_arguments.py,sha256=ZPkJamB6noJAEpG_cyZGVYu6hXxtQ7H7c-j7gq3Csi8,10405
|
7
|
+
meerschaum/_internal/arguments/_parser.py,sha256=9PsfyiqQHpmZPKRryCti8qdUCSKD_ncBZ26iVgcOdzE,13796
|
8
8
|
meerschaum/_internal/docs/__init__.py,sha256=ZQYHWo6n0kfLLkyG36YXqTYvv2Pc7it5HZHMylT6cBA,126
|
9
9
|
meerschaum/_internal/docs/index.py,sha256=iWMe1rOVKvaP84q0tEzqwy-Dtgojg9cFmBntgPQBHu0,7076
|
10
10
|
meerschaum/_internal/gui/__init__.py,sha256=KF6Opae0aBOjIndMZ2txoPs7ozCXRlR-lcTsicLO7fc,1313
|
@@ -12,7 +12,7 @@ meerschaum/_internal/gui/app/__init__.py,sha256=rKUa8hHk6Fai-PDF61tQcpT1myxKcfmv
|
|
12
12
|
meerschaum/_internal/gui/app/_windows.py,sha256=-VHdjTzA3V596fVqnbmTxemONSp_80-sTNJ0CTB8FwU,2632
|
13
13
|
meerschaum/_internal/gui/app/actions.py,sha256=rx37qXf3uoa7Ou0n1cISqNFZNL0nr4wO7vSUmWO8f2E,935
|
14
14
|
meerschaum/_internal/gui/app/pipes.py,sha256=4nAQ0rrHb_2bNgDF0Ru2YlbPaCDDzAl5beOGU4Af-4A,1596
|
15
|
-
meerschaum/_internal/shell/Shell.py,sha256=
|
15
|
+
meerschaum/_internal/shell/Shell.py,sha256=JgxEg4gnxUS8R8HdFZ4k49KXvTGoy3dRQcEi4dmjw9I,33111
|
16
16
|
meerschaum/_internal/shell/ShellCompleter.py,sha256=bbG-mExNXO4pltWBOXdbMp8P2wLgy8_BgipIr5aGp5s,3114
|
17
17
|
meerschaum/_internal/shell/ValidAutoSuggest.py,sha256=bARjOWMidz0dvMelLUe6yRPto5l3gcEHYHqFDjoh22I,1280
|
18
18
|
meerschaum/_internal/shell/__init__.py,sha256=vXQoQPEVlYiUYai1b5AwQAlTnja6A2cSABnqXhzlS7I,281
|
@@ -23,13 +23,13 @@ meerschaum/_internal/term/tools.py,sha256=dXVAimKD-Yv2fg2WOTr0YGBY7XDKjQqw-RizcS
|
|
23
23
|
meerschaum/actions/__init__.py,sha256=ZUdQk6FvuMqyEvLCP-RiDDlIK4NwkqLRgFZSKq04qq4,11440
|
24
24
|
meerschaum/actions/api.py,sha256=mWhv4bn3Ap17_Gqf2Cx9bAsHKG-Zhy072pBbNzHLEJc,12756
|
25
25
|
meerschaum/actions/backup.py,sha256=MhdNEo7ptOdFpR-L0o9Z590hBmKeqHsSx64GPKhx9e8,1230
|
26
|
-
meerschaum/actions/bootstrap.py,sha256=
|
26
|
+
meerschaum/actions/bootstrap.py,sha256=Tsv3bL63mb6zDSCpxl3Mq05YulwbDTGNNZr3ttVmksA,14119
|
27
27
|
meerschaum/actions/clear.py,sha256=OoFZE0bK5m8s3GLNZcixuVT0DMj1izXVxGCATcmUGbI,4851
|
28
28
|
meerschaum/actions/copy.py,sha256=8g3ANXfVdvuyaoXcZjgTg3BxHTOhHGrzVDOOsTBrpSU,6213
|
29
29
|
meerschaum/actions/deduplicate.py,sha256=puYyxeFYEUy1Sd2IOcZB2e6MrNxAZl2bTLmNzFDkCiw,1167
|
30
30
|
meerschaum/actions/delete.py,sha256=RDkIQEnnN8t52dMAJpxoQ7LN-pzH7UAfGF8yT5oNiIw,17325
|
31
31
|
meerschaum/actions/drop.py,sha256=Hd5h4rrWd7qL2rTqglsTonUsEoH7qQlsfqNFSHGeqr0,2453
|
32
|
-
meerschaum/actions/edit.py,sha256=
|
32
|
+
meerschaum/actions/edit.py,sha256=93_mlZhPfiErs9TJ3_Xf9KYxIopaR86nQXJlZsKNNok,11752
|
33
33
|
meerschaum/actions/install.py,sha256=akzzgsvy5yqUFuUqzSMG4eBKARY2iSnL3n_BiaNcM58,7431
|
34
34
|
meerschaum/actions/login.py,sha256=fNgsgkrFCn9wBQJY50SQhz2PwsN_TvEYYHnXK3JG4ig,4206
|
35
35
|
meerschaum/actions/os.py,sha256=dtoppoBhLzW3rLNF0SFovEfNxA4WJWt_9WrOGlS5KbA,2251
|
@@ -46,7 +46,7 @@ meerschaum/actions/start.py,sha256=9Ej3Hk7qXfbrBaQq17KirTII_4Pa-BWSdrkutMnLA3k,1
|
|
46
46
|
meerschaum/actions/stop.py,sha256=KTBadAmJ6SbReqlltkwfqZW6EryB4kZXupl0ZyInI0Q,4311
|
47
47
|
meerschaum/actions/sync.py,sha256=10uPREu3HBVgtzakVxhCegQOz_mistABJlsNNCMgywY,17518
|
48
48
|
meerschaum/actions/tag.py,sha256=SJf5qFW0ccLXjqlTdkK_0MCcrCMdg6xhYrhKdco0hdA,3053
|
49
|
-
meerschaum/actions/uninstall.py,sha256=
|
49
|
+
meerschaum/actions/uninstall.py,sha256=tBXhdXggSieGEQe4EPGxpgMK0MZTJCweNvAJ9-59El0,5776
|
50
50
|
meerschaum/actions/upgrade.py,sha256=wepYdvrjSuc2wMd21rbLoxGjlRuXxLVH0GOD9OhKB48,6658
|
51
51
|
meerschaum/actions/verify.py,sha256=tY5slGpHiWiE0v9TDnjbmxSKn86zBnu9WBpixUgKNQU,4885
|
52
52
|
meerschaum/api/__init__.py,sha256=oOYwNnkXM2s-h52EYnN2NGPfrlaQh6D4-zmHa7uPLG0,7450
|
@@ -124,7 +124,7 @@ meerschaum/api/routes/_users.py,sha256=SfAkZFKrKnGjpzj8SFIKzPemzQJOH3oB72h19EaUv
|
|
124
124
|
meerschaum/api/routes/_version.py,sha256=2t-nw_9IxCVZCNEar0LOwmut2zsClRVHjiOOUx16cu0,825
|
125
125
|
meerschaum/api/routes/_webterm.py,sha256=7eilgDXckpEc2LyeNmJS5YO6HxlyMkwPnAMWd7eMfJM,3909
|
126
126
|
meerschaum/api/tables/__init__.py,sha256=e2aNC0CdlWICTUMx1i9RauF8Pm426J0RZJbsJWv4SWo,482
|
127
|
-
meerschaum/config/__init__.py,sha256=
|
127
|
+
meerschaum/config/__init__.py,sha256=xNEps5IG0b1TrllYdG5GZ_x93sR8b6KlX9sUVdTugDs,11542
|
128
128
|
meerschaum/config/_dash.py,sha256=BJHl4xMrQB-YHUEU7ldEW8q_nOPoIRSOqLrfGElc6Dw,187
|
129
129
|
meerschaum/config/_default.py,sha256=J6AWxxXM4mntCdkM6bKIpyQznZ5NuMICmTaurF11J9Q,5275
|
130
130
|
meerschaum/config/_edit.py,sha256=_kabgFbJdI5kcLs-JIsoaTo0JdyxnPnBdrlTyTAgPm8,8236
|
@@ -137,7 +137,7 @@ meerschaum/config/_preprocess.py,sha256=-AEA8m_--KivZwTQ1sWN6LTn5sio_fUr2XZ51BO6
|
|
137
137
|
meerschaum/config/_read_config.py,sha256=WFZKIXZMDe_ca0ES7ivgM_mnwShvFxLdoeisT_X5-h0,14720
|
138
138
|
meerschaum/config/_shell.py,sha256=s74cmJl8NrhM_Y1cB_P41_JDUYXV0g4WXnKFZWMtnrY,3551
|
139
139
|
meerschaum/config/_sync.py,sha256=oK2ZujO2T1he08BXCFyiniBUevNGWSQKXLcS_jRv_7Y,4155
|
140
|
-
meerschaum/config/_version.py,sha256=
|
140
|
+
meerschaum/config/_version.py,sha256=EYhjKU-_lntkfeba7JixXzvd1fRvaGeo4UJv29kVR0E,76
|
141
141
|
meerschaum/config/paths.py,sha256=Z7vaOunaEJbVFXiSSz4IthhNOQDI-dhtpi5TpSyrcXg,206
|
142
142
|
meerschaum/config/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
143
143
|
meerschaum/config/stack/__init__.py,sha256=Yt7GNzC_hz7iUDZ4gVho_lugJO2DnXgnMtsMG_ReoRg,9114
|
@@ -188,16 +188,17 @@ meerschaum/core/Pipe/_delete.py,sha256=1geNp9BgrocXP1gt76dMbnlJWKYFMuSNqPFA4K4-h
|
|
188
188
|
meerschaum/core/Pipe/_drop.py,sha256=uf3MvMkCw9tVfJ2fuo8LqZ4vvMNa3xC3YoFGEuc-hH8,1052
|
189
189
|
meerschaum/core/Pipe/_dtypes.py,sha256=NcfVMJPyyA1VzIJOnPhyL36YTt2IXMRqQy4ZRDySSqg,3694
|
190
190
|
meerschaum/core/Pipe/_edit.py,sha256=ZH2A0ZOpZKsVDnQxKzmXspNQKTEFUhkkZDjwOkmWtaY,8471
|
191
|
-
meerschaum/core/Pipe/_fetch.py,sha256=
|
191
|
+
meerschaum/core/Pipe/_fetch.py,sha256=lhumdeaXBrKRqBO-I5PVbgsxjcUJh0qd7pU1MPL4ExY,5367
|
192
192
|
meerschaum/core/Pipe/_register.py,sha256=Sd5xaAW8H7uLTIoommcKb-6kHPRuHJLWNSbPnt2UbvA,2240
|
193
193
|
meerschaum/core/Pipe/_show.py,sha256=nG50y8eBT9TVuKkRgAKtNDNIxysJvMNxfu__lkL1F9k,1352
|
194
|
-
meerschaum/core/Pipe/_sync.py,sha256=
|
194
|
+
meerschaum/core/Pipe/_sync.py,sha256=tDlg0tDHgZ-yQhVIoJLnQZxFykCbr8dOUxqhiwZ9pRk,28935
|
195
195
|
meerschaum/core/Pipe/_verify.py,sha256=KSnthUzImRLjt9fxyBaLvArqDuOLRpKBfk0tnseJClc,14262
|
196
196
|
meerschaum/core/Plugin/__init__.py,sha256=UXg64EvJPgI1PCxkY_KM02-ZmBm4FZpLPIQR_uSJJDc,137
|
197
197
|
meerschaum/core/User/_User.py,sha256=CApB7Y0QJL6S9QOCCfrG4SbPuPXJ9AsAYQ5pASMP_Aw,6527
|
198
198
|
meerschaum/core/User/__init__.py,sha256=lJ7beIZTG9sO4dAi3367fFBl17dXYEWHKi7HoaPlDyk,193
|
199
199
|
meerschaum/plugins/_Plugin.py,sha256=LpplVPviSskKqf_igl4yIsD72H2C9vaFPQgU7-93ytg,34039
|
200
200
|
meerschaum/plugins/__init__.py,sha256=RUnkBTvusySyp4rvVRbtqoV2lKCdKeu0uxExB5Fg7KM,23503
|
201
|
+
meerschaum/plugins/bootstrap.py,sha256=qg9MQ1YAU8ShwGqWDl38WjiXLIxDPl95pSIGDLN9rOw,11423
|
201
202
|
meerschaum/utils/__init__.py,sha256=QrK1K9hIbPCRCM5k2nZGFqGnrqhA0Eh-iSmCU7FG6Cs,612
|
202
203
|
meerschaum/utils/_get_pipes.py,sha256=dlPckpYYyM0IwRZ2VL0u9DiEeYhr5Ho9gkzvWxzNVwI,11460
|
203
204
|
meerschaum/utils/dataframe.py,sha256=vxZ72ME7IWuadtktgjFZF5bc9fXW_0TuynjFlJljlLU,31955
|
@@ -207,7 +208,7 @@ meerschaum/utils/misc.py,sha256=2_FyirImT793NH-wQriJ1VPOW7DcXm98Id0XMn8nh9I,4344
|
|
207
208
|
meerschaum/utils/networking.py,sha256=Sr_eYUGW8_UV9-k9LqRFf7xLtbUcsDucODyLCRsFRUc,1006
|
208
209
|
meerschaum/utils/pool.py,sha256=vkE42af4fjrTEJTxf6Ek3xGucm1MtEkpsSEiaVzNKHs,2655
|
209
210
|
meerschaum/utils/process.py,sha256=UyiNszYXdnjF6WN8Tt0NchWjkCV10MbOXEFn_TAhXeg,7510
|
210
|
-
meerschaum/utils/prompt.py,sha256=
|
211
|
+
meerschaum/utils/prompt.py,sha256=HG5pPZBsxwE-R3kRJqbOrl38Y7IHNZQuLPdU7dgqlBY,18524
|
211
212
|
meerschaum/utils/schedule.py,sha256=btAeSDaoFH62-7wTO0U7NK9P9QHV46PtY3DJ8DN_mCY,10860
|
212
213
|
meerschaum/utils/sql.py,sha256=4sCNEpgUd6uFz6ySs4nnUMVaOT0YAvPM1ZlQYJTSF-0,46656
|
213
214
|
meerschaum/utils/threading.py,sha256=3N8JXPAnwqJiSjuQcbbJg3Rv9-CCUMJpeQRfKFR7MaA,2489
|
@@ -221,7 +222,7 @@ meerschaum/utils/daemon/__init__.py,sha256=I_ki51yml4vsh9OoH7BWTaz9SnATD8qM0i0fN
|
|
221
222
|
meerschaum/utils/daemon/_names.py,sha256=Prf7xA2GWDbKR_9Xq9_5RTTIf9GNWY3Yt0s4tEU3JgM,4330
|
222
223
|
meerschaum/utils/dtypes/__init__.py,sha256=JR9PViJTzhukZhq0QoPIs73HOnXZZr8OmfhAAD4OAUA,6261
|
223
224
|
meerschaum/utils/dtypes/sql.py,sha256=IkEOyB63je-rCLHM6WwFzGbCerYk1zobL1cXkWqmTa4,14638
|
224
|
-
meerschaum/utils/formatting/__init__.py,sha256=
|
225
|
+
meerschaum/utils/formatting/__init__.py,sha256=zIJAEVdYw6ldI0TKx5vdgryYfmZqGNrO0_oeZrx5S4k,14350
|
225
226
|
meerschaum/utils/formatting/_jobs.py,sha256=s1lVcdMkzNj5Bqw-GsUhcguUFtahi5nQ-kg1fbp0Idw,3294
|
226
227
|
meerschaum/utils/formatting/_pipes.py,sha256=wy0iWJFsFl3X2VloaiA_gp9Yx9w6tD3FQZvAQAqef4A,19492
|
227
228
|
meerschaum/utils/formatting/_pprint.py,sha256=tgrT3FyGyu5CWJYysqK3kX1xdZYorlbOk9fcU_vt9Qg,3096
|
@@ -231,11 +232,11 @@ meerschaum/utils/packages/_packages.py,sha256=gWrco46rqKjtAI714aJp0XfzYQFAdNi08K
|
|
231
232
|
meerschaum/utils/packages/lazy_loader.py,sha256=VHnph3VozH29R4JnSSBfwtA5WKZYZQFT_GeQSShCnuc,2540
|
232
233
|
meerschaum/utils/venv/_Venv.py,sha256=sBnlmxHdAh2bx8btfVoD79-H9-cYsv5lP02IIXkyECs,3553
|
233
234
|
meerschaum/utils/venv/__init__.py,sha256=4vFAu85lQ5GYEVhc6e_KhFmrks4t_Ma6ysmtraccYbs,24187
|
234
|
-
meerschaum-2.2.5.
|
235
|
-
meerschaum-2.2.5.
|
236
|
-
meerschaum-2.2.5.
|
237
|
-
meerschaum-2.2.5.
|
238
|
-
meerschaum-2.2.5.
|
239
|
-
meerschaum-2.2.5.
|
240
|
-
meerschaum-2.2.5.
|
241
|
-
meerschaum-2.2.5.
|
235
|
+
meerschaum-2.2.5.dev2.dist-info/LICENSE,sha256=jG2zQEdRNt88EgHUWPpXVWmOrOduUQRx7MnYV9YIPaw,11359
|
236
|
+
meerschaum-2.2.5.dev2.dist-info/METADATA,sha256=QSbWuB3P7CVf1sqjJMqt00hWQo1idl5YoOwHSAdXTok,24192
|
237
|
+
meerschaum-2.2.5.dev2.dist-info/NOTICE,sha256=OTA9Fcthjf5BRvWDDIcBC_xfLpeDV-RPZh3M-HQBRtQ,114
|
238
|
+
meerschaum-2.2.5.dev2.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
239
|
+
meerschaum-2.2.5.dev2.dist-info/entry_points.txt,sha256=5YBVzibw-0rNA_1VjB16z5GABsOGf-CDhW4yqH8C7Gc,88
|
240
|
+
meerschaum-2.2.5.dev2.dist-info/top_level.txt,sha256=bNoSiDj0El6buocix-FRoAtJOeq1qOF5rRm2u9i7Q6A,11
|
241
|
+
meerschaum-2.2.5.dev2.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
242
|
+
meerschaum-2.2.5.dev2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|