meerschaum 2.2.6__py3-none-any.whl → 2.3.0.dev1__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/__init__.py +4 -1
- meerschaum/__main__.py +10 -5
- meerschaum/_internal/arguments/_parser.py +44 -15
- meerschaum/_internal/entry.py +35 -14
- meerschaum/_internal/shell/Shell.py +155 -53
- meerschaum/_internal/shell/updates.py +175 -0
- meerschaum/actions/api.py +12 -12
- meerschaum/actions/attach.py +95 -0
- meerschaum/actions/delete.py +35 -26
- meerschaum/actions/register.py +19 -5
- meerschaum/actions/show.py +119 -148
- meerschaum/actions/start.py +85 -75
- meerschaum/actions/stop.py +68 -39
- meerschaum/actions/sync.py +3 -3
- meerschaum/actions/upgrade.py +28 -36
- meerschaum/api/_events.py +18 -1
- meerschaum/api/_oauth2.py +2 -0
- meerschaum/api/_websockets.py +2 -2
- meerschaum/api/dash/jobs.py +5 -2
- meerschaum/api/routes/__init__.py +1 -0
- meerschaum/api/routes/_actions.py +122 -44
- meerschaum/api/routes/_jobs.py +340 -0
- meerschaum/api/routes/_pipes.py +25 -25
- meerschaum/config/_default.py +1 -0
- meerschaum/config/_formatting.py +1 -0
- meerschaum/config/_paths.py +5 -0
- meerschaum/config/_shell.py +84 -67
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +9 -0
- meerschaum/connectors/__init__.py +9 -11
- meerschaum/connectors/api/APIConnector.py +18 -1
- meerschaum/connectors/api/_actions.py +60 -71
- meerschaum/connectors/api/_jobs.py +260 -0
- meerschaum/connectors/api/_misc.py +1 -1
- meerschaum/connectors/api/_request.py +13 -9
- meerschaum/connectors/parse.py +23 -7
- meerschaum/core/Pipe/_sync.py +3 -0
- meerschaum/plugins/__init__.py +89 -5
- meerschaum/utils/daemon/Daemon.py +333 -149
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +19 -10
- meerschaum/utils/daemon/RotatingFile.py +18 -7
- meerschaum/utils/daemon/StdinFile.py +110 -0
- meerschaum/utils/daemon/__init__.py +40 -27
- meerschaum/utils/formatting/__init__.py +83 -37
- meerschaum/utils/formatting/_jobs.py +118 -51
- meerschaum/utils/formatting/_shell.py +6 -0
- meerschaum/utils/jobs/_Job.py +684 -0
- meerschaum/utils/jobs/__init__.py +245 -0
- meerschaum/utils/misc.py +18 -17
- meerschaum/utils/packages/__init__.py +21 -15
- meerschaum/utils/packages/_packages.py +2 -2
- meerschaum/utils/prompt.py +20 -7
- meerschaum/utils/schedule.py +21 -15
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/METADATA +9 -9
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/RECORD +61 -54
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/WHEEL +1 -1
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.3.0.dev1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# vim:fenc=utf-8
|
4
|
+
|
5
|
+
"""
|
6
|
+
Higher-level utilities for managing `meerschaum.utils.daemon.Daemon`.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import pathlib
|
10
|
+
|
11
|
+
import meerschaum as mrsm
|
12
|
+
from meerschaum.utils.jobs._Job import Job, StopMonitoringLogs
|
13
|
+
from meerschaum.utils.typing import Dict, Optional, List, Callable, Any
|
14
|
+
|
15
|
+
__all__ = (
|
16
|
+
'Job',
|
17
|
+
'get_jobs',
|
18
|
+
'get_filtered_jobs',
|
19
|
+
'get_restart_jobs',
|
20
|
+
'get_running_jobs',
|
21
|
+
'get_stopped_jobs',
|
22
|
+
'get_paused_jobs',
|
23
|
+
'get_restart_jobs',
|
24
|
+
'check_restart_jobs',
|
25
|
+
'start_check_jobs_thread',
|
26
|
+
'stop_check_jobs_thread',
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
def get_jobs(
|
31
|
+
executor_keys: Optional[str] = None,
|
32
|
+
debug: bool = False,
|
33
|
+
) -> Dict[str, Job]:
|
34
|
+
"""
|
35
|
+
Return a dictionary of the existing jobs.
|
36
|
+
|
37
|
+
Parameters
|
38
|
+
----------
|
39
|
+
executor_keys: Optional[str], default None
|
40
|
+
If provided, return remote jobs on the given API instance.
|
41
|
+
Otherwise return local jobs.
|
42
|
+
|
43
|
+
Returns
|
44
|
+
-------
|
45
|
+
A dictionary mapping job names to jobs.
|
46
|
+
"""
|
47
|
+
from meerschaum.connectors.parse import parse_connector_keys
|
48
|
+
if executor_keys == 'local':
|
49
|
+
executor_keys = None
|
50
|
+
|
51
|
+
if executor_keys is not None:
|
52
|
+
try:
|
53
|
+
_ = parse_connector_keys(executor_keys, construct=False)
|
54
|
+
conn = mrsm.get_connector(executor_keys)
|
55
|
+
return conn.get_jobs(debug=debug)
|
56
|
+
except Exception:
|
57
|
+
return {}
|
58
|
+
|
59
|
+
from meerschaum.utils.daemon import get_daemons
|
60
|
+
daemons = get_daemons()
|
61
|
+
return {
|
62
|
+
daemon.daemon_id: Job(name=daemon.daemon_id)
|
63
|
+
for daemon in daemons
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
def get_filtered_jobs(
|
68
|
+
executor_keys: Optional[str] = None,
|
69
|
+
filter_list: Optional[List[str]] = None,
|
70
|
+
warn: bool = False,
|
71
|
+
debug: bool = False,
|
72
|
+
) -> Dict[str, Job]:
|
73
|
+
"""
|
74
|
+
Return a list of jobs filtered by the user.
|
75
|
+
"""
|
76
|
+
from meerschaum.utils.warnings import warn as _warn
|
77
|
+
jobs = get_jobs(executor_keys, debug=debug)
|
78
|
+
|
79
|
+
if not filter_list:
|
80
|
+
return {
|
81
|
+
name: job
|
82
|
+
for name, job in jobs.items()
|
83
|
+
if not job.hidden
|
84
|
+
}
|
85
|
+
|
86
|
+
jobs_to_return = {}
|
87
|
+
for name in filter_list:
|
88
|
+
job = jobs.get(name, None)
|
89
|
+
if job is None:
|
90
|
+
if warn:
|
91
|
+
_warn(
|
92
|
+
f"Job '{name}' does not exist.",
|
93
|
+
stack=False,
|
94
|
+
)
|
95
|
+
continue
|
96
|
+
jobs_to_return[name] = job
|
97
|
+
|
98
|
+
return jobs_to_return
|
99
|
+
|
100
|
+
|
101
|
+
def get_restart_jobs(
|
102
|
+
executor_keys: Optional[str] = None,
|
103
|
+
jobs: Optional[Dict[str, Job]] = None,
|
104
|
+
debug: bool = False,
|
105
|
+
) -> Dict[str, Job]:
|
106
|
+
"""
|
107
|
+
Return jobs which were created with `--restart` or `--loop`.
|
108
|
+
"""
|
109
|
+
if jobs is None:
|
110
|
+
jobs = get_jobs(executor_keys, debug=debug)
|
111
|
+
|
112
|
+
return {
|
113
|
+
name: job
|
114
|
+
for name, job in jobs.items()
|
115
|
+
if job.restart
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
def get_running_jobs(
|
120
|
+
executor_keys: Optional[str] = None,
|
121
|
+
jobs: Optional[Dict[str, Job]] = None,
|
122
|
+
debug: bool = False,
|
123
|
+
) -> Dict[str, Job]:
|
124
|
+
"""
|
125
|
+
Return a dictionary of running jobs.
|
126
|
+
"""
|
127
|
+
if jobs is None:
|
128
|
+
jobs = get_jobs(executor_keys, debug=debug)
|
129
|
+
|
130
|
+
return {
|
131
|
+
name: job
|
132
|
+
for name, job in jobs.items()
|
133
|
+
if job.status == 'running'
|
134
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
def get_paused_jobs(
|
138
|
+
executor_keys: Optional[str] = None,
|
139
|
+
jobs: Optional[Dict[str, Job]] = None,
|
140
|
+
debug: bool = False,
|
141
|
+
) -> Dict[str, Job]:
|
142
|
+
"""
|
143
|
+
Return a dictionary of paused jobs.
|
144
|
+
"""
|
145
|
+
if jobs is None:
|
146
|
+
jobs = get_jobs(executor_keys, debug=debug)
|
147
|
+
|
148
|
+
return {
|
149
|
+
name: job
|
150
|
+
for name, job in jobs.items()
|
151
|
+
if job.status == 'paused'
|
152
|
+
}
|
153
|
+
|
154
|
+
|
155
|
+
def get_stopped_jobs(
|
156
|
+
executor_keys: Optional[str] = None,
|
157
|
+
jobs: Optional[Dict[str, Job]] = None,
|
158
|
+
debug: bool = False,
|
159
|
+
) -> Dict[str, Job]:
|
160
|
+
"""
|
161
|
+
Return a dictionary of stopped jobs.
|
162
|
+
"""
|
163
|
+
if jobs is None:
|
164
|
+
jobs = get_jobs(executor_keys, debug=debug)
|
165
|
+
|
166
|
+
return {
|
167
|
+
name: job
|
168
|
+
for name, job in jobs.items()
|
169
|
+
if job.status == 'stopped'
|
170
|
+
}
|
171
|
+
|
172
|
+
|
173
|
+
def check_restart_jobs(
|
174
|
+
executor_keys: Optional[str] = None,
|
175
|
+
silent: bool = False,
|
176
|
+
) -> None:
|
177
|
+
"""
|
178
|
+
Restart any stopped jobs which were created with `--restart`.
|
179
|
+
|
180
|
+
Parameters
|
181
|
+
----------
|
182
|
+
executor_keys: Optional[str], default None
|
183
|
+
If provided, check jobs on the given remote API instance.
|
184
|
+
Otherwise check local jobs.
|
185
|
+
|
186
|
+
silent: bool, default False
|
187
|
+
If `True`, do not print the restart success message.
|
188
|
+
"""
|
189
|
+
jobs = get_jobs(executor_keys)
|
190
|
+
for name, job in jobs.items():
|
191
|
+
success, msg = job.check_restart()
|
192
|
+
if not silent:
|
193
|
+
mrsm.pprint((success, msg))
|
194
|
+
|
195
|
+
|
196
|
+
def _check_restart_jobs_against_lock(*args, **kwargs):
|
197
|
+
from meerschaum.config.paths import CHECK_JOBS_LOCK_PATH
|
198
|
+
fasteners = mrsm.attempt_import('fasteners')
|
199
|
+
lock = fasteners.InterProcessLock(CHECK_JOBS_LOCK_PATH)
|
200
|
+
with lock:
|
201
|
+
check_restart_jobs(*args, **kwargs)
|
202
|
+
|
203
|
+
|
204
|
+
_check_loop_stop_thread = None
|
205
|
+
def start_check_jobs_thread():
|
206
|
+
"""
|
207
|
+
Start a thread to regularly monitor jobs.
|
208
|
+
"""
|
209
|
+
import atexit
|
210
|
+
from functools import partial
|
211
|
+
from meerschaum.utils.threading import RepeatTimer
|
212
|
+
from meerschaum.config.static import STATIC_CONFIG
|
213
|
+
|
214
|
+
global _check_loop_stop_thread
|
215
|
+
sleep_seconds = STATIC_CONFIG['jobs']['check_restart_seconds']
|
216
|
+
|
217
|
+
_check_loop_stop_thread = RepeatTimer(
|
218
|
+
sleep_seconds,
|
219
|
+
partial(
|
220
|
+
_check_restart_jobs_against_lock,
|
221
|
+
silent=True,
|
222
|
+
)
|
223
|
+
)
|
224
|
+
_check_loop_stop_thread.daemon = False
|
225
|
+
atexit.register(stop_check_jobs_thread)
|
226
|
+
|
227
|
+
_check_loop_stop_thread.start()
|
228
|
+
|
229
|
+
|
230
|
+
def stop_check_jobs_thread():
|
231
|
+
"""
|
232
|
+
Stop the job monitoring thread.
|
233
|
+
"""
|
234
|
+
from meerschaum.config.paths import CHECK_JOBS_LOCK_PATH
|
235
|
+
from meerschaum.utils.warnings import warn
|
236
|
+
if _check_loop_stop_thread is None:
|
237
|
+
return
|
238
|
+
|
239
|
+
_check_loop_stop_thread.cancel()
|
240
|
+
|
241
|
+
try:
|
242
|
+
if CHECK_JOBS_LOCK_PATH.exists():
|
243
|
+
CHECK_JOBS_LOCK_PATH.unlink()
|
244
|
+
except Exception as e:
|
245
|
+
warn(f"Failed to remove check jobs lock file:\n{e}")
|
meerschaum/utils/misc.py
CHANGED
@@ -875,7 +875,7 @@ def dict_from_od(od: collections.OrderedDict) -> Dict[Any, Any]:
|
|
875
875
|
_d[k] = dict_from_od(v)
|
876
876
|
return _d
|
877
877
|
|
878
|
-
def remove_ansi(s
|
878
|
+
def remove_ansi(s: str) -> str:
|
879
879
|
"""
|
880
880
|
Remove ANSI escape characters from a string.
|
881
881
|
|
@@ -899,10 +899,10 @@ def remove_ansi(s : str) -> str:
|
|
899
899
|
|
900
900
|
|
901
901
|
def get_connector_labels(
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
902
|
+
*types: str,
|
903
|
+
search_term: str = '',
|
904
|
+
ignore_exact_match = True,
|
905
|
+
) -> List[str]:
|
906
906
|
"""
|
907
907
|
Read connector labels from the configuration dictionary.
|
908
908
|
|
@@ -1063,7 +1063,7 @@ def async_wrap(func):
|
|
1063
1063
|
loop = asyncio.get_event_loop()
|
1064
1064
|
pfunc = partial(func, *args, **kwargs)
|
1065
1065
|
return await loop.run_in_executor(executor, pfunc)
|
1066
|
-
return run
|
1066
|
+
return run
|
1067
1067
|
|
1068
1068
|
|
1069
1069
|
def debug_trace(browser: bool = True):
|
@@ -1077,17 +1077,17 @@ def debug_trace(browser: bool = True):
|
|
1077
1077
|
|
1078
1078
|
|
1079
1079
|
def items_str(
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1080
|
+
items: List[Any],
|
1081
|
+
quotes: bool = True,
|
1082
|
+
quote_str: str = "'",
|
1083
|
+
commas: bool = True,
|
1084
|
+
comma_str: str = ',',
|
1085
|
+
and_: bool = True,
|
1086
|
+
and_str: str = 'and',
|
1087
|
+
oxford_comma: bool = True,
|
1088
|
+
spaces: bool = True,
|
1089
|
+
space_str = ' ',
|
1090
|
+
) -> str:
|
1091
1091
|
"""
|
1092
1092
|
Return a formatted string if list items separated by commas.
|
1093
1093
|
|
@@ -1522,6 +1522,7 @@ def safely_extract_tar(tarf: 'file', output_dir: Union[str, 'pathlib.Path']) ->
|
|
1522
1522
|
|
1523
1523
|
return safe_extract(tarf, output_dir)
|
1524
1524
|
|
1525
|
+
|
1525
1526
|
##################
|
1526
1527
|
# Legacy imports #
|
1527
1528
|
##################
|
@@ -816,6 +816,7 @@ def pip_install(
|
|
816
816
|
"""
|
817
817
|
from meerschaum.config._paths import VIRTENV_RESOURCES_PATH
|
818
818
|
from meerschaum.config import get_config
|
819
|
+
from meerschaum.config.static import STATIC_CONFIG
|
819
820
|
from meerschaum.utils.warnings import warn
|
820
821
|
from meerschaum.utils.misc import is_android
|
821
822
|
if args is None:
|
@@ -827,6 +828,11 @@ def pip_install(
|
|
827
828
|
if check_wheel:
|
828
829
|
have_wheel = venv_contains_package('wheel', venv=venv, debug=debug)
|
829
830
|
|
831
|
+
daemon_env_var = STATIC_CONFIG['environment']['daemon_id']
|
832
|
+
inside_daemon = daemon_env_var in os.environ
|
833
|
+
if inside_daemon:
|
834
|
+
silent = True
|
835
|
+
|
830
836
|
_args = list(args)
|
831
837
|
have_pip = venv_contains_package('pip', venv=None, debug=debug)
|
832
838
|
try:
|
@@ -844,16 +850,16 @@ def pip_install(
|
|
844
850
|
if have_pip and not have_uv_pip and _install_uv_pip and not is_android():
|
845
851
|
if not pip_install(
|
846
852
|
'uv',
|
847
|
-
venv
|
848
|
-
debug
|
849
|
-
_install_uv_pip
|
850
|
-
check_update
|
851
|
-
check_pypi
|
852
|
-
check_wheel
|
853
|
-
):
|
853
|
+
venv=None,
|
854
|
+
debug=debug,
|
855
|
+
_install_uv_pip=False,
|
856
|
+
check_update=False,
|
857
|
+
check_pypi=False,
|
858
|
+
check_wheel=False,
|
859
|
+
) and not silent:
|
854
860
|
warn(
|
855
861
|
f"Failed to install `uv` for virtual environment '{venv}'.",
|
856
|
-
color
|
862
|
+
color=False,
|
857
863
|
)
|
858
864
|
|
859
865
|
use_uv_pip = (
|
@@ -909,13 +915,13 @@ def pip_install(
|
|
909
915
|
check_wheel = False,
|
910
916
|
debug = debug,
|
911
917
|
_install_uv_pip = False,
|
912
|
-
):
|
918
|
+
) and not silent:
|
913
919
|
warn(
|
914
920
|
(
|
915
921
|
"Failed to install `setuptools`, `wheel`, and `uv` for virtual "
|
916
922
|
+ f"environment '{venv}'."
|
917
923
|
),
|
918
|
-
color
|
924
|
+
color=False,
|
919
925
|
)
|
920
926
|
|
921
927
|
if requirements_file_path is not None:
|
@@ -975,7 +981,7 @@ def pip_install(
|
|
975
981
|
if not completely_uninstall_package(
|
976
982
|
_install_no_version,
|
977
983
|
venv=venv, debug=debug,
|
978
|
-
):
|
984
|
+
) and not silent:
|
979
985
|
warn(
|
980
986
|
f"Failed to clean up package '{_install_no_version}'.",
|
981
987
|
)
|
@@ -989,9 +995,9 @@ def pip_install(
|
|
989
995
|
rc = run_python_package(
|
990
996
|
('pip' if not use_uv_pip else 'uv'),
|
991
997
|
_args + _packages,
|
992
|
-
venv
|
993
|
-
env
|
994
|
-
debug
|
998
|
+
venv=None,
|
999
|
+
env=_get_pip_os_env(color=color),
|
1000
|
+
debug=debug,
|
995
1001
|
)
|
996
1002
|
if debug:
|
997
1003
|
print(f"{rc=}")
|
@@ -1003,7 +1009,7 @@ def pip_install(
|
|
1003
1009
|
)
|
1004
1010
|
if not silent:
|
1005
1011
|
print(msg)
|
1006
|
-
if debug:
|
1012
|
+
if debug and not silent:
|
1007
1013
|
print('pip ' + ('un' if _uninstall else '') + 'install returned:', success)
|
1008
1014
|
return success
|
1009
1015
|
|
@@ -48,7 +48,7 @@ packages: Dict[str, Dict[str, str]] = {
|
|
48
48
|
'prompt_toolkit' : 'prompt-toolkit>=3.0.39',
|
49
49
|
'more_itertools' : 'more-itertools>=8.7.0',
|
50
50
|
'daemon' : 'python-daemon>=0.2.3',
|
51
|
-
'fasteners' : 'fasteners>=0.
|
51
|
+
'fasteners' : 'fasteners>=0.19.0',
|
52
52
|
'psutil' : 'psutil>=5.8.0',
|
53
53
|
'watchfiles' : 'watchfiles>=0.21.0',
|
54
54
|
'dill' : 'dill>=0.3.3',
|
@@ -58,7 +58,7 @@ packages: Dict[str, Dict[str, str]] = {
|
|
58
58
|
},
|
59
59
|
'drivers': {
|
60
60
|
'cryptography' : 'cryptography>=38.0.1',
|
61
|
-
'psycopg' : 'psycopg[binary]>=3.1
|
61
|
+
'psycopg' : 'psycopg[binary]>=3.2.1',
|
62
62
|
'pymysql' : 'PyMySQL>=0.9.0',
|
63
63
|
'aiomysql' : 'aiomysql>=0.0.21',
|
64
64
|
'sqlalchemy_cockroachdb' : 'sqlalchemy-cockroachdb>=2.0.0',
|
meerschaum/utils/prompt.py
CHANGED
@@ -14,6 +14,7 @@ def prompt(
|
|
14
14
|
question: str,
|
15
15
|
icon: bool = True,
|
16
16
|
default: Union[str, Tuple[str, str], None] = None,
|
17
|
+
default_editable: Optional[str] = None,
|
17
18
|
detect_password: bool = True,
|
18
19
|
is_password: bool = False,
|
19
20
|
wrap_lines: bool = True,
|
@@ -37,6 +38,9 @@ def prompt(
|
|
37
38
|
default: Union[str, Tuple[str, str], None], default None
|
38
39
|
If the response is '', return the default value.
|
39
40
|
|
41
|
+
default_editable: Optional[str], default None
|
42
|
+
If provided, auto-type this user-editable string in the prompt.
|
43
|
+
|
40
44
|
detect_password: bool, default True
|
41
45
|
If `True`, set the input method to a censored password box if the word `password`
|
42
46
|
appears in the question.
|
@@ -62,6 +66,7 @@ def prompt(
|
|
62
66
|
from meerschaum.config import get_config
|
63
67
|
from meerschaum.config.static import _static_config
|
64
68
|
from meerschaum.utils.misc import filter_keywords
|
69
|
+
from meerschaum.utils.daemon import running_in_daemon
|
65
70
|
noask = check_noask(noask)
|
66
71
|
if not noask:
|
67
72
|
prompt_toolkit = attempt_import('prompt_toolkit')
|
@@ -98,13 +103,21 @@ def prompt(
|
|
98
103
|
question += '\n' + other_lines
|
99
104
|
question += ' '
|
100
105
|
|
101
|
-
|
102
|
-
|
103
|
-
prompt_toolkit.
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
106
|
+
if not running_in_daemon():
|
107
|
+
answer = (
|
108
|
+
prompt_toolkit.prompt(
|
109
|
+
prompt_toolkit.formatted_text.ANSI(question),
|
110
|
+
wrap_lines = wrap_lines,
|
111
|
+
default = default_editable or '',
|
112
|
+
**filter_keywords(prompt_toolkit.prompt, **kw)
|
113
|
+
) if not noask else ''
|
114
|
+
)
|
115
|
+
else:
|
116
|
+
print(question, end='', flush=True)
|
117
|
+
try:
|
118
|
+
answer = input()
|
119
|
+
except EOFError:
|
120
|
+
answer = ''
|
108
121
|
if noask:
|
109
122
|
print(question)
|
110
123
|
if answer == '' and default is not None:
|
meerschaum/utils/schedule.py
CHANGED
@@ -7,10 +7,12 @@ Schedule processes and threads.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
import
|
10
|
+
import signal
|
11
|
+
import traceback
|
11
12
|
from datetime import datetime, timezone, timedelta
|
12
13
|
import meerschaum as mrsm
|
13
14
|
from meerschaum.utils.typing import Callable, Any, Optional, List, Dict
|
15
|
+
from meerschaum.utils.warnings import warn, error
|
14
16
|
|
15
17
|
STARTING_KEYWORD: str = 'starting'
|
16
18
|
INTERVAL_UNITS: List[str] = ['months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'years']
|
@@ -70,15 +72,15 @@ SCHEDULE_ALIASES: Dict[str, str] = {
|
|
70
72
|
|
71
73
|
_scheduler = None
|
72
74
|
def schedule_function(
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
function: Callable[[Any], Any],
|
76
|
+
schedule: str,
|
77
|
+
*args,
|
78
|
+
debug: bool = False,
|
79
|
+
**kw
|
80
|
+
) -> mrsm.SuccessTuple:
|
79
81
|
"""
|
80
82
|
Block the process and execute the function intermittently according to the frequency.
|
81
|
-
https://
|
83
|
+
https://meerschaum.io/reference/background-jobs/#-schedules
|
82
84
|
|
83
85
|
Parameters
|
84
86
|
----------
|
@@ -88,10 +90,13 @@ def schedule_function(
|
|
88
90
|
schedule: str
|
89
91
|
The frequency schedule at which `function` should be executed (e.g. `'daily'`).
|
90
92
|
|
93
|
+
Returns
|
94
|
+
-------
|
95
|
+
A `SuccessTuple` upon exit.
|
91
96
|
"""
|
92
97
|
import asyncio
|
93
|
-
from meerschaum.utils.warnings import warn
|
94
98
|
from meerschaum.utils.misc import filter_keywords, round_time
|
99
|
+
|
95
100
|
global _scheduler
|
96
101
|
kw['debug'] = debug
|
97
102
|
kw = filter_keywords(function, **kw)
|
@@ -105,15 +110,16 @@ def schedule_function(
|
|
105
110
|
except RuntimeError:
|
106
111
|
loop = asyncio.new_event_loop()
|
107
112
|
|
113
|
+
|
108
114
|
async def run_scheduler():
|
109
115
|
async with _scheduler:
|
110
116
|
job = await _scheduler.add_schedule(
|
111
117
|
function,
|
112
118
|
trigger,
|
113
|
-
args
|
114
|
-
kwargs
|
115
|
-
max_running_jobs
|
116
|
-
conflict_policy
|
119
|
+
args=args,
|
120
|
+
kwargs=kw,
|
121
|
+
max_running_jobs=1,
|
122
|
+
conflict_policy=apscheduler.ConflictPolicy.replace,
|
117
123
|
)
|
118
124
|
try:
|
119
125
|
await _scheduler.run_until_stopped()
|
@@ -126,12 +132,13 @@ def schedule_function(
|
|
126
132
|
except (KeyboardInterrupt, SystemExit) as e:
|
127
133
|
loop.run_until_complete(_stop_scheduler())
|
128
134
|
|
135
|
+
return True, "Success"
|
136
|
+
|
129
137
|
|
130
138
|
def parse_schedule(schedule: str, now: Optional[datetime] = None):
|
131
139
|
"""
|
132
140
|
Parse a schedule string (e.g. 'daily') into a Trigger object.
|
133
141
|
"""
|
134
|
-
from meerschaum.utils.warnings import error
|
135
142
|
from meerschaum.utils.misc import items_str, is_int
|
136
143
|
(
|
137
144
|
apscheduler_triggers_cron,
|
@@ -279,7 +286,6 @@ def parse_start_time(schedule: str, now: Optional[datetime] = None) -> datetime:
|
|
279
286
|
datetime.datetime(2024, 5, 13, 0, 30, tzinfo=datetime.timezone.utc)
|
280
287
|
"""
|
281
288
|
from meerschaum.utils.misc import round_time
|
282
|
-
from meerschaum.utils.warnings import error, warn
|
283
289
|
dateutil_parser = mrsm.attempt_import('dateutil.parser')
|
284
290
|
starting_parts = schedule.split(STARTING_KEYWORD)
|
285
291
|
starting_str = ('now' if len(starting_parts) == 1 else starting_parts[-1]).strip()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: meerschaum
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3.0.dev1
|
4
4
|
Summary: Sync Time-Series Pipes with Meerschaum
|
5
5
|
Home-page: https://meerschaum.io
|
6
6
|
Author: Bennett Meares
|
@@ -51,7 +51,7 @@ Requires-Dist: databases >=0.4.0 ; extra == 'api'
|
|
51
51
|
Requires-Dist: aiosqlite >=0.16.0 ; extra == 'api'
|
52
52
|
Requires-Dist: asyncpg >=0.21.0 ; extra == 'api'
|
53
53
|
Requires-Dist: cryptography >=38.0.1 ; extra == 'api'
|
54
|
-
Requires-Dist: psycopg[binary] >=3.1
|
54
|
+
Requires-Dist: psycopg[binary] >=3.2.1 ; extra == 'api'
|
55
55
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'api'
|
56
56
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'api'
|
57
57
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'api'
|
@@ -74,7 +74,7 @@ Requires-Dist: packaging >=21.3.0 ; extra == 'api'
|
|
74
74
|
Requires-Dist: prompt-toolkit >=3.0.39 ; extra == 'api'
|
75
75
|
Requires-Dist: more-itertools >=8.7.0 ; extra == 'api'
|
76
76
|
Requires-Dist: python-daemon >=0.2.3 ; extra == 'api'
|
77
|
-
Requires-Dist: fasteners >=0.
|
77
|
+
Requires-Dist: fasteners >=0.19.0 ; extra == 'api'
|
78
78
|
Requires-Dist: psutil >=5.8.0 ; extra == 'api'
|
79
79
|
Requires-Dist: watchfiles >=0.21.0 ; extra == 'api'
|
80
80
|
Requires-Dist: dill >=0.3.3 ; extra == 'api'
|
@@ -124,7 +124,7 @@ Requires-Dist: packaging >=21.3.0 ; extra == 'core'
|
|
124
124
|
Requires-Dist: prompt-toolkit >=3.0.39 ; extra == 'core'
|
125
125
|
Requires-Dist: more-itertools >=8.7.0 ; extra == 'core'
|
126
126
|
Requires-Dist: python-daemon >=0.2.3 ; extra == 'core'
|
127
|
-
Requires-Dist: fasteners >=0.
|
127
|
+
Requires-Dist: fasteners >=0.19.0 ; extra == 'core'
|
128
128
|
Requires-Dist: psutil >=5.8.0 ; extra == 'core'
|
129
129
|
Requires-Dist: watchfiles >=0.21.0 ; extra == 'core'
|
130
130
|
Requires-Dist: dill >=0.3.3 ; extra == 'core'
|
@@ -161,7 +161,7 @@ Requires-Dist: mkdocs-redirects >=1.0.4 ; extra == 'docs'
|
|
161
161
|
Requires-Dist: jinja2 ==3.0.3 ; extra == 'docs'
|
162
162
|
Provides-Extra: drivers
|
163
163
|
Requires-Dist: cryptography >=38.0.1 ; extra == 'drivers'
|
164
|
-
Requires-Dist: psycopg[binary] >=3.1
|
164
|
+
Requires-Dist: psycopg[binary] >=3.2.1 ; extra == 'drivers'
|
165
165
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'drivers'
|
166
166
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'drivers'
|
167
167
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'drivers'
|
@@ -211,7 +211,7 @@ Requires-Dist: packaging >=21.3.0 ; extra == 'full'
|
|
211
211
|
Requires-Dist: prompt-toolkit >=3.0.39 ; extra == 'full'
|
212
212
|
Requires-Dist: more-itertools >=8.7.0 ; extra == 'full'
|
213
213
|
Requires-Dist: python-daemon >=0.2.3 ; extra == 'full'
|
214
|
-
Requires-Dist: fasteners >=0.
|
214
|
+
Requires-Dist: fasteners >=0.19.0 ; extra == 'full'
|
215
215
|
Requires-Dist: psutil >=5.8.0 ; extra == 'full'
|
216
216
|
Requires-Dist: watchfiles >=0.21.0 ; extra == 'full'
|
217
217
|
Requires-Dist: dill >=0.3.3 ; extra == 'full'
|
@@ -219,7 +219,7 @@ Requires-Dist: virtualenv >=20.1.0 ; extra == 'full'
|
|
219
219
|
Requires-Dist: APScheduler >=4.0.0a5 ; extra == 'full'
|
220
220
|
Requires-Dist: uv >=0.2.11 ; extra == 'full'
|
221
221
|
Requires-Dist: cryptography >=38.0.1 ; extra == 'full'
|
222
|
-
Requires-Dist: psycopg[binary] >=3.1
|
222
|
+
Requires-Dist: psycopg[binary] >=3.2.1 ; extra == 'full'
|
223
223
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'full'
|
224
224
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'full'
|
225
225
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'full'
|
@@ -273,7 +273,7 @@ Requires-Dist: databases >=0.4.0 ; extra == 'sql'
|
|
273
273
|
Requires-Dist: aiosqlite >=0.16.0 ; extra == 'sql'
|
274
274
|
Requires-Dist: asyncpg >=0.21.0 ; extra == 'sql'
|
275
275
|
Requires-Dist: cryptography >=38.0.1 ; extra == 'sql'
|
276
|
-
Requires-Dist: psycopg[binary] >=3.1
|
276
|
+
Requires-Dist: psycopg[binary] >=3.2.1 ; extra == 'sql'
|
277
277
|
Requires-Dist: PyMySQL >=0.9.0 ; extra == 'sql'
|
278
278
|
Requires-Dist: aiomysql >=0.0.21 ; extra == 'sql'
|
279
279
|
Requires-Dist: sqlalchemy-cockroachdb >=2.0.0 ; extra == 'sql'
|
@@ -296,7 +296,7 @@ Requires-Dist: packaging >=21.3.0 ; extra == 'sql'
|
|
296
296
|
Requires-Dist: prompt-toolkit >=3.0.39 ; extra == 'sql'
|
297
297
|
Requires-Dist: more-itertools >=8.7.0 ; extra == 'sql'
|
298
298
|
Requires-Dist: python-daemon >=0.2.3 ; extra == 'sql'
|
299
|
-
Requires-Dist: fasteners >=0.
|
299
|
+
Requires-Dist: fasteners >=0.19.0 ; extra == 'sql'
|
300
300
|
Requires-Dist: psutil >=5.8.0 ; extra == 'sql'
|
301
301
|
Requires-Dist: watchfiles >=0.21.0 ; extra == 'sql'
|
302
302
|
Requires-Dist: dill >=0.3.3 ; extra == 'sql'
|