mccode-plumber 0.16.0__py3-none-any.whl → 0.17.0__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.
- mccode_plumber/manage/manager.py +80 -3
- mccode_plumber/manage/orchestrate.py +8 -1
- mccode_plumber/splitrun.py +16 -4
- {mccode_plumber-0.16.0.dist-info → mccode_plumber-0.17.0.dist-info}/METADATA +3 -3
- {mccode_plumber-0.16.0.dist-info → mccode_plumber-0.17.0.dist-info}/RECORD +8 -8
- {mccode_plumber-0.16.0.dist-info → mccode_plumber-0.17.0.dist-info}/WHEEL +1 -1
- {mccode_plumber-0.16.0.dist-info → mccode_plumber-0.17.0.dist-info}/entry_points.txt +0 -0
- {mccode_plumber-0.16.0.dist-info → mccode_plumber-0.17.0.dist-info}/top_level.txt +0 -0
mccode_plumber/manage/manager.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
3
|
from subprocess import Popen, PIPE
|
|
4
4
|
from threading import Thread
|
|
5
5
|
from enum import Enum
|
|
@@ -12,6 +12,54 @@ class IOType(Enum):
|
|
|
12
12
|
stderr = 2
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
@dataclass
|
|
16
|
+
class Triage:
|
|
17
|
+
level: str = field(default=lambda: 'info')
|
|
18
|
+
ignore: list[str] = field(default_factory=list)
|
|
19
|
+
patterns: dict[str, list[str]] = field(default_factory=lambda: {
|
|
20
|
+
'critical': [r'\bcritical\b', r'^cri'],
|
|
21
|
+
'error': [r'\berror\b', r'exception', r'traceback', r'^err' ],
|
|
22
|
+
'warning': [r'\bwarn(ing)?\b', r'deprecated', r'^war'],
|
|
23
|
+
'notice': [r'\bnotice\b', r'^not'],
|
|
24
|
+
'info': [r'\binfo\b', r'starting', r'done'],
|
|
25
|
+
'hint': [r'\bhint\b'],
|
|
26
|
+
'debug': [r'\bdebug\b', r'^deb', r'^dbg'],
|
|
27
|
+
})
|
|
28
|
+
styles: dict[str, str] = field(default_factory=lambda: {
|
|
29
|
+
'critical': Fore.MAGENTA + Style.BRIGHT,
|
|
30
|
+
'error': Fore.RED + Style.BRIGHT,
|
|
31
|
+
'warning': Fore.YELLOW + Style.BRIGHT,
|
|
32
|
+
'notice': Fore.CYAN + Style.BRIGHT,
|
|
33
|
+
'info': Fore.GREEN,
|
|
34
|
+
'hint': Fore.BLUE,
|
|
35
|
+
'debug': Fore.WHITE + Style.BRIGHT,
|
|
36
|
+
'default': Fore.WHITE,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
def _filtered_level(self, level: str) -> bool:
|
|
40
|
+
def _level_value(v: str):
|
|
41
|
+
for i, lvl in enumerate(self.patterns.keys()):
|
|
42
|
+
if v == lvl:
|
|
43
|
+
return i
|
|
44
|
+
return -1
|
|
45
|
+
return _level_value(level) > _level_value(self.level)
|
|
46
|
+
|
|
47
|
+
def _style_line(self, level: str, line: str):
|
|
48
|
+
return self.styles.get(level, '') + line + Style.RESET_ALL
|
|
49
|
+
|
|
50
|
+
def __call__(self, line: str) -> tuple[bool, str | None]:
|
|
51
|
+
import re
|
|
52
|
+
# If the line contains an ignored keyword, ignore it.
|
|
53
|
+
if any(kw in line for kw in self.ignore):
|
|
54
|
+
return True, None
|
|
55
|
+
# Check if we can identify the status level of this message
|
|
56
|
+
for level, patterns in self.patterns.items():
|
|
57
|
+
for pattern in patterns:
|
|
58
|
+
if re.search(pattern, line, re.IGNORECASE):
|
|
59
|
+
return self._filtered_level(level), self._style_line(level, line)
|
|
60
|
+
return self._filtered_level('default'), self._style_line('default', line)
|
|
61
|
+
|
|
62
|
+
|
|
15
63
|
@dataclass
|
|
16
64
|
class Manager:
|
|
17
65
|
"""
|
|
@@ -19,13 +67,24 @@ class Manager:
|
|
|
19
67
|
|
|
20
68
|
Properties
|
|
21
69
|
----------
|
|
70
|
+
name: str
|
|
71
|
+
The name of the process, used as a prefix for all printed status messages
|
|
72
|
+
style: AnsiStyle
|
|
73
|
+
Format string to style the printed process name
|
|
74
|
+
_triage: Triage
|
|
75
|
+
An object to filter status messages and identify severity levels
|
|
76
|
+
applying its own message styling based on the identified level
|
|
22
77
|
_process: a subprocess.Popen instance
|
|
78
|
+
_stdout_thread: Thread
|
|
79
|
+
_stderr_thread: Thread
|
|
23
80
|
"""
|
|
24
81
|
name: str
|
|
25
82
|
style: AnsiStyle
|
|
83
|
+
triage: Triage
|
|
26
84
|
_process: Popen | None
|
|
27
85
|
_stdout_thread: Thread | None
|
|
28
86
|
_stderr_thread: Thread | None
|
|
87
|
+
_name_padding: int
|
|
29
88
|
|
|
30
89
|
def __run_command__(self) -> list[str]:
|
|
31
90
|
return []
|
|
@@ -38,6 +97,18 @@ class Manager:
|
|
|
38
97
|
from dataclasses import fields
|
|
39
98
|
return [field.name for field in fields(cls)]
|
|
40
99
|
|
|
100
|
+
@property
|
|
101
|
+
def name_padding(self):
|
|
102
|
+
return self._name_padding
|
|
103
|
+
|
|
104
|
+
@name_padding.setter
|
|
105
|
+
def name_padding(self, value: int):
|
|
106
|
+
self._name_padding = value
|
|
107
|
+
|
|
108
|
+
def _pretty_name(self):
|
|
109
|
+
padding = ' ' * self.name_padding
|
|
110
|
+
return f'{self.style}{self.name}:{Style.RESET_ALL}{padding}'
|
|
111
|
+
|
|
41
112
|
def _read_stream(self, stream, io_type: IOType):
|
|
42
113
|
"""Read lines from stream and print them until EOF.
|
|
43
114
|
|
|
@@ -51,8 +122,10 @@ class Manager:
|
|
|
51
122
|
for line in iter(stream.readline, ''):
|
|
52
123
|
if not line:
|
|
53
124
|
break
|
|
54
|
-
|
|
55
|
-
|
|
125
|
+
ignored, line = self.triage(line)
|
|
126
|
+
if ignored:
|
|
127
|
+
continue
|
|
128
|
+
formatted = f'{self._pretty_name()} {line}'
|
|
56
129
|
if io_type == IOType.stdout:
|
|
57
130
|
print(formatted, end='')
|
|
58
131
|
else:
|
|
@@ -79,6 +152,10 @@ class Manager:
|
|
|
79
152
|
kwargs['name'] = 'Managed process'
|
|
80
153
|
if 'style' not in kwargs:
|
|
81
154
|
kwargs['style'] = Fore.WHITE + Back.BLACK
|
|
155
|
+
if 'triage' not in kwargs:
|
|
156
|
+
kwargs['triage'] = Triage()
|
|
157
|
+
if '_name_padding' not in kwargs:
|
|
158
|
+
kwargs['_name_padding'] = 0
|
|
82
159
|
|
|
83
160
|
manager = cls(**kwargs)
|
|
84
161
|
|
|
@@ -261,6 +261,7 @@ def load_in_wait_load_out(
|
|
|
261
261
|
)
|
|
262
262
|
from mccode_plumber.manage.forwarder import forwarder_verbosity
|
|
263
263
|
from mccode_plumber.manage.writer import writer_verbosity
|
|
264
|
+
from mccode_plumber.manage.manager import Triage
|
|
264
265
|
|
|
265
266
|
# Start up services if they should be managed locally
|
|
266
267
|
if manage:
|
|
@@ -283,7 +284,10 @@ def load_in_wait_load_out(
|
|
|
283
284
|
efu = [EventFormationUnitConfig.from_dict(data)]
|
|
284
285
|
things = tuple(
|
|
285
286
|
EventFormationUnit.start(
|
|
286
|
-
style=Fore.BLUE,
|
|
287
|
+
style=Fore.BLUE,
|
|
288
|
+
broker=broker,
|
|
289
|
+
triage=Triage(ignore=["graphite", ":2003 failed"]),
|
|
290
|
+
**x.to_dict()
|
|
287
291
|
) for x in efu) + (
|
|
288
292
|
Forwarder.start(
|
|
289
293
|
name='FWD',
|
|
@@ -309,6 +313,9 @@ def load_in_wait_load_out(
|
|
|
309
313
|
verbosity=writer_verbosity(verbosity_writer),
|
|
310
314
|
),
|
|
311
315
|
)
|
|
316
|
+
longest_name = max(len(thing.name) for thing in things)
|
|
317
|
+
for thing in things:
|
|
318
|
+
thing.name_padding = longest_name - len(thing.name)
|
|
312
319
|
else:
|
|
313
320
|
things = ()
|
|
314
321
|
|
mccode_plumber/splitrun.py
CHANGED
|
@@ -17,11 +17,15 @@ def make_parser():
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def monitors_to_kafka_callback_with_arguments(
|
|
20
|
-
broker: str, topic: str | None, source: str | None, names: list[str] | None
|
|
20
|
+
broker: str, topic: str | None, source: str | None, names: list[str] | None,
|
|
21
|
+
delete_after_sending: bool = True,
|
|
21
22
|
):
|
|
22
23
|
from mccode_to_kafka.sender import send_histograms
|
|
23
24
|
|
|
24
|
-
partial_kwargs: dict[str, Union[str,list[str]]] = {
|
|
25
|
+
partial_kwargs: dict[str, Union[str,list[str]]] = {
|
|
26
|
+
'broker': broker,
|
|
27
|
+
'delete': delete_after_sending,
|
|
28
|
+
}
|
|
25
29
|
if topic is not None and source is not None and names is not None and len(names) > 1:
|
|
26
30
|
raise ValueError("Cannot specify both topic/source and multiple names simultaneously.")
|
|
27
31
|
|
|
@@ -41,7 +45,15 @@ def monitors_to_kafka_callback_with_arguments(
|
|
|
41
45
|
def main():
|
|
42
46
|
from .mccode import get_mcstas_instr
|
|
43
47
|
from restage.splitrun import splitrun_args, parse_splitrun
|
|
44
|
-
|
|
48
|
+
parser = make_parser()
|
|
49
|
+
parser.add_argument('--keep-after-send', action='store_true', help='Keep after sending histograms', default=False)
|
|
50
|
+
args, parameters, precision = parse_splitrun(parser)
|
|
45
51
|
instr = get_mcstas_instr(args.instrument)
|
|
46
|
-
callback, callback_args = monitors_to_kafka_callback_with_arguments(
|
|
52
|
+
callback, callback_args = monitors_to_kafka_callback_with_arguments(
|
|
53
|
+
broker=args.broker,
|
|
54
|
+
topic=args.topic,
|
|
55
|
+
source=args.source,
|
|
56
|
+
names=args.names,
|
|
57
|
+
delete_after_sending=not args.keep_after_send
|
|
58
|
+
)
|
|
47
59
|
return splitrun_args(instr, parameters, precision, args, callback=callback, callback_arguments=callback_args)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mccode-plumber
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.0
|
|
4
4
|
Author-email: Gregory Tucker <gregory.tucker@ess.eu>
|
|
5
5
|
Classifier: License :: OSI Approved :: BSD License
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -13,8 +13,8 @@ Requires-Dist: p4p
|
|
|
13
13
|
Requires-Dist: kafka-python>=2.2.11
|
|
14
14
|
Requires-Dist: ess-streaming-data-types>=0.14.0
|
|
15
15
|
Requires-Dist: restage>=0.10.1
|
|
16
|
-
Requires-Dist: mccode-to-kafka>=0.
|
|
17
|
-
Requires-Dist: moreniius>=0.
|
|
16
|
+
Requires-Dist: mccode-to-kafka>=0.5.0
|
|
17
|
+
Requires-Dist: moreniius>=0.7.0
|
|
18
18
|
Requires-Dist: icecream
|
|
19
19
|
Requires-Dist: ephemeral-port-reserve
|
|
20
20
|
Provides-Extra: test
|
|
@@ -5,7 +5,7 @@ mccode_plumber/epics_watcher.py,sha256=Jiz761A5NfoUzJ6ZzBGg8_BewFTmHDo5qYgh_DZHx
|
|
|
5
5
|
mccode_plumber/forwarder.py,sha256=Nccjof4GydaZLFyk_Ij9xBXy8QUpGigOV6lOPGw0PAQ,4513
|
|
6
6
|
mccode_plumber/kafka.py,sha256=1BVTsGmiFJPkl-5RVJbkLm68AKRCp2NyngPjMcSutBs,2501
|
|
7
7
|
mccode_plumber/mccode.py,sha256=vc4Gb5WhdOfuDRjEejU3Flps0C2A60sfFbMrxmKLhn0,2189
|
|
8
|
-
mccode_plumber/splitrun.py,sha256=
|
|
8
|
+
mccode_plumber/splitrun.py,sha256=kJShCw1Cd_QawAeHooxa79XimtslLeWxeuJ3W4clsKk,2424
|
|
9
9
|
mccode_plumber/utils.py,sha256=E8NoGo_3Z-pPEpzicVGSWfQOX8p3eR-GxElT33-kX5U,2167
|
|
10
10
|
mccode_plumber/writer.py,sha256=uNU1nICANNbB-gTa2WKptfls6tzmoHkUIdzmIeaFWXE,21569
|
|
11
11
|
mccode_plumber/file_writer_control/CommandChannel.py,sha256=Ge5O71tZqpPmgcyYVcQe6XnxkE9r71Tf3he1ndvOFlQ,9038
|
|
@@ -26,11 +26,11 @@ mccode_plumber/manage/efu.py,sha256=y4V-LBQ9Xt5YATEfW0XkZ9KcPGo230-5BIemthSaMD8,
|
|
|
26
26
|
mccode_plumber/manage/ensure.py,sha256=rS1kjUGhbks42_jsAZ2GjnhzJmpYqn59h6y3HJgshLs,3166
|
|
27
27
|
mccode_plumber/manage/epics.py,sha256=oQt_hL-7KgtI9Kmwyw8L7a7RxQe7YJWRbmHnKIqMLpQ,1310
|
|
28
28
|
mccode_plumber/manage/forwarder.py,sha256=stDKEVVfepCOqs5vBCVepaO3d63KJT-6okxooIl9dGs,3136
|
|
29
|
-
mccode_plumber/manage/manager.py,sha256=
|
|
30
|
-
mccode_plumber/manage/orchestrate.py,sha256=
|
|
29
|
+
mccode_plumber/manage/manager.py,sha256=oQal8gmVqWy2Qd9BjTRZEliRkRzWjZbG6wtPD3__EX0,6762
|
|
30
|
+
mccode_plumber/manage/orchestrate.py,sha256=knODbPBgSZNSCCpBjqc6yiSivWQGQMMLHidShVu-aCc,18323
|
|
31
31
|
mccode_plumber/manage/writer.py,sha256=SEv1U14L01Y9-BcaJKPei4Ah2LFfwexDy9FTjpvtSEs,2245
|
|
32
|
-
mccode_plumber-0.
|
|
33
|
-
mccode_plumber-0.
|
|
34
|
-
mccode_plumber-0.
|
|
35
|
-
mccode_plumber-0.
|
|
36
|
-
mccode_plumber-0.
|
|
32
|
+
mccode_plumber-0.17.0.dist-info/METADATA,sha256=0erkj44mHc3c9oyNUArbp16YA2BOaWfLMAcn6Pyr8Qk,957
|
|
33
|
+
mccode_plumber-0.17.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
34
|
+
mccode_plumber-0.17.0.dist-info/entry_points.txt,sha256=k3LDo_9HG2v4-IgMYlNukphdMmaAT6zkJZYaB1zJh3c,900
|
|
35
|
+
mccode_plumber-0.17.0.dist-info/top_level.txt,sha256=kCCIpYtKHCKWxiPEqX9J1UaGEm-ze0Qb-cemBCEPhDA,15
|
|
36
|
+
mccode_plumber-0.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|