meerschaum 3.0.0rc4__py3-none-any.whl → 3.0.0rc7__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/_parser.py +14 -2
- meerschaum/_internal/cli/__init__.py +6 -0
- meerschaum/_internal/cli/daemons.py +103 -0
- meerschaum/_internal/cli/entry.py +220 -0
- meerschaum/_internal/cli/workers.py +434 -0
- meerschaum/_internal/docs/index.py +1 -2
- meerschaum/_internal/entry.py +44 -8
- meerschaum/_internal/shell/Shell.py +113 -19
- meerschaum/_internal/shell/__init__.py +4 -1
- meerschaum/_internal/static.py +3 -1
- meerschaum/_internal/term/TermPageHandler.py +1 -2
- meerschaum/_internal/term/__init__.py +40 -6
- meerschaum/_internal/term/tools.py +33 -8
- meerschaum/actions/__init__.py +6 -4
- meerschaum/actions/api.py +39 -11
- meerschaum/actions/attach.py +1 -0
- meerschaum/actions/delete.py +4 -2
- meerschaum/actions/edit.py +27 -8
- meerschaum/actions/login.py +8 -8
- meerschaum/actions/register.py +13 -7
- meerschaum/actions/reload.py +22 -5
- meerschaum/actions/restart.py +14 -0
- meerschaum/actions/show.py +69 -4
- meerschaum/actions/start.py +135 -14
- meerschaum/actions/stop.py +36 -3
- meerschaum/actions/sync.py +6 -1
- meerschaum/api/__init__.py +35 -13
- meerschaum/api/_events.py +2 -2
- meerschaum/api/_oauth2.py +47 -4
- meerschaum/api/dash/callbacks/dashboard.py +29 -0
- meerschaum/api/dash/callbacks/jobs.py +3 -2
- meerschaum/api/dash/callbacks/login.py +10 -1
- meerschaum/api/dash/callbacks/register.py +9 -2
- meerschaum/api/dash/pages/login.py +2 -2
- meerschaum/api/dash/pipes.py +72 -36
- meerschaum/api/dash/webterm.py +14 -6
- meerschaum/api/models/_pipes.py +7 -1
- meerschaum/api/resources/static/js/terminado.js +3 -0
- meerschaum/api/resources/static/js/xterm-addon-unicode11.js +2 -0
- meerschaum/api/resources/templates/termpage.html +1 -0
- meerschaum/api/routes/_jobs.py +23 -11
- meerschaum/api/routes/_login.py +73 -5
- meerschaum/api/routes/_pipes.py +6 -4
- meerschaum/api/routes/_webterm.py +3 -3
- meerschaum/config/__init__.py +60 -13
- meerschaum/config/_default.py +89 -61
- meerschaum/config/_edit.py +10 -8
- meerschaum/config/_formatting.py +2 -0
- meerschaum/config/_patch.py +4 -2
- meerschaum/config/_paths.py +127 -12
- meerschaum/config/_read_config.py +20 -10
- meerschaum/config/_version.py +1 -1
- meerschaum/config/environment.py +262 -0
- meerschaum/config/stack/__init__.py +7 -5
- meerschaum/connectors/_Connector.py +1 -2
- meerschaum/connectors/__init__.py +37 -2
- meerschaum/connectors/api/_APIConnector.py +1 -1
- meerschaum/connectors/api/_jobs.py +11 -0
- meerschaum/connectors/api/_pipes.py +7 -1
- meerschaum/connectors/instance/_plugins.py +9 -1
- meerschaum/connectors/instance/_tokens.py +20 -3
- meerschaum/connectors/instance/_users.py +8 -1
- meerschaum/connectors/parse.py +1 -1
- meerschaum/connectors/sql/_create_engine.py +3 -0
- meerschaum/connectors/sql/_pipes.py +93 -79
- meerschaum/connectors/sql/_users.py +8 -1
- meerschaum/connectors/valkey/_ValkeyConnector.py +3 -3
- meerschaum/connectors/valkey/_pipes.py +7 -5
- meerschaum/core/Pipe/__init__.py +45 -71
- meerschaum/core/Pipe/_attributes.py +66 -90
- meerschaum/core/Pipe/_cache.py +555 -0
- meerschaum/core/Pipe/_clear.py +0 -11
- meerschaum/core/Pipe/_data.py +0 -50
- meerschaum/core/Pipe/_deduplicate.py +0 -13
- meerschaum/core/Pipe/_delete.py +12 -21
- meerschaum/core/Pipe/_drop.py +11 -23
- meerschaum/core/Pipe/_dtypes.py +1 -1
- meerschaum/core/Pipe/_index.py +8 -14
- meerschaum/core/Pipe/_sync.py +12 -18
- meerschaum/core/Plugin/_Plugin.py +7 -1
- meerschaum/core/Token/_Token.py +1 -1
- meerschaum/core/User/_User.py +1 -2
- meerschaum/jobs/_Executor.py +88 -4
- meerschaum/jobs/_Job.py +135 -35
- meerschaum/jobs/systemd.py +7 -2
- meerschaum/plugins/__init__.py +277 -81
- meerschaum/utils/daemon/Daemon.py +195 -41
- meerschaum/utils/daemon/FileDescriptorInterceptor.py +0 -1
- meerschaum/utils/daemon/RotatingFile.py +63 -36
- meerschaum/utils/daemon/StdinFile.py +53 -13
- meerschaum/utils/daemon/__init__.py +18 -5
- meerschaum/utils/daemon/_names.py +6 -3
- meerschaum/utils/debug.py +34 -4
- meerschaum/utils/dtypes/__init__.py +5 -1
- meerschaum/utils/formatting/__init__.py +4 -1
- meerschaum/utils/formatting/_jobs.py +1 -1
- meerschaum/utils/formatting/_pipes.py +47 -46
- meerschaum/utils/formatting/_shell.py +16 -6
- meerschaum/utils/misc.py +18 -38
- meerschaum/utils/packages/__init__.py +15 -13
- meerschaum/utils/packages/_packages.py +1 -0
- meerschaum/utils/pipes.py +33 -5
- meerschaum/utils/process.py +1 -1
- meerschaum/utils/prompt.py +171 -144
- meerschaum/utils/sql.py +12 -2
- meerschaum/utils/threading.py +42 -0
- meerschaum/utils/venv/__init__.py +2 -0
- meerschaum/utils/warnings.py +19 -13
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/METADATA +3 -1
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/RECORD +116 -110
- meerschaum/config/_environment.py +0 -145
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/WHEEL +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/entry_points.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/LICENSE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/licenses/NOTICE +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/top_level.txt +0 -0
- {meerschaum-3.0.0rc4.dist-info → meerschaum-3.0.0rc7.dist-info}/zip-safe +0 -0
@@ -13,6 +13,7 @@ import os
|
|
13
13
|
import selectors
|
14
14
|
import traceback
|
15
15
|
|
16
|
+
import meerschaum as mrsm
|
16
17
|
from meerschaum.utils.typing import Optional, Union
|
17
18
|
from meerschaum.utils.warnings import warn
|
18
19
|
|
@@ -25,6 +26,8 @@ class StdinFile(io.TextIOBase):
|
|
25
26
|
self,
|
26
27
|
file_path: Union[pathlib.Path, str],
|
27
28
|
lock_file_path: Optional[pathlib.Path] = None,
|
29
|
+
decode: bool = True,
|
30
|
+
refresh_seconds: Union[int, float, None] = None,
|
28
31
|
):
|
29
32
|
if isinstance(file_path, str):
|
30
33
|
file_path = pathlib.Path(file_path)
|
@@ -38,6 +41,13 @@ class StdinFile(io.TextIOBase):
|
|
38
41
|
self._file_handler = None
|
39
42
|
self._fd = None
|
40
43
|
self.sel = selectors.DefaultSelector()
|
44
|
+
self.decode = decode
|
45
|
+
self._write_fp = None
|
46
|
+
self._refresh_seconds = refresh_seconds
|
47
|
+
|
48
|
+
@property
|
49
|
+
def encoding(self):
|
50
|
+
return 'utf-8'
|
41
51
|
|
42
52
|
@property
|
43
53
|
def file_handler(self):
|
@@ -47,11 +57,9 @@ class StdinFile(io.TextIOBase):
|
|
47
57
|
if self._file_handler is not None:
|
48
58
|
return self._file_handler
|
49
59
|
|
50
|
-
if self.file_path.exists():
|
51
|
-
self.file_path.
|
52
|
-
|
53
|
-
self.file_path.parent.mkdir(parents=True, exist_ok=True)
|
54
|
-
os.mkfifo(self.file_path.as_posix(), mode=0o600)
|
60
|
+
if not self.file_path.exists():
|
61
|
+
self.file_path.parent.mkdir(parents=True, exist_ok=True)
|
62
|
+
os.mkfifo(self.file_path.as_posix(), mode=0o600)
|
55
63
|
|
56
64
|
self._fd = os.open(self.file_path, os.O_RDONLY | os.O_NONBLOCK)
|
57
65
|
self._file_handler = os.fdopen(self._fd, 'rb', buffering=0)
|
@@ -59,11 +67,19 @@ class StdinFile(io.TextIOBase):
|
|
59
67
|
return self._file_handler
|
60
68
|
|
61
69
|
def write(self, data):
|
70
|
+
if self._write_fp is None:
|
71
|
+
self.file_path.parent.mkdir(parents=True, exist_ok=True)
|
72
|
+
if not self.file_path.exists():
|
73
|
+
os.mkfifo(self.file_path.as_posix(), mode=0o600)
|
74
|
+
self._write_fp = open(self.file_path, 'wb')
|
75
|
+
|
62
76
|
if isinstance(data, str):
|
63
77
|
data = data.encode('utf-8')
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
try:
|
79
|
+
self._write_fp.write(data)
|
80
|
+
self._write_fp.flush()
|
81
|
+
except BrokenPipeError:
|
82
|
+
pass
|
67
83
|
|
68
84
|
def fileno(self):
|
69
85
|
fileno = self.file_handler.fileno()
|
@@ -83,18 +99,19 @@ class StdinFile(io.TextIOBase):
|
|
83
99
|
self.blocking_file_path.unlink()
|
84
100
|
except Exception:
|
85
101
|
warn(traceback.format_exc())
|
86
|
-
return data.decode('utf-8')
|
102
|
+
return data.decode('utf-8') if self.decode else data
|
87
103
|
except (OSError, EOFError):
|
88
104
|
pass
|
89
105
|
|
90
|
-
self.blocking_file_path.
|
91
|
-
|
106
|
+
if not self.blocking_file_path.exists():
|
107
|
+
self.blocking_file_path.touch()
|
108
|
+
time.sleep(self.refresh_seconds)
|
92
109
|
|
93
110
|
def readline(self, size=-1):
|
94
|
-
line = ''
|
111
|
+
line = '' if self.decode else b''
|
95
112
|
while True:
|
96
113
|
data = self.read(1)
|
97
|
-
if not data or data == '\n':
|
114
|
+
if not data or ((data == '\n') if self.decode else (data == b'\n')):
|
98
115
|
break
|
99
116
|
line += data
|
100
117
|
|
@@ -111,11 +128,34 @@ class StdinFile(io.TextIOBase):
|
|
111
128
|
self._file_handler = None
|
112
129
|
self._fd = None
|
113
130
|
|
131
|
+
if self._write_fp is not None:
|
132
|
+
try:
|
133
|
+
self._write_fp.close()
|
134
|
+
except BrokenPipeError:
|
135
|
+
pass
|
136
|
+
self._write_fp = None
|
137
|
+
|
138
|
+
try:
|
139
|
+
if self.blocking_file_path.exists():
|
140
|
+
self.blocking_file_path.unlink()
|
141
|
+
except Exception:
|
142
|
+
pass
|
114
143
|
super().close()
|
115
144
|
|
116
145
|
def is_open(self):
|
117
146
|
return self._file_handler is not None
|
118
147
|
|
148
|
+
def isatty(self) -> bool:
|
149
|
+
return False
|
150
|
+
|
151
|
+
@property
|
152
|
+
def refresh_seconds(self) -> Union[int, float]:
|
153
|
+
"""
|
154
|
+
How many seconds between checking for blocking functions.
|
155
|
+
"""
|
156
|
+
if not self._refresh_seconds:
|
157
|
+
self._refresh_seconds = mrsm.get_config('system', 'cli', 'refresh_seconds')
|
158
|
+
return self._refresh_seconds
|
119
159
|
|
120
160
|
def __str__(self) -> str:
|
121
161
|
return f"StdinFile('{self.file_path}')"
|
@@ -16,8 +16,7 @@ import datetime
|
|
16
16
|
import threading
|
17
17
|
import shlex
|
18
18
|
|
19
|
-
from meerschaum.utils.typing import SuccessTuple, List, Optional, Callable, Any, Dict
|
20
|
-
from meerschaum.config._paths import DAEMON_RESOURCES_PATH
|
19
|
+
from meerschaum.utils.typing import SuccessTuple, List, Optional, Callable, Any, Dict, Union
|
21
20
|
from meerschaum.utils.daemon.StdinFile import StdinFile
|
22
21
|
from meerschaum.utils.daemon.Daemon import Daemon
|
23
22
|
from meerschaum.utils.daemon.RotatingFile import RotatingFile
|
@@ -41,9 +40,10 @@ __all__ = (
|
|
41
40
|
'StdinFile',
|
42
41
|
'RotatingFile',
|
43
42
|
'FileDescriptorInterceptor',
|
44
|
-
'DAEMON_RESOURCES_PATH',
|
45
43
|
)
|
46
44
|
|
45
|
+
_daemons = {}
|
46
|
+
|
47
47
|
|
48
48
|
def daemon_entry(sysargs: Optional[List[str]] = None) -> SuccessTuple:
|
49
49
|
"""Parse sysargs and execute a Meerschaum action as a daemon.
|
@@ -211,6 +211,7 @@ def get_daemon_ids() -> List[str]:
|
|
211
211
|
"""
|
212
212
|
Return the IDs of all daemons on disk.
|
213
213
|
"""
|
214
|
+
from meerschaum.config._paths import DAEMON_RESOURCES_PATH
|
214
215
|
return [
|
215
216
|
daemon_dir
|
216
217
|
for daemon_dir in sorted(os.listdir(DAEMON_RESOURCES_PATH))
|
@@ -298,8 +299,6 @@ def get_filtered_daemons(
|
|
298
299
|
if warn:
|
299
300
|
_warn(f"Daemon '{d_id}' does not exist.", stack=False)
|
300
301
|
continue
|
301
|
-
if d.hidden:
|
302
|
-
pass
|
303
302
|
daemons.append(d)
|
304
303
|
return daemons
|
305
304
|
|
@@ -311,3 +310,17 @@ def running_in_daemon() -> bool:
|
|
311
310
|
from meerschaum._internal.static import STATIC_CONFIG
|
312
311
|
daemon_env_var = STATIC_CONFIG['environment']['daemon_id']
|
313
312
|
return daemon_env_var in os.environ
|
313
|
+
|
314
|
+
|
315
|
+
def get_current_daemon() -> Union[Daemon, None]:
|
316
|
+
"""
|
317
|
+
If running withing a daemon context, return the corresponding `Daemon`.
|
318
|
+
Otherwise return `None`.
|
319
|
+
"""
|
320
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
321
|
+
daemon_env_var = STATIC_CONFIG['environment']['daemon_id']
|
322
|
+
daemon_id = os.environ.get(daemon_env_var, None)
|
323
|
+
if daemon_id is None:
|
324
|
+
return None
|
325
|
+
|
326
|
+
return _daemons.get(daemon_id, Daemon(daemon_id=daemon_id))
|
@@ -7,9 +7,11 @@ Generate random names for jobs.
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
import os
|
12
|
+
import random
|
13
|
+
|
14
|
+
from meerschaum.utils.typing import Dict, List
|
13
15
|
|
14
16
|
_bank: Dict[str, Dict[str, List[str]]] = {
|
15
17
|
'adjectives': {
|
@@ -116,6 +118,7 @@ def get_new_daemon_name() -> str:
|
|
116
118
|
Generate a new random name until a unique one is found
|
117
119
|
(up to ~6000 maximum possibilities).
|
118
120
|
"""
|
121
|
+
from meerschaum.config._paths import DAEMON_RESOURCES_PATH
|
119
122
|
existing_names = (
|
120
123
|
os.listdir(DAEMON_RESOURCES_PATH)
|
121
124
|
if DAEMON_RESOURCES_PATH.exists()
|
meerschaum/utils/debug.py
CHANGED
@@ -7,11 +7,31 @@ Functions to handle debug statements
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
|
+
|
11
|
+
from datetime import datetime, timezone
|
12
|
+
import meerschaum as mrsm
|
10
13
|
from meerschaum.utils.typing import Union, Optional, List
|
11
14
|
|
15
|
+
|
16
|
+
_rich_text = None
|
17
|
+
def _import_rich_text_for_dprint():
|
18
|
+
"""
|
19
|
+
Avoid calling `attempt_import()` on every dprint.
|
20
|
+
"""
|
21
|
+
global _rich_text
|
22
|
+
if _rich_text is not None:
|
23
|
+
return _rich_text
|
24
|
+
|
25
|
+
from meerschaum.utils.packages import import_rich, attempt_import
|
26
|
+
_ = import_rich()
|
27
|
+
_rich_text = attempt_import('rich.text', lazy=False)
|
28
|
+
return _rich_text
|
29
|
+
|
30
|
+
|
12
31
|
def dprint(
|
13
32
|
msg: str,
|
14
33
|
leader: bool = True,
|
34
|
+
timestamp: bool = True,
|
15
35
|
package: bool = True,
|
16
36
|
color: Optional[Union[str, List[str]]] = None,
|
17
37
|
attrs: Optional[List[str]] = None,
|
@@ -35,6 +55,12 @@ def dprint(
|
|
35
55
|
else:
|
36
56
|
CHARSET, ANSI, colored, _color, cf = 'ascii', False, None, None, None
|
37
57
|
|
58
|
+
if timestamp:
|
59
|
+
from meerschaum.utils.dtypes import get_current_timestamp
|
60
|
+
now = get_current_timestamp('ms').replace(tzinfo=None)
|
61
|
+
else:
|
62
|
+
now = None
|
63
|
+
|
38
64
|
import logging, sys, inspect
|
39
65
|
logging.basicConfig(format='%(message)s')
|
40
66
|
log = logging.getLogger(__name__)
|
@@ -46,8 +72,13 @@ def dprint(
|
|
46
72
|
parent_package = parent_globals['__name__']
|
47
73
|
msg = str(msg)
|
48
74
|
premsg = ""
|
75
|
+
|
76
|
+
if now:
|
77
|
+
premsg = now.isoformat().split('T', maxsplit=1)[-1][:-3] + (' | ' if package else ':')
|
49
78
|
if package:
|
50
|
-
premsg = parent_package + ':' + str(parent_lineno)
|
79
|
+
premsg = premsg + parent_package + ':' + str(parent_lineno)
|
80
|
+
if premsg:
|
81
|
+
premsg += "\n"
|
51
82
|
if leader and cf is not None:
|
52
83
|
try:
|
53
84
|
debug_leader = cf['formatting']['debug'][CHARSET]['icon'] if cf is not None else ''
|
@@ -75,10 +106,9 @@ def dprint(
|
|
75
106
|
_color = {}
|
76
107
|
if colored is not None:
|
77
108
|
premsg = colored(premsg, **_color)
|
109
|
+
|
78
110
|
if _progress is not None:
|
79
|
-
|
80
|
-
rich = import_rich()
|
81
|
-
rich_text = attempt_import('rich.text')
|
111
|
+
rich_text = _import_rich_text_for_dprint()
|
82
112
|
text = rich_text.Text.from_ansi(premsg + msg)
|
83
113
|
_progress.console.log(text)
|
84
114
|
else:
|
@@ -1054,7 +1054,7 @@ def get_current_timestamp(
|
|
1054
1054
|
return ts_val.as_unit(MRSM_PRECISION_UNITS_ABBREVIATIONS[true_precision_unit])
|
1055
1055
|
|
1056
1056
|
|
1057
|
-
def
|
1057
|
+
def is_dtype_special(type_: str) -> bool:
|
1058
1058
|
"""
|
1059
1059
|
Return whether a dtype should be treated as a special Meerschaum dtype.
|
1060
1060
|
This is not the same as a Meerschaum alias.
|
@@ -1069,6 +1069,7 @@ def dtype_is_special(type_: str) -> bool:
|
|
1069
1069
|
'geometry',
|
1070
1070
|
'geography',
|
1071
1071
|
'date',
|
1072
|
+
'bool',
|
1072
1073
|
):
|
1073
1074
|
return True
|
1074
1075
|
|
@@ -1081,6 +1082,9 @@ def dtype_is_special(type_: str) -> bool:
|
|
1081
1082
|
if true_type.startswith('numeric'):
|
1082
1083
|
return True
|
1083
1084
|
|
1085
|
+
if true_type.startswith('bool'):
|
1086
|
+
return True
|
1087
|
+
|
1084
1088
|
if true_type.startswith('geometry'):
|
1085
1089
|
return True
|
1086
1090
|
|
@@ -209,6 +209,8 @@ def get_console():
|
|
209
209
|
try:
|
210
210
|
console = rich_console.Console(force_terminal=True, color_system='truecolor')
|
211
211
|
except Exception:
|
212
|
+
import traceback
|
213
|
+
traceback.print_exc()
|
212
214
|
console = None
|
213
215
|
return console
|
214
216
|
|
@@ -488,8 +490,9 @@ def fill_ansi(string: str, style: str = '') -> str:
|
|
488
490
|
msg = Text.from_ansi(string)
|
489
491
|
except AttributeError:
|
490
492
|
import traceback
|
491
|
-
traceback.
|
493
|
+
traceback.print_exc()
|
492
494
|
msg = ''
|
495
|
+
|
493
496
|
plain_indices = []
|
494
497
|
for left_span, right_span in iterate_chunks(msg.spans, 2, fillvalue=len(msg)):
|
495
498
|
left = left_span.end
|
@@ -97,7 +97,7 @@ def pprint_jobs(
|
|
97
97
|
msg = '\n'.join(line.lstrip().rstrip() for line in lines)
|
98
98
|
success_tuple = success, msg
|
99
99
|
success_tuple_str = (
|
100
|
-
format_success_tuple(success_tuple, left_padding=
|
100
|
+
format_success_tuple(success_tuple, left_padding=0)
|
101
101
|
if success_tuple is not None
|
102
102
|
else None
|
103
103
|
)
|
@@ -277,18 +277,31 @@ def pprint_pipe_columns(
|
|
277
277
|
|
278
278
|
|
279
279
|
def pipe_repr(
|
280
|
-
pipe: mrsm.Pipe,
|
280
|
+
pipe: Union[mrsm.Pipe, Dict[str, Any]],
|
281
281
|
as_rich_text: bool = False,
|
282
282
|
ansi: Optional[bool] = None,
|
283
283
|
) -> Union[str, 'rich.text.Text']:
|
284
284
|
"""
|
285
285
|
Return a formatted string for representing a `meerschaum.Pipe`.
|
286
286
|
"""
|
287
|
-
from meerschaum.utils.formatting import
|
287
|
+
from meerschaum.utils.formatting import ANSI, colored, rich_text_to_str
|
288
288
|
from meerschaum.utils.packages import import_rich, attempt_import
|
289
|
-
|
289
|
+
import meerschaum as mrsm
|
290
|
+
|
291
|
+
_ = import_rich()
|
290
292
|
Text = attempt_import('rich.text').Text
|
291
293
|
|
294
|
+
if isinstance(pipe, mrsm.Pipe):
|
295
|
+
connector_keys = pipe.connector_keys
|
296
|
+
metric_key = pipe.metric_key
|
297
|
+
location_key = pipe.location_key
|
298
|
+
instance_keys = pipe.instance_keys
|
299
|
+
else:
|
300
|
+
connector_keys = pipe.get('connector_keys')
|
301
|
+
metric_key = pipe.get('metric_key')
|
302
|
+
location_key = pipe.get('location_key')
|
303
|
+
instance_keys = pipe.get('instance_keys', get_config('meerschaum', 'instance'))
|
304
|
+
|
292
305
|
styles = get_config('formatting', 'pipes', '__repr__', 'ansi', 'styles')
|
293
306
|
if not ANSI or (ansi is False):
|
294
307
|
styles = {k: '' for k in styles}
|
@@ -298,26 +311,26 @@ def pipe_repr(
|
|
298
311
|
)
|
299
312
|
text_obj = (
|
300
313
|
Text.from_markup(_pipe_style_prefix + "Pipe(" + _pipe_style_suffix)
|
301
|
-
+ colored(("'" +
|
314
|
+
+ colored(("'" + connector_keys + "'"), style=styles['connector'], as_rich_text=True)
|
302
315
|
+ Text.from_markup(_pipe_style_prefix + ", " + _pipe_style_suffix)
|
303
|
-
+ colored(("'" +
|
316
|
+
+ colored(("'" + metric_key + "'"), style=styles['metric'], as_rich_text=True)
|
304
317
|
+ (
|
305
318
|
(
|
306
319
|
colored(', ', style=styles['punctuation'], as_rich_text=True)
|
307
320
|
+ colored(
|
308
|
-
("'" +
|
321
|
+
("'" + location_key + "'"),
|
309
322
|
style=styles['location'], as_rich_text=True
|
310
323
|
)
|
311
|
-
) if
|
324
|
+
) if location_key is not None
|
312
325
|
else colored('', style='', as_rich_text=True)
|
313
326
|
) + (
|
314
327
|
( ### Add the `instance=` argument.
|
315
328
|
colored(', instance=', style=styles['punctuation'], as_rich_text=True)
|
316
329
|
+ colored(
|
317
|
-
("'" +
|
330
|
+
("'" + instance_keys + "'"),
|
318
331
|
style=styles['instance'], as_rich_text=True
|
319
332
|
)
|
320
|
-
) if
|
333
|
+
) if instance_keys != get_config('meerschaum', 'instance')
|
321
334
|
else colored('', style='', as_rich_text=True)
|
322
335
|
)
|
323
336
|
+ Text.from_markup(_pipe_style_prefix + ")" + _pipe_style_suffix)
|
@@ -327,6 +340,7 @@ def pipe_repr(
|
|
327
340
|
return rich_text_to_str(text_obj).replace('\n', '')
|
328
341
|
|
329
342
|
|
343
|
+
|
330
344
|
def highlight_pipes(message: str) -> str:
|
331
345
|
"""
|
332
346
|
Add syntax highlighting to an info message containing stringified `meerschaum.Pipe` objects.
|
@@ -334,48 +348,35 @@ def highlight_pipes(message: str) -> str:
|
|
334
348
|
if 'Pipe(' not in message:
|
335
349
|
return message
|
336
350
|
|
337
|
-
from meerschaum import
|
351
|
+
from meerschaum.utils.misc import parse_arguments_str
|
338
352
|
segments = message.split('Pipe(')
|
339
353
|
msg = ''
|
340
|
-
_d = {}
|
341
354
|
for i, segment in enumerate(segments):
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
double_quote_index = segment.find('"')
|
346
|
-
|
347
|
-
has_comma = comma_index != -1
|
348
|
-
has_paren = paren_index != -1
|
349
|
-
has_single_quote = single_quote_index != -1
|
350
|
-
has_double_quote = double_quote_index != -1
|
351
|
-
has_quote = has_single_quote or has_double_quote
|
352
|
-
quote_index = (
|
353
|
-
min(single_quote_index, double_quote_index)
|
354
|
-
if has_double_quote and has_single_quote
|
355
|
-
else (single_quote_index if has_single_quote else double_quote_index)
|
356
|
-
)
|
357
|
-
|
358
|
-
has_pipe = (
|
359
|
-
has_comma
|
360
|
-
and
|
361
|
-
has_paren
|
362
|
-
and
|
363
|
-
has_quote
|
364
|
-
and not
|
365
|
-
(comma_index > paren_index or quote_index > paren_index)
|
366
|
-
)
|
355
|
+
if i == 0:
|
356
|
+
msg += segment
|
357
|
+
continue
|
367
358
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
exec(code)
|
372
|
-
_to_add = pipe_repr(_d['pipe']) + segment[paren_index + 1:]
|
373
|
-
_ = _d.pop('pipe', None)
|
374
|
-
except Exception as e:
|
375
|
-
_to_add = 'Pipe(' + segment
|
376
|
-
msg += _to_add
|
359
|
+
paren_index = segment.find(')')
|
360
|
+
if paren_index == -1:
|
361
|
+
msg += 'Pipe(' + segment
|
377
362
|
continue
|
378
|
-
|
363
|
+
|
364
|
+
pipe_args_str = segment[:paren_index]
|
365
|
+
try:
|
366
|
+
args, kwargs = parse_arguments_str(pipe_args_str)
|
367
|
+
pipe_dict = {
|
368
|
+
'connector_keys': args[0],
|
369
|
+
'metric_key': args[1],
|
370
|
+
}
|
371
|
+
if len(args) > 2:
|
372
|
+
pipe_dict['location_key'] = args[2]
|
373
|
+
if 'instance' in kwargs:
|
374
|
+
pipe_dict['instance_keys'] = kwargs['instance']
|
375
|
+
|
376
|
+
_to_add = pipe_repr(pipe_dict) + segment[paren_index + 1:]
|
377
|
+
except Exception:
|
378
|
+
_to_add = 'Pipe(' + segment
|
379
|
+
msg += _to_add
|
379
380
|
return msg
|
380
381
|
|
381
382
|
|
@@ -6,7 +6,6 @@
|
|
6
6
|
Formatting functions for the interactive shell
|
7
7
|
"""
|
8
8
|
|
9
|
-
from re import sub
|
10
9
|
from meerschaum.utils.threading import Lock
|
11
10
|
_locks = {'_tried_clear_command': Lock()}
|
12
11
|
|
@@ -51,28 +50,39 @@ def clear_screen(debug: bool = False) -> bool:
|
|
51
50
|
from meerschaum.utils.debug import dprint
|
52
51
|
from meerschaum.config import get_config
|
53
52
|
from meerschaum.utils.daemon import running_in_daemon
|
53
|
+
from meerschaum._internal.static import STATIC_CONFIG
|
54
54
|
global _tried_clear_command
|
55
|
+
clear_string = '\033[2J'
|
56
|
+
reset_string = '\033[0m'
|
57
|
+
clear_token = STATIC_CONFIG['jobs']['clear_token']
|
55
58
|
|
56
|
-
if
|
59
|
+
if not get_config('shell', 'clear_screen'):
|
57
60
|
return True
|
58
61
|
|
59
|
-
if
|
62
|
+
if running_in_daemon():
|
63
|
+
if debug:
|
64
|
+
dprint("Skip printing clear token.")
|
65
|
+
print('\n', end='', flush=True)
|
66
|
+
return True
|
67
|
+
print(clear_token, flush=True)
|
60
68
|
return True
|
61
69
|
|
70
|
+
|
62
71
|
print("", end="", flush=True)
|
63
72
|
if debug:
|
64
73
|
dprint("Skipping screen clear.")
|
65
74
|
return True
|
75
|
+
|
66
76
|
if ANSI and platform.system() != 'Windows':
|
67
77
|
if get_console() is not None:
|
68
78
|
get_console().clear()
|
69
79
|
print("", end="", flush=True)
|
70
80
|
return True
|
71
|
-
|
72
|
-
reset_string = '\033[0m'
|
81
|
+
|
73
82
|
print(clear_string + reset_string, end="")
|
74
83
|
print("", end="", flush=True)
|
75
84
|
return True
|
85
|
+
|
76
86
|
### ANSI support is disabled, try system level instead
|
77
87
|
if _tried_clear_command is not None:
|
78
88
|
return os.system(_tried_clear_command) == 0
|
@@ -81,7 +91,7 @@ def clear_screen(debug: bool = False) -> bool:
|
|
81
91
|
command = 'clear' if platform.system() != 'Windows' else 'cls'
|
82
92
|
try:
|
83
93
|
rc = os.system(command)
|
84
|
-
except Exception
|
94
|
+
except Exception:
|
85
95
|
pass
|
86
96
|
if rc == 0:
|
87
97
|
with _locks['_tried_clear_command']:
|
meerschaum/utils/misc.py
CHANGED
@@ -6,9 +6,11 @@ Miscellaneous functions go here
|
|
6
6
|
"""
|
7
7
|
|
8
8
|
from __future__ import annotations
|
9
|
+
|
9
10
|
import sys
|
10
11
|
import functools
|
11
|
-
from datetime import timedelta, datetime
|
12
|
+
from datetime import timedelta, datetime
|
13
|
+
|
12
14
|
from meerschaum.utils.typing import (
|
13
15
|
Union,
|
14
16
|
Any,
|
@@ -20,13 +22,8 @@ from meerschaum.utils.typing import (
|
|
20
22
|
Iterable,
|
21
23
|
PipesDict,
|
22
24
|
Tuple,
|
23
|
-
InstanceConnector,
|
24
|
-
Hashable,
|
25
|
-
Generator,
|
26
|
-
Iterator,
|
27
25
|
TYPE_CHECKING,
|
28
26
|
)
|
29
|
-
import meerschaum as mrsm
|
30
27
|
if TYPE_CHECKING:
|
31
28
|
import collections
|
32
29
|
|
@@ -43,6 +40,9 @@ __pdoc__: Dict[str, bool] = {
|
|
43
40
|
'df_is_chunk_generator': False,
|
44
41
|
'choices_docstring': False,
|
45
42
|
'_get_subaction_names': False,
|
43
|
+
'is_pipe_registered': False,
|
44
|
+
'replace_pipes_in_dict': False,
|
45
|
+
'round_time': False,
|
46
46
|
}
|
47
47
|
|
48
48
|
|
@@ -347,37 +347,6 @@ def edit_file(
|
|
347
347
|
return rc == 0
|
348
348
|
|
349
349
|
|
350
|
-
def is_pipe_registered(
|
351
|
-
pipe: mrsm.Pipe,
|
352
|
-
pipes: PipesDict,
|
353
|
-
debug: bool = False
|
354
|
-
) -> bool:
|
355
|
-
"""
|
356
|
-
Check if a Pipe is inside the pipes dictionary.
|
357
|
-
|
358
|
-
Parameters
|
359
|
-
----------
|
360
|
-
pipe: meerschaum.Pipe
|
361
|
-
The pipe to see if it's in the dictionary.
|
362
|
-
|
363
|
-
pipes: PipesDict
|
364
|
-
The dictionary to search inside.
|
365
|
-
|
366
|
-
debug: bool, default False
|
367
|
-
Verbosity toggle.
|
368
|
-
|
369
|
-
Returns
|
370
|
-
-------
|
371
|
-
A bool indicating whether the pipe is inside the dictionary.
|
372
|
-
"""
|
373
|
-
from meerschaum.utils.debug import dprint
|
374
|
-
ck, mk, lk = pipe.connector_keys, pipe.metric_key, pipe.location_key
|
375
|
-
if debug:
|
376
|
-
dprint(f'{ck}, {mk}, {lk}')
|
377
|
-
dprint(f'{pipe}, {pipes}')
|
378
|
-
return ck in pipes and mk in pipes[ck] and lk in pipes[ck][mk]
|
379
|
-
|
380
|
-
|
381
350
|
def get_cols_lines(default_cols: int = 100, default_lines: int = 120) -> Tuple[int, int]:
|
382
351
|
"""
|
383
352
|
Determine the columns and lines in the terminal.
|
@@ -1263,11 +1232,13 @@ def is_systemd_available() -> bool:
|
|
1263
1232
|
import subprocess
|
1264
1233
|
try:
|
1265
1234
|
has_systemctl = subprocess.call(
|
1266
|
-
['systemctl', '
|
1235
|
+
['systemctl', 'whoami'],
|
1267
1236
|
stdout=subprocess.DEVNULL,
|
1268
1237
|
stderr=subprocess.STDOUT,
|
1269
1238
|
) == 0
|
1270
1239
|
except Exception:
|
1240
|
+
import traceback
|
1241
|
+
traceback.print_exc()
|
1271
1242
|
has_systemctl = False
|
1272
1243
|
return has_systemctl
|
1273
1244
|
|
@@ -1844,6 +1815,15 @@ def replace_pipes_in_dict(*args, **kwargs):
|
|
1844
1815
|
return replace_pipes_in_dict(*args, **kwargs)
|
1845
1816
|
|
1846
1817
|
|
1818
|
+
def is_pipe_registered(*args, **kwargs):
|
1819
|
+
"""
|
1820
|
+
Placeholder function to prevent breaking legacy behavior.
|
1821
|
+
See `meerschaum.utils.pipes.is_pipe_registered`.
|
1822
|
+
"""
|
1823
|
+
from meerschaum.utils.pipes import is_pipe_registered
|
1824
|
+
return is_pipe_registered(*args, **kwargs)
|
1825
|
+
|
1826
|
+
|
1847
1827
|
def round_time(*args, **kwargs):
|
1848
1828
|
"""
|
1849
1829
|
Placeholder function to prevent breaking legacy behavior.
|