meerschaum 2.2.6__py3-none-any.whl → 2.2.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/__main__.py +10 -5
- meerschaum/_internal/entry.py +13 -13
- meerschaum/_internal/shell/Shell.py +26 -22
- meerschaum/_internal/shell/updates.py +175 -0
- meerschaum/actions/register.py +19 -5
- meerschaum/actions/sync.py +3 -3
- meerschaum/actions/upgrade.py +28 -36
- meerschaum/api/routes/_pipes.py +20 -20
- meerschaum/config/_formatting.py +1 -0
- meerschaum/config/_paths.py +4 -0
- meerschaum/config/_shell.py +78 -66
- meerschaum/config/_version.py +1 -1
- meerschaum/config/static/__init__.py +1 -0
- meerschaum/connectors/api/_misc.py +1 -1
- meerschaum/connectors/api/_request.py +13 -9
- meerschaum/core/Pipe/_sync.py +3 -0
- meerschaum/utils/daemon/Daemon.py +88 -129
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +14 -5
- meerschaum/utils/daemon/RotatingFile.py +8 -1
- meerschaum/utils/daemon/__init__.py +28 -21
- meerschaum/utils/formatting/__init__.py +81 -36
- meerschaum/utils/formatting/_jobs.py +47 -9
- meerschaum/utils/packages/__init__.py +21 -15
- meerschaum/utils/prompt.py +5 -0
- meerschaum/utils/schedule.py +21 -15
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/METADATA +1 -1
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/RECORD +33 -32
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/LICENSE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/NOTICE +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/WHEEL +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/top_level.txt +0 -0
- {meerschaum-2.2.6.dist-info → meerschaum-2.2.7.dist-info}/zip-safe +0 -0
@@ -67,19 +67,17 @@ def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
|
67
67
|
if daemon.status == 'running':
|
68
68
|
return True, f"Daemon '{daemon}' is already running."
|
69
69
|
return daemon.run(
|
70
|
-
debug
|
71
|
-
allow_dirty_run
|
70
|
+
debug=debug,
|
71
|
+
allow_dirty_run=True,
|
72
72
|
)
|
73
73
|
|
74
74
|
success_tuple = run_daemon(
|
75
75
|
entry,
|
76
76
|
filtered_sysargs,
|
77
|
-
daemon_id
|
78
|
-
label
|
79
|
-
keep_daemon_output
|
77
|
+
daemon_id=_args.get('name', None) if _args else None,
|
78
|
+
label=label,
|
79
|
+
keep_daemon_output=('--rm' not in sysargs),
|
80
80
|
)
|
81
|
-
if not isinstance(success_tuple, tuple):
|
82
|
-
success_tuple = False, str(success_tuple)
|
83
81
|
return success_tuple
|
84
82
|
|
85
83
|
|
@@ -109,25 +107,25 @@ def daemon_action(**kw) -> SuccessTuple:
|
|
109
107
|
|
110
108
|
|
111
109
|
def run_daemon(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
110
|
+
func: Callable[[Any], Any],
|
111
|
+
*args,
|
112
|
+
daemon_id: Optional[str] = None,
|
113
|
+
keep_daemon_output: bool = True,
|
114
|
+
allow_dirty_run: bool = False,
|
115
|
+
label: Optional[str] = None,
|
116
|
+
**kw
|
117
|
+
) -> Any:
|
120
118
|
"""Execute a function as a daemon."""
|
121
119
|
daemon = Daemon(
|
122
120
|
func,
|
123
|
-
daemon_id
|
124
|
-
target_args
|
125
|
-
target_kw
|
126
|
-
label
|
121
|
+
daemon_id=daemon_id,
|
122
|
+
target_args=[arg for arg in args],
|
123
|
+
target_kw=kw,
|
124
|
+
label=label,
|
127
125
|
)
|
128
126
|
return daemon.run(
|
129
|
-
keep_daemon_output
|
130
|
-
allow_dirty_run
|
127
|
+
keep_daemon_output=keep_daemon_output,
|
128
|
+
allow_dirty_run=allow_dirty_run,
|
131
129
|
)
|
132
130
|
|
133
131
|
|
@@ -268,3 +266,12 @@ def get_filtered_daemons(
|
|
268
266
|
pass
|
269
267
|
daemons.append(d)
|
270
268
|
return daemons
|
269
|
+
|
270
|
+
|
271
|
+
def running_in_daemon() -> bool:
|
272
|
+
"""
|
273
|
+
Return whether the current thread is running in a Daemon context.
|
274
|
+
"""
|
275
|
+
from meerschaum.config.static import STATIC_CONFIG
|
276
|
+
daemon_env_var = STATIC_CONFIG['environment']['daemon_id']
|
277
|
+
return daemon_env_var in os.environ
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
10
10
|
import platform
|
11
11
|
import os
|
12
12
|
import sys
|
13
|
+
import meerschaum as mrsm
|
13
14
|
from meerschaum.utils.typing import Optional, Union, Any, Dict
|
14
15
|
from meerschaum.utils.formatting._shell import make_header
|
15
16
|
from meerschaum.utils.formatting._pprint import pprint
|
@@ -33,6 +34,7 @@ __all__ = sorted([
|
|
33
34
|
'colored',
|
34
35
|
'translate_rich_to_termcolor',
|
35
36
|
'get_console',
|
37
|
+
'format_success_tuple',
|
36
38
|
'print_tuple',
|
37
39
|
'print_options',
|
38
40
|
'fill_ansi',
|
@@ -222,16 +224,17 @@ def get_console():
|
|
222
224
|
|
223
225
|
|
224
226
|
def print_tuple(
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
227
|
+
tup: mrsm.SuccessTuple,
|
228
|
+
skip_common: bool = True,
|
229
|
+
common_only: bool = False,
|
230
|
+
upper_padding: int = 0,
|
231
|
+
lower_padding: int = 0,
|
232
|
+
left_padding: int = 1,
|
233
|
+
calm: bool = False,
|
234
|
+
_progress: Optional['rich.progress.Progress'] = None,
|
235
|
+
) -> None:
|
233
236
|
"""
|
234
|
-
|
237
|
+
Format `meerschaum.utils.typing.SuccessTuple`.
|
235
238
|
|
236
239
|
Parameters
|
237
240
|
----------
|
@@ -247,24 +250,18 @@ def print_tuple(
|
|
247
250
|
lower_padding: int, default 0
|
248
251
|
How many newlines to append to the message.
|
249
252
|
|
253
|
+
left_padding: int, default 1
|
254
|
+
How mant spaces to preprend to the message.
|
255
|
+
|
250
256
|
calm: bool, default False
|
251
257
|
If `True`, use the default emoji and color scheme.
|
258
|
+
|
252
259
|
"""
|
253
260
|
from meerschaum.config.static import STATIC_CONFIG
|
254
|
-
|
255
|
-
try:
|
256
|
-
status = 'success' if tup[0] else 'failure'
|
257
|
-
except TypeError:
|
258
|
-
status = 'failure'
|
259
|
-
tup = None, None
|
260
|
-
|
261
|
-
if calm:
|
262
|
-
status += '_calm'
|
261
|
+
do_print = True
|
263
262
|
|
264
263
|
omit_messages = STATIC_CONFIG['system']['success']['ignore']
|
265
264
|
|
266
|
-
do_print = True
|
267
|
-
|
268
265
|
if common_only:
|
269
266
|
skip_common = False
|
270
267
|
do_print = tup[1] in omit_messages
|
@@ -272,22 +269,70 @@ def print_tuple(
|
|
272
269
|
if skip_common:
|
273
270
|
do_print = tup[1] not in omit_messages
|
274
271
|
|
275
|
-
if do_print:
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
272
|
+
if not do_print:
|
273
|
+
return
|
274
|
+
|
275
|
+
print(format_success_tuple(
|
276
|
+
tup,
|
277
|
+
upper_padding=upper_padding,
|
278
|
+
lower_padding=lower_padding,
|
279
|
+
calm=calm,
|
280
|
+
_progress=_progress,
|
281
|
+
))
|
282
|
+
|
283
|
+
|
284
|
+
def format_success_tuple(
|
285
|
+
tup: mrsm.SuccessTuple,
|
286
|
+
upper_padding: int = 0,
|
287
|
+
lower_padding: int = 0,
|
288
|
+
left_padding: int = 1,
|
289
|
+
calm: bool = False,
|
290
|
+
_progress: Optional['rich.progress.Progress'] = None,
|
291
|
+
) -> str:
|
292
|
+
"""
|
293
|
+
Format `meerschaum.utils.typing.SuccessTuple`.
|
294
|
+
|
295
|
+
Parameters
|
296
|
+
----------
|
297
|
+
upper_padding: int, default 0
|
298
|
+
How many newlines to prepend to the message.
|
299
|
+
|
300
|
+
lower_padding: int, default 0
|
301
|
+
How many newlines to append to the message.
|
302
|
+
|
303
|
+
left_padding: int, default 1
|
304
|
+
How mant spaces to preprend to the message.
|
305
|
+
|
306
|
+
calm: bool, default False
|
307
|
+
If `True`, use the default emoji and color scheme.
|
308
|
+
"""
|
309
|
+
from meerschaum.config.static import STATIC_CONFIG
|
310
|
+
_init()
|
311
|
+
try:
|
312
|
+
status = 'success' if tup[0] else 'failure'
|
313
|
+
except TypeError:
|
314
|
+
status = 'failure'
|
315
|
+
tup = None, None
|
316
|
+
|
317
|
+
if calm:
|
318
|
+
status += '_calm'
|
319
|
+
|
320
|
+
ANSI, CHARSET = __getattr__('ANSI'), __getattr__('CHARSET')
|
321
|
+
from meerschaum.config import get_config
|
322
|
+
status_config = get_config('formatting', status, patch=True)
|
323
|
+
|
324
|
+
msg = (' ' * left_padding) + status_config[CHARSET]['icon'] + ' ' + str(tup[1])
|
325
|
+
lines = msg.split('\n')
|
326
|
+
lines = [lines[0]] + [
|
327
|
+
((' ' + line if not line.startswith(' ') else line))
|
328
|
+
for line in lines[1:]
|
329
|
+
]
|
330
|
+
if ANSI:
|
331
|
+
lines[0] = fill_ansi(highlight_pipes(lines[0]), **status_config['ansi']['rich'])
|
332
|
+
|
333
|
+
msg = '\n'.join(lines)
|
334
|
+
msg = ('\n' * upper_padding) + msg + ('\n' * lower_padding)
|
335
|
+
return msg
|
291
336
|
|
292
337
|
|
293
338
|
def print_options(
|
@@ -7,7 +7,8 @@ Print jobs information.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
|
10
|
+
import meerschaum as mrsm
|
11
|
+
from meerschaum.utils.typing import List, Optional, Any, is_success_tuple
|
11
12
|
from meerschaum.utils.daemon import (
|
12
13
|
Daemon,
|
13
14
|
get_daemons,
|
@@ -17,9 +18,9 @@ from meerschaum.utils.daemon import (
|
|
17
18
|
)
|
18
19
|
|
19
20
|
def pprint_jobs(
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
daemons: List[Daemon],
|
22
|
+
nopretty: bool = False,
|
23
|
+
):
|
23
24
|
"""Pretty-print a list of Daemons."""
|
24
25
|
from meerschaum.utils.formatting import make_header
|
25
26
|
|
@@ -48,10 +49,12 @@ def pprint_jobs(
|
|
48
49
|
pprint_job(d, nopretty=nopretty)
|
49
50
|
|
50
51
|
def _pretty_print():
|
51
|
-
from meerschaum.utils.formatting import get_console, UNICODE, ANSI
|
52
|
+
from meerschaum.utils.formatting import get_console, UNICODE, ANSI, format_success_tuple
|
52
53
|
from meerschaum.utils.packages import import_rich, attempt_import
|
53
54
|
rich = import_rich()
|
54
|
-
rich_table, rich_text, rich_box = attempt_import(
|
55
|
+
rich_table, rich_text, rich_box, rich_json, rich_panel, rich_console = attempt_import(
|
56
|
+
'rich.table', 'rich.text', 'rich.box', 'rich.json', 'rich.panel', 'rich.console',
|
57
|
+
)
|
55
58
|
table = rich_table.Table(
|
56
59
|
title = rich_text.Text('Jobs'),
|
57
60
|
box = (rich_box.ROUNDED if UNICODE else rich_box.ASCII),
|
@@ -62,13 +65,42 @@ def pprint_jobs(
|
|
62
65
|
table.add_column("Command")
|
63
66
|
table.add_column("Status")
|
64
67
|
|
68
|
+
def get_success_text(d):
|
69
|
+
success_tuple = d.properties.get('result', None)
|
70
|
+
if isinstance(success_tuple, list):
|
71
|
+
success_tuple = tuple(success_tuple)
|
72
|
+
if not is_success_tuple(success_tuple):
|
73
|
+
return rich_text.Text('')
|
74
|
+
|
75
|
+
success = success_tuple[0]
|
76
|
+
msg = success_tuple[1]
|
77
|
+
lines = msg.split('\n')
|
78
|
+
msg = '\n'.join(line.lstrip().rstrip() for line in lines)
|
79
|
+
success_tuple = success, msg
|
80
|
+
success_tuple_str = (
|
81
|
+
format_success_tuple(success_tuple, left_padding=1)
|
82
|
+
if success_tuple is not None
|
83
|
+
else None
|
84
|
+
)
|
85
|
+
success_tuple_text = (
|
86
|
+
rich_text.Text.from_ansi(success_tuple_str)
|
87
|
+
) if success_tuple_str is not None else None
|
88
|
+
|
89
|
+
if success_tuple_text is None:
|
90
|
+
return rich_text.Text('')
|
91
|
+
|
92
|
+
return rich_text.Text('\n') + success_tuple_text
|
93
|
+
|
94
|
+
|
65
95
|
for d in running_daemons:
|
66
96
|
if d.hidden:
|
67
97
|
continue
|
68
98
|
table.add_row(
|
69
99
|
d.daemon_id,
|
70
100
|
d.label,
|
71
|
-
|
101
|
+
rich_console.Group(
|
102
|
+
rich_text.Text(d.status, style=('green' if ANSI else '')),
|
103
|
+
),
|
72
104
|
)
|
73
105
|
|
74
106
|
for d in paused_daemons:
|
@@ -77,16 +109,22 @@ def pprint_jobs(
|
|
77
109
|
table.add_row(
|
78
110
|
d.daemon_id,
|
79
111
|
d.label,
|
80
|
-
|
112
|
+
rich_console.Group(
|
113
|
+
rich_text.Text(d.status, style=('yellow' if ANSI else '')),
|
114
|
+
),
|
81
115
|
)
|
82
116
|
|
83
117
|
for d in stopped_daemons:
|
84
118
|
if d.hidden:
|
85
119
|
continue
|
120
|
+
|
86
121
|
table.add_row(
|
87
122
|
d.daemon_id,
|
88
123
|
d.label,
|
89
|
-
|
124
|
+
rich_console.Group(
|
125
|
+
rich_text.Text(d.status, style=('red' if ANSI else '')),
|
126
|
+
get_success_text(d)
|
127
|
+
),
|
90
128
|
)
|
91
129
|
get_console().print(table)
|
92
130
|
|
@@ -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
|
|
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.
|
@@ -102,6 +106,7 @@ def prompt(
|
|
102
106
|
prompt_toolkit.prompt(
|
103
107
|
prompt_toolkit.formatted_text.ANSI(question),
|
104
108
|
wrap_lines = wrap_lines,
|
109
|
+
default = default_editable or '',
|
105
110
|
**filter_keywords(prompt_toolkit.prompt, **kw)
|
106
111
|
) if not noask else ''
|
107
112
|
)
|
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()
|