ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
Generators
PowhegControl
python
utility
process_handling.py
Go to the documentation of this file.
1
# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
2
3
from
..
import
Logging
4
from
.non_blocking_stream_reader
import
NonBlockingStreamReader
5
import
subprocess
6
import
re
7
8
9
logger = Logging.logging.getLogger(
"PowhegControl"
)
10
11
12
class
ProcessManager
(object):
13
"""! Wrapper to handle multiple Powheg subprocesses.
14
15
@author James Robinson <james.robinson@cern.ch>
16
"""
17
18
def
__init__
(self, process_list):
19
"""! Constructor.
20
21
@param process_list List of processes to manage.
22
"""
23
self.
__process_list
= process_list
24
self.
__n_initial
= len(process_list)
25
26
def
monitor
(self):
27
"""! Monitor each of the managed processes and log when they are finished."""
28
for
idx, process
in
enumerate(self.
__process_list
):
29
process.id_number = idx + 1
30
while
len(self.
__process_list
) > 0:
31
for
process
in
list(self.
__process_list
):
32
if
not
process.has_output():
33
_return_code = process.return_code
34
self.
__process_list
.remove(process)
35
if
_return_code == 0:
36
logger.info(
"Finished process #{}: there are now {}/{} running"
.format(process.id_number, len(self.
__process_list
), self.
__n_initial
))
37
else
:
38
logger.warning(
"Process #{} terminated unexpectedly (return code {}): there are now {}/{} running"
.format(process.id_number, _return_code, len(self.
__process_list
), self.
__n_initial
))
39
40
41
class
SingleProcessThread
(object):
42
"""! Single executable running in a subprocess (usually PowhegBox).
43
44
@author James Robinson <james.robinson@cern.ch>
45
"""
46
47
log_level = {
"stdout"
:
"info"
,
"stderr"
:
"error"
}
48
__output_prefix =
" | "
49
__ignore_output = []
50
51
def
__init__
(self, command_list, seed_index=None, stdin=None, ignore_output=None, warning_output=[], info_output=[], error_output=[]):
52
"""! Constructor.
53
54
Setup underlying process together with non-blocking readers for stdout and stderr.
55
56
@param command_list Command that will be run (possibly with options).
57
@param seed_index Which seed from pwgseeds.dat to use.
58
@param stdin An open file handle providing input.
59
@param ignore_output List of strings to filter out from messages.
60
@param warning_output List of strings which would always trigger a warning only, even if produced in stderr.
61
@param info_output List of strings which would always trigger an info only, even if produced in stderr.
62
@param error_output List of strings which would always trigger an error, even if produced in stdout.
63
"""
64
if
not
isinstance(command_list, list):
65
command_list = [command_list]
66
command_list = [str(x)
for
x
in
command_list]
67
# Set up messages to ignore
68
if
ignore_output
is
not
None
:
69
self.
__ignore_output
= ignore_output
70
# Set up messages with special treatment
71
self.
__warning_output
= warning_output
72
self.
__info_output
= info_output
73
self.
__error_output
= error_output
74
# Usual case, where no open file handle is provided
75
if
stdin
is
None
:
76
self.
__process
= subprocess.Popen(command_list, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, text=
True
)
77
# Write seed to stdin
78
if
seed_index
is
not
None
:
79
self.
__output_prefix
+=
"Process #{}: "
.format(seed_index)
80
self.
__process
.stdin.write(str(seed_index))
81
self.
__process
.stdin.close()
82
with
open(
"pwgseeds.dat"
,
"r"
)
as
seed_file:
83
random_seed_list = seed_file.read().splitlines()
84
self.
log
(
"Providing random seed: {}"
.format(random_seed_list[seed_index - 1]))
85
# Using an open file handle to provide input to stdin: remember to close this later
86
else
:
87
self.
__process
= subprocess.Popen(command_list, stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.PIPE, text=
True
)
88
# Setup non-blocking stream readers for stdout and stderr
89
self.
__stdout
=
NonBlockingStreamReader
(self.
__process
.stdout)
90
self.
__stderr
=
NonBlockingStreamReader
(self.
__process
.stderr)
91
92
93
94
def
has_output
(self):
95
"""! Write queued output and return process status."""
96
status = self.
is_running
()
97
self.
write_queued_output
()
98
return
status
99
100
def
is_running
(self):
101
"""! Check if the underlying process is running and finalise stream readers if not."""
102
if
self.
__process
.poll()
is
not
None
:
# process has ended
103
for
nbsr
in
(
"stdout"
,
"stderr"
):
104
getattr(self, nbsr).finalise()
105
return
False
106
return
True
107
108
def
log
(self, message, log_level="info"):
109
"""! Write to the logger with appropriate log-level.
110
111
@param message The message to pass to the logger.
112
@param log_level Which level to log at.
113
"""
114
for
word
in
self.
__ignore_output
:
115
while
word
in
message:
116
message = message.replace(word,
""
)
117
getattr(logger, log_level)(
"{}{}"
.format(self.
__output_prefix
, message.strip()))
118
119
def
write_queued_output
(self):
120
"""! Pass queued output to the logger."""
121
float_only = re.compile(
r"^\s*[+-]?\d+\.\d+\s*$"
)
122
for
stream
in
[
"stdout"
,
"stderr"
]:
123
while
True
:
124
output, queue_size = getattr(self, stream).readline(timeout=0.1)
125
if
output
is
not
None
and
float_only.match(output):
126
self.
log
(output,
"info"
)
127
elif
output
is
not
None
and
any([(pattern
in
output)
for
pattern
in
self.
__error_output
]):
128
self.
log
(output,
"error"
)
129
elif
output
is
not
None
and
any([(pattern
in
output)
for
pattern
in
self.
__warning_output
]):
130
self.
log
(output,
"warning"
)
131
elif
output
is
not
None
and
any([(pattern
in
output)
for
pattern
in
self.
__info_output
]):
132
self.
log
(output,
"info"
)
133
elif
not
(output
is
None
or
len(output) == 0):
134
self.
log
(output, self.
log_level
[stream])
135
if
queue_size == 0:
136
break
137
138
@property
139
def
return_code
(self):
140
"""! Return code of underlying process."""
141
return
self.
__process
.returncode
142
143
@property
144
def
stdout
(self):
145
"""! stdout stream from underlying process."""
146
return
self.
__stdout
147
148
@property
149
def
stderr
(self):
150
"""! stderr stream from underlying process."""
151
return
self.
__stderr
python.utility.non_blocking_stream_reader.NonBlockingStreamReader
Read an output stream without blocking.
Definition
non_blocking_stream_reader.py:7
python.utility.process_handling.ProcessManager
Wrapper to handle multiple Powheg subprocesses.
Definition
process_handling.py:12
python.utility.process_handling.ProcessManager.__n_initial
__n_initial
Definition
process_handling.py:24
python.utility.process_handling.ProcessManager.__process_list
__process_list
Definition
process_handling.py:23
python.utility.process_handling.ProcessManager.monitor
monitor(self)
Monitor each of the managed processes and log when they are finished.
Definition
process_handling.py:26
python.utility.process_handling.ProcessManager.__init__
__init__(self, process_list)
Constructor.
Definition
process_handling.py:18
python.utility.process_handling.SingleProcessThread
Single executable running in a subprocess (usually PowhegBox).
Definition
process_handling.py:41
python.utility.process_handling.SingleProcessThread.__init__
__init__(self, command_list, seed_index=None, stdin=None, ignore_output=None, warning_output=[], info_output=[], error_output=[])
Constructor.
Definition
process_handling.py:51
python.utility.process_handling.SingleProcessThread.__info_output
__info_output
Definition
process_handling.py:72
python.utility.process_handling.SingleProcessThread.log
log(self, message, log_level="info")
Write to the logger with appropriate log-level.
Definition
process_handling.py:108
python.utility.process_handling.SingleProcessThread.__ignore_output
list __ignore_output
Definition
process_handling.py:49
python.utility.process_handling.SingleProcessThread.__process
__process
Definition
process_handling.py:76
python.utility.process_handling.SingleProcessThread.__warning_output
__warning_output
Definition
process_handling.py:71
python.utility.process_handling.SingleProcessThread.__stdout
__stdout
Definition
process_handling.py:89
python.utility.process_handling.SingleProcessThread.stdout
stdout(self)
stdout stream from underlying process.
Definition
process_handling.py:144
python.utility.process_handling.SingleProcessThread.has_output
has_output(self)
Write queued output and return process status.
Definition
process_handling.py:94
python.utility.process_handling.SingleProcessThread.__output_prefix
str __output_prefix
Definition
process_handling.py:48
python.utility.process_handling.SingleProcessThread.return_code
return_code(self)
Return code of underlying process.
Definition
process_handling.py:139
python.utility.process_handling.SingleProcessThread.write_queued_output
write_queued_output(self)
Pass queued output to the logger.
Definition
process_handling.py:119
python.utility.process_handling.SingleProcessThread.__error_output
__error_output
Definition
process_handling.py:73
python.utility.process_handling.SingleProcessThread.__stderr
__stderr
Definition
process_handling.py:90
python.utility.process_handling.SingleProcessThread.stderr
stderr(self)
stderr stream from underlying process.
Definition
process_handling.py:149
python.utility.process_handling.SingleProcessThread.log_level
dict log_level
Definition
process_handling.py:47
python.utility.process_handling.SingleProcessThread.is_running
is_running(self)
Check if the underlying process is running and finalise stream readers if not.
Definition
process_handling.py:100
Generated on
for ATLAS Offline Software by
1.17.0