3 from AthenaCommon
import Logging
4 from .non_blocking_stream_reader
import NonBlockingStreamReader
8 logger = Logging.logging.getLogger(
"PowhegControl")
12 """! Wrapper to handle multiple Powheg subprocesses.
14 @author James Robinson <james.robinson@cern.ch>
20 @param process_list List of processes to manage.
26 """! Monitor each of the managed processes and log when they are finished."""
28 process.id_number = idx + 1
31 if not process.has_output():
32 _return_code = process.return_code
37 logger.warning(
"Process #{} terminated unexpectedly (return code {}): there are now {}/{} running".
format(process.id_number, _return_code, len(self.
__process_list), self.
__n_initial))
41 """! Single executable running in a subprocess (usually PowhegBox).
43 @author James Robinson <james.robinson@cern.ch>
46 log_level = {
"stdout":
"info",
"stderr":
"error"}
47 __output_prefix =
" | "
50 def __init__(self, command_list, seed_index=None, stdin=None, ignore_output=None, warning_output=[], info_output=[], error_output=[]):
53 Setup underlying process together with non-blocking readers for stdout and stderr.
55 @param command_list Command that will be run (possibly with options).
56 @param seed_index Which seed from pwgseeds.dat to use.
57 @param stdin An open file handle providing input.
58 @param ignore_output List of strings to filter out from messages.
59 @param warning_output List of strings which would always trigger a warning only, even if produced in stderr.
60 @param info_output List of strings which would always trigger an info only, even if produced in stderr.
61 @param error_output List of strings which would always trigger an error, even if produced in stdout.
63 if not isinstance(command_list, list):
64 command_list = [command_list]
65 command_list = [
str(x)
for x
in command_list]
67 if ignore_output
is not None:
75 self.
__process = subprocess.Popen(command_list, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, text=
True)
77 if seed_index
is not None:
81 with open(
"pwgseeds.dat",
"r")
as seed_file:
82 random_seed_list = seed_file.read().splitlines()
83 self.
log(
"Providing random seed: {}".
format(random_seed_list[seed_index - 1]))
86 self.
__process = subprocess.Popen(command_list, stdout=subprocess.PIPE, stdin=stdin, stderr=subprocess.PIPE, text=
True)
94 """! Write queued output and return process status."""
100 """! Check if the underlying process is running and finalise stream readers if not."""
102 for nbsr
in (
"stdout",
"stderr"):
103 getattr(self, nbsr).finalise()
107 def log(self, message, log_level="info"):
108 """! Write to the logger with appropriate log-level.
110 @param message The message to pass to the logger.
111 @param log_level Which level to log at.
114 while word
in message:
115 message = message.replace(word,
"")
119 """! Pass queued output to the logger."""
120 for stream
in [
"stdout",
"stderr"]:
122 output, queue_size = getattr(self, stream).readline(timeout=0.1)
123 if output
is not None and any([(pattern
in output)
for pattern
in self.
__error_output]):
124 self.
log(output,
"error")
125 elif output
is not None and any([(pattern
in output)
for pattern
in self.
__warning_output]):
126 self.
log(output,
"warning")
127 elif output
is not None and any([(pattern
in output)
for pattern
in self.
__info_output]):
128 self.
log(output,
"info")
129 elif not (output
is None or len(output) == 0):
136 """! Return code of underlying process."""
141 """! stdout stream from underlying process."""
146 """! stderr stream from underlying process."""