meerschaum 2.7.5__py3-none-any.whl → 2.7.7__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 +4 -6
- meerschaum/_internal/shell/ShellCompleter.py +6 -5
- meerschaum/actions/clear.py +6 -3
- meerschaum/actions/copy.py +33 -27
- meerschaum/actions/drop.py +100 -22
- meerschaum/actions/index.py +71 -0
- meerschaum/actions/register.py +8 -12
- meerschaum/actions/sql.py +1 -1
- meerschaum/actions/sync.py +22 -18
- meerschaum/api/dash/pipes.py +2 -3
- meerschaum/api/routes/_pipes.py +18 -0
- meerschaum/api/routes/_plugins.py +1 -1
- meerschaum/api/routes/_users.py +62 -61
- meerschaum/config/_default.py +5 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/api/_misc.py +3 -2
- meerschaum/connectors/api/_pipes.py +28 -9
- meerschaum/connectors/sql/_SQLConnector.py +7 -3
- meerschaum/connectors/sql/_create_engine.py +1 -1
- meerschaum/connectors/sql/_fetch.py +4 -9
- meerschaum/connectors/sql/_instance.py +3 -3
- meerschaum/connectors/sql/_pipes.py +292 -76
- meerschaum/connectors/sql/_plugins.py +11 -16
- meerschaum/connectors/sql/_sql.py +13 -9
- meerschaum/connectors/sql/_uri.py +9 -9
- meerschaum/connectors/sql/_users.py +10 -12
- meerschaum/connectors/sql/tables/__init__.py +13 -14
- meerschaum/core/Pipe/__init__.py +12 -2
- meerschaum/core/Pipe/_attributes.py +32 -38
- meerschaum/core/Pipe/_drop.py +73 -2
- meerschaum/core/Pipe/_index.py +68 -0
- meerschaum/jobs/_Job.py +1 -0
- meerschaum/plugins/__init__.py +7 -3
- meerschaum/utils/daemon/Daemon.py +5 -1
- meerschaum/utils/daemon/__init__.py +2 -2
- meerschaum/utils/dtypes/sql.py +2 -2
- meerschaum/utils/misc.py +7 -6
- meerschaum/utils/packages/__init__.py +31 -27
- meerschaum/utils/packages/_packages.py +1 -1
- meerschaum/utils/prompt.py +54 -36
- meerschaum/utils/sql.py +80 -34
- meerschaum/utils/venv/__init__.py +12 -3
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/METADATA +17 -5
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/RECORD +50 -48
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/WHEEL +1 -1
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/LICENSE +0 -0
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/NOTICE +0 -0
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/top_level.txt +0 -0
- {meerschaum-2.7.5.dist-info → meerschaum-2.7.7.dist-info}/zip-safe +0 -0
meerschaum/jobs/_Job.py
CHANGED
meerschaum/plugins/__init__.py
CHANGED
@@ -126,8 +126,8 @@ def pre_sync_hook(
|
|
126
126
|
|
127
127
|
|
128
128
|
def post_sync_hook(
|
129
|
-
|
130
|
-
|
129
|
+
function: Callable[[Any], Any],
|
130
|
+
) -> Callable[[Any], Any]:
|
131
131
|
"""
|
132
132
|
Register a function as a sync hook to be executed upon completion of a sync.
|
133
133
|
|
@@ -143,10 +143,14 @@ def post_sync_hook(
|
|
143
143
|
Examples
|
144
144
|
--------
|
145
145
|
>>> from meerschaum.plugins import post_sync_hook
|
146
|
+
>>> from meerschaum.utils.misc import interval_str
|
147
|
+
>>> from datetime import timedelta
|
146
148
|
>>>
|
147
149
|
>>> @post_sync_hook
|
148
150
|
... def log_sync(pipe, success_tuple, duration=None, **kwargs):
|
149
|
-
...
|
151
|
+
... duration_delta = timedelta(seconds=duration)
|
152
|
+
... duration_text = interval_str(duration_delta)
|
153
|
+
... print(f"It took {duration_text} to sync {pipe}.")
|
150
154
|
>>>
|
151
155
|
"""
|
152
156
|
with _locks['_post_sync_hooks']:
|
@@ -1017,7 +1017,8 @@ class Daemon:
|
|
1017
1017
|
|
1018
1018
|
def read_pickle(self) -> Daemon:
|
1019
1019
|
"""Read a Daemon's pickle file and return the `Daemon`."""
|
1020
|
-
import pickle
|
1020
|
+
import pickle
|
1021
|
+
import traceback
|
1021
1022
|
if not self.pickle_path.exists():
|
1022
1023
|
error(f"Pickle file does not exist for daemon '{self.daemon_id}'.")
|
1023
1024
|
|
@@ -1053,6 +1054,9 @@ class Daemon:
|
|
1053
1054
|
if self._properties is None:
|
1054
1055
|
self._properties = {}
|
1055
1056
|
|
1057
|
+
if self._properties.get('result', None) is None:
|
1058
|
+
_ = self._properties.pop('result', None)
|
1059
|
+
|
1056
1060
|
if _file_properties is not None:
|
1057
1061
|
self._properties = apply_patch_to_config(
|
1058
1062
|
_file_properties,
|
@@ -37,7 +37,7 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
|
37
37
|
filtered_sysargs = [arg for arg in sysargs if arg not in ('-d', '--daemon')]
|
38
38
|
try:
|
39
39
|
label = shlex.join(filtered_sysargs) if sysargs else None
|
40
|
-
except Exception
|
40
|
+
except Exception:
|
41
41
|
label = ' '.join(filtered_sysargs) if sysargs else None
|
42
42
|
|
43
43
|
name = _args.get('name', None)
|
@@ -45,7 +45,7 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
|
45
45
|
if name:
|
46
46
|
try:
|
47
47
|
daemon = Daemon(daemon_id=name)
|
48
|
-
except Exception
|
48
|
+
except Exception:
|
49
49
|
daemon = None
|
50
50
|
|
51
51
|
if daemon is not None:
|
meerschaum/utils/dtypes/sql.py
CHANGED
@@ -536,7 +536,7 @@ def get_db_type_from_pd_type(
|
|
536
536
|
from meerschaum.utils.packages import attempt_import
|
537
537
|
from meerschaum.utils.dtypes import are_dtypes_equal, MRSM_ALIAS_DTYPES
|
538
538
|
from meerschaum.utils.misc import parse_arguments_str
|
539
|
-
sqlalchemy_types = attempt_import('sqlalchemy.types')
|
539
|
+
sqlalchemy_types = attempt_import('sqlalchemy.types', lazy=False)
|
540
540
|
|
541
541
|
types_registry = (
|
542
542
|
PD_TO_DB_DTYPES_FLAVORS
|
@@ -559,7 +559,7 @@ def get_db_type_from_pd_type(
|
|
559
559
|
found_db_type = True
|
560
560
|
|
561
561
|
if not found_db_type:
|
562
|
-
warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.")
|
562
|
+
warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.", stacklevel=3)
|
563
563
|
return (
|
564
564
|
'TEXT'
|
565
565
|
if not as_sqlalchemy
|
meerschaum/utils/misc.py
CHANGED
@@ -90,20 +90,21 @@ def add_method_to_class(
|
|
90
90
|
|
91
91
|
|
92
92
|
def generate_password(length: int = 12) -> str:
|
93
|
-
"""
|
93
|
+
"""
|
94
|
+
Generate a secure password of given length.
|
94
95
|
|
95
96
|
Parameters
|
96
97
|
----------
|
97
|
-
length
|
98
|
+
length: int, default 12
|
98
99
|
The length of the password.
|
99
100
|
|
100
101
|
Returns
|
101
102
|
-------
|
102
103
|
A random password string.
|
103
|
-
|
104
104
|
"""
|
105
|
-
import secrets
|
106
|
-
|
105
|
+
import secrets
|
106
|
+
import string
|
107
|
+
return ''.join((secrets.choice(string.ascii_letters + string.digits) for i in range(length)))
|
107
108
|
|
108
109
|
def is_int(s : str) -> bool:
|
109
110
|
"""
|
@@ -121,7 +122,7 @@ def is_int(s : str) -> bool:
|
|
121
122
|
"""
|
122
123
|
try:
|
123
124
|
float(s)
|
124
|
-
except Exception
|
125
|
+
except Exception:
|
125
126
|
return False
|
126
127
|
|
127
128
|
return float(s).is_integer()
|
@@ -337,14 +337,14 @@ def get_install_no_version(install_name: str) -> str:
|
|
337
337
|
|
338
338
|
import_versions = {}
|
339
339
|
def determine_version(
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
340
|
+
path: pathlib.Path,
|
341
|
+
import_name: Optional[str] = None,
|
342
|
+
venv: Optional[str] = 'mrsm',
|
343
|
+
search_for_metadata: bool = True,
|
344
|
+
split: bool = True,
|
345
|
+
warn: bool = False,
|
346
|
+
debug: bool = False,
|
347
|
+
) -> Union[str, None]:
|
348
348
|
"""
|
349
349
|
Determine a module's `__version__` string from its filepath.
|
350
350
|
|
@@ -381,11 +381,8 @@ def determine_version(
|
|
381
381
|
with _locks['import_versions']:
|
382
382
|
if venv not in import_versions:
|
383
383
|
import_versions[venv] = {}
|
384
|
-
import
|
385
|
-
import re, os
|
384
|
+
import os
|
386
385
|
old_cwd = os.getcwd()
|
387
|
-
if debug:
|
388
|
-
from meerschaum.utils.debug import dprint
|
389
386
|
from meerschaum.utils.warnings import warn as warn_function
|
390
387
|
if import_name is None:
|
391
388
|
import_name = path.parent.stem if path.stem == '__init__' else path.stem
|
@@ -395,7 +392,10 @@ def determine_version(
|
|
395
392
|
_version = None
|
396
393
|
module_parent_dir = (
|
397
394
|
path.parent.parent if path.stem == '__init__' else path.parent
|
398
|
-
) if path is not None else venv_target_path(venv, debug=debug)
|
395
|
+
) if path is not None else venv_target_path(venv, allow_nonexistent=True, debug=debug)
|
396
|
+
|
397
|
+
if not module_parent_dir.exists():
|
398
|
+
return None
|
399
399
|
|
400
400
|
installed_dir_name = _import_to_dir_name(import_name)
|
401
401
|
clean_installed_dir_name = installed_dir_name.lower().replace('-', '_')
|
@@ -403,7 +403,11 @@ def determine_version(
|
|
403
403
|
### First, check if a dist-info directory exists.
|
404
404
|
_found_versions = []
|
405
405
|
if search_for_metadata:
|
406
|
-
|
406
|
+
try:
|
407
|
+
filenames = os.listdir(module_parent_dir)
|
408
|
+
except FileNotFoundError:
|
409
|
+
filenames = []
|
410
|
+
for filename in filenames:
|
407
411
|
if not filename.endswith('.dist-info'):
|
408
412
|
continue
|
409
413
|
filename_lower = filename.lower()
|
@@ -430,7 +434,7 @@ def determine_version(
|
|
430
434
|
try:
|
431
435
|
os.chdir(module_parent_dir)
|
432
436
|
_version = importlib_metadata.metadata(import_name)['Version']
|
433
|
-
except Exception
|
437
|
+
except Exception:
|
434
438
|
_version = None
|
435
439
|
finally:
|
436
440
|
os.chdir(old_cwd)
|
@@ -698,7 +702,7 @@ def need_update(
|
|
698
702
|
(not semver.Version.parse(version).match(required_version))
|
699
703
|
if required_version else False
|
700
704
|
)
|
701
|
-
except AttributeError
|
705
|
+
except AttributeError:
|
702
706
|
pip_install(_import_to_install_name('semver'), venv='mrsm', debug=debug)
|
703
707
|
semver = manually_import_module('semver', venv='mrsm', debug=debug)
|
704
708
|
return (
|
@@ -724,10 +728,10 @@ def need_update(
|
|
724
728
|
|
725
729
|
|
726
730
|
def get_pip(
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
+
venv: Optional[str] = 'mrsm',
|
732
|
+
color: bool = True,
|
733
|
+
debug: bool = False,
|
734
|
+
) -> bool:
|
731
735
|
"""
|
732
736
|
Download and run the get-pip.py script.
|
733
737
|
|
@@ -747,7 +751,8 @@ def get_pip(
|
|
747
751
|
A bool indicating success.
|
748
752
|
|
749
753
|
"""
|
750
|
-
import sys
|
754
|
+
import sys
|
755
|
+
import subprocess
|
751
756
|
from meerschaum.utils.misc import wget
|
752
757
|
from meerschaum.config._paths import CACHE_RESOURCES_PATH
|
753
758
|
from meerschaum.config.static import STATIC_CONFIG
|
@@ -755,7 +760,7 @@ def get_pip(
|
|
755
760
|
dest = CACHE_RESOURCES_PATH / 'get-pip.py'
|
756
761
|
try:
|
757
762
|
wget(url, dest, color=False, debug=debug)
|
758
|
-
except Exception
|
763
|
+
except Exception:
|
759
764
|
print(f"Failed to fetch pip from '{url}'. Please install pip and restart Meerschaum.")
|
760
765
|
sys.exit(1)
|
761
766
|
if venv is not None:
|
@@ -776,6 +781,7 @@ def pip_install(
|
|
776
781
|
_uninstall: bool = False,
|
777
782
|
_from_completely_uninstall: bool = False,
|
778
783
|
_install_uv_pip: bool = True,
|
784
|
+
_use_uv_pip: bool = True,
|
779
785
|
color: bool = True,
|
780
786
|
silent: bool = False,
|
781
787
|
debug: bool = False,
|
@@ -835,10 +841,7 @@ def pip_install(
|
|
835
841
|
from meerschaum.utils.warnings import warn
|
836
842
|
if args is None:
|
837
843
|
args = ['--upgrade'] if not _uninstall else []
|
838
|
-
if color
|
839
|
-
ANSI, UNICODE = True, True
|
840
|
-
else:
|
841
|
-
ANSI, UNICODE = False, False
|
844
|
+
ANSI = True if color else False
|
842
845
|
if check_wheel:
|
843
846
|
have_wheel = venv_contains_package('wheel', venv=venv, debug=debug)
|
844
847
|
|
@@ -877,7 +880,8 @@ def pip_install(
|
|
877
880
|
)
|
878
881
|
|
879
882
|
use_uv_pip = (
|
880
|
-
|
883
|
+
_use_uv_pip
|
884
|
+
and venv_contains_package('uv', venv=None, debug=debug)
|
881
885
|
and uv_bin is not None
|
882
886
|
and venv is not None
|
883
887
|
and is_uv_enabled()
|
@@ -136,7 +136,7 @@ packages['sql'] = {
|
|
136
136
|
'numpy' : 'numpy>=1.18.5',
|
137
137
|
'pandas' : 'pandas[parquet]>=2.0.1',
|
138
138
|
'pyarrow' : 'pyarrow>=16.1.0',
|
139
|
-
'dask' : 'dask[complete]>=2024.
|
139
|
+
'dask' : 'dask[complete]>=2024.12.1',
|
140
140
|
'partd' : 'partd>=1.4.2',
|
141
141
|
'pytz' : 'pytz',
|
142
142
|
'joblib' : 'joblib>=0.17.0',
|
meerschaum/utils/prompt.py
CHANGED
@@ -7,7 +7,9 @@ Functions for interacting with the user.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
10
11
|
import os
|
12
|
+
import meerschaum as mrsm
|
11
13
|
from meerschaum.utils.typing import Any, Union, Optional, Tuple, List
|
12
14
|
|
13
15
|
|
@@ -63,9 +65,8 @@ def prompt(
|
|
63
65
|
|
64
66
|
"""
|
65
67
|
from meerschaum.utils.packages import attempt_import
|
66
|
-
from meerschaum.utils.formatting import
|
68
|
+
from meerschaum.utils.formatting import ANSI, CHARSET, highlight_pipes, fill_ansi
|
67
69
|
from meerschaum.config import get_config
|
68
|
-
from meerschaum.config.static import _static_config
|
69
70
|
from meerschaum.utils.misc import filter_keywords
|
70
71
|
from meerschaum.utils.daemon import running_in_daemon
|
71
72
|
noask = check_noask(noask)
|
@@ -175,8 +176,6 @@ def yes_no(
|
|
175
176
|
```
|
176
177
|
"""
|
177
178
|
from meerschaum.utils.warnings import error, warn
|
178
|
-
from meerschaum.utils.formatting import ANSI, UNICODE
|
179
|
-
from meerschaum.utils.packages import attempt_import
|
180
179
|
|
181
180
|
default = options[0] if yes else default
|
182
181
|
noask = yes or check_noask(noask)
|
@@ -195,7 +194,7 @@ def yes_no(
|
|
195
194
|
success = False
|
196
195
|
|
197
196
|
if not success:
|
198
|
-
error(
|
197
|
+
error("Error getting response. Aborting...", stack=False)
|
199
198
|
if answer == "":
|
200
199
|
answer = default
|
201
200
|
|
@@ -205,19 +204,20 @@ def yes_no(
|
|
205
204
|
|
206
205
|
return answer.lower() == options[0].lower()
|
207
206
|
|
207
|
+
|
208
208
|
def choose(
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
209
|
+
question: str,
|
210
|
+
choices: List[Union[str, Tuple[str, str]]],
|
211
|
+
default: Union[str, List[str], None] = None,
|
212
|
+
numeric: bool = True,
|
213
|
+
multiple: bool = False,
|
214
|
+
as_indices: bool = False,
|
215
|
+
delimiter: str = ',',
|
216
|
+
icon: bool = True,
|
217
|
+
warn: bool = True,
|
218
|
+
noask: bool = False,
|
219
|
+
**kw
|
220
|
+
) -> Union[str, Tuple[str], None]:
|
221
221
|
"""
|
222
222
|
Present a list of options and return the user's choice.
|
223
223
|
|
@@ -418,8 +418,8 @@ def choose(
|
|
418
418
|
valid = (len(answers) > 1 or not (len(answers) == 1 and answers[0] is None))
|
419
419
|
for a in answers:
|
420
420
|
if (
|
421
|
-
not
|
422
|
-
and not
|
421
|
+
a not in {_original for _new, _original in altered_choices.items()}
|
422
|
+
and a not in _choices
|
423
423
|
and a != default
|
424
424
|
and not noask
|
425
425
|
):
|
@@ -428,21 +428,22 @@ def choose(
|
|
428
428
|
if valid:
|
429
429
|
break
|
430
430
|
if warn:
|
431
|
-
_warn(
|
431
|
+
_warn("Please pick a valid choice.", stack=False)
|
432
432
|
|
433
433
|
if not multiple:
|
434
434
|
if not numeric:
|
435
435
|
return answer
|
436
436
|
try:
|
437
437
|
_answer = choices[int(answer) - 1]
|
438
|
-
if as_indices and isinstance(
|
438
|
+
if as_indices and isinstance(_answer, tuple):
|
439
439
|
return _answer[0]
|
440
440
|
return _answer
|
441
|
-
except Exception
|
441
|
+
except Exception:
|
442
442
|
_warn(f"Could not cast answer '{answer}' to an integer.", stacklevel=3)
|
443
443
|
|
444
444
|
if not numeric:
|
445
445
|
return answers
|
446
|
+
|
446
447
|
_answers = []
|
447
448
|
for a in answers:
|
448
449
|
try:
|
@@ -451,17 +452,17 @@ def choose(
|
|
451
452
|
if isinstance(_answer_to_return, tuple) and as_indices:
|
452
453
|
_answer_to_return = _answer_to_return[0]
|
453
454
|
_answers.append(_answer_to_return)
|
454
|
-
except Exception
|
455
|
+
except Exception:
|
455
456
|
_warn(f"Could not cast answer '{a}' to an integer.", stacklevel=3)
|
456
457
|
return _answers
|
457
458
|
|
458
459
|
|
459
460
|
def get_password(
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
461
|
+
username: Optional[str] = None,
|
462
|
+
minimum_length: Optional[int] = None,
|
463
|
+
confirm: bool = True,
|
464
|
+
**kw: Any
|
465
|
+
) -> str:
|
465
466
|
"""
|
466
467
|
Prompt the user for a password.
|
467
468
|
|
@@ -493,15 +494,15 @@ def get_password(
|
|
493
494
|
from meerschaum.utils.warnings import warn
|
494
495
|
while True:
|
495
496
|
password = prompt(
|
496
|
-
|
497
|
-
is_password
|
497
|
+
"Password" + (f" for user '{username}':" if username is not None else ":"),
|
498
|
+
is_password=True,
|
498
499
|
**kw
|
499
500
|
)
|
500
501
|
if minimum_length is not None and len(password) < minimum_length:
|
501
502
|
warn(
|
502
503
|
"Password is too short. " +
|
503
504
|
f"Please enter a password that is at least {minimum_length} characters.",
|
504
|
-
stack
|
505
|
+
stack=False
|
505
506
|
)
|
506
507
|
continue
|
507
508
|
|
@@ -509,12 +510,12 @@ def get_password(
|
|
509
510
|
return password
|
510
511
|
|
511
512
|
_password = prompt(
|
512
|
-
|
513
|
-
is_password
|
513
|
+
"Confirm password" + (f" for user '{username}':" if username is not None else ":"),
|
514
|
+
is_password=True,
|
514
515
|
**kw
|
515
516
|
)
|
516
517
|
if password != _password:
|
517
|
-
warn(
|
518
|
+
warn("Passwords do not match! Please try again.", stack=False)
|
518
519
|
continue
|
519
520
|
else:
|
520
521
|
return password
|
@@ -550,13 +551,13 @@ def get_email(username: Optional[str] = None, allow_omit: bool = True, **kw: Any
|
|
550
551
|
from meerschaum.utils.misc import is_valid_email
|
551
552
|
while True:
|
552
553
|
email = prompt(
|
553
|
-
|
554
|
+
"Email" + (f" for user '{username}'" if username is not None else "") +
|
554
555
|
(" (empty to omit):" if allow_omit else ": "),
|
555
556
|
**kw
|
556
557
|
)
|
557
558
|
if (allow_omit and email == '') or is_valid_email(email):
|
558
559
|
return email
|
559
|
-
warn(
|
560
|
+
warn("Invalid email! Please try again.", stack=False)
|
560
561
|
|
561
562
|
|
562
563
|
def check_noask(noask: bool = False) -> bool:
|
@@ -571,3 +572,20 @@ def check_noask(noask: bool = False) -> bool:
|
|
571
572
|
os.environ.get(NOASK, 'false').lower()
|
572
573
|
in ('1', 'true')
|
573
574
|
)
|
575
|
+
|
576
|
+
|
577
|
+
def get_connectors_completer(*types: str):
|
578
|
+
"""
|
579
|
+
Return a prompt-toolkit Completer object to pass into `prompt()`.
|
580
|
+
"""
|
581
|
+
from meerschaum.utils.misc import get_connector_labels
|
582
|
+
prompt_toolkit_completion = mrsm.attempt_import('prompt_toolkit.completion', lazy=False)
|
583
|
+
Completer = prompt_toolkit_completion.Completer
|
584
|
+
Completion = prompt_toolkit_completion.Completion
|
585
|
+
|
586
|
+
class ConnectorCompleter(Completer):
|
587
|
+
def get_completions(self, document, complete_event):
|
588
|
+
for label in get_connector_labels(*types):
|
589
|
+
yield Completion(label, start_position=(-1 * len(document.text)))
|
590
|
+
|
591
|
+
return ConnectorCompleter()
|