HPS-MC
 
Loading...
Searching...
No Matches
component.py
Go to the documentation of this file.
1"""!
2@package component
3Defines the base interface that component classes should extend.
4"""
5
6import os
7import sys
8import subprocess
9import logging
10
11from ._config import convert_config_value
12from hpsmc import global_config
13
14
15class Component(object):
16 """!
17 Base class for components in a job.
18
19 Do not perform any logging in the init method of Component subclasses,
20 as this is not configured by the job manager until after the components
21 are created.
22
23 Optional parameters are: **nevents**, **seed**
24
25 @param name name of the component
26 @param command command to execute
27 @param nevents number of events to process
28 @param seed random seed
29 @param inputs list of input files
30 @param outputs list of output files
31 @param append_tok token to append to output file names
32 @param output_ext extension to append to output file names; format is .ext
33 @param ignore_job_params list of parameters to ignore when setting parameters
34 @param kwargs additional keyword arguments
35 """
36
38 self,
39 name,
40 command=None,
41 nevents=None,
42 seed=1,
43 inputs=[],
44 outputs=None,
45 append_tok=None,
46 output_ext=None,
47 ignore_job_params=[],
48 **kwargs
49 ):
50
51 self.name = name
52 self.command = command
53 self.nevents = nevents
54 self.seed = seed
55 self.inputs = inputs
56 self.outputs = outputs
57 self.append_tok = append_tok
58 self.output_ext = output_ext
59
60
61 self.ignore_job_params = ignore_job_params
62
63 self.hpsmc_dir = os.getenv("HPSMC_DIR", None)
64 if self.hpsmc_dir is None:
65 raise Exception("The HPSMC_DIR is not set!")
66
67 # Setup a logger specifically for this component. It will be configured later.
68 self.logger = logging.getLogger(
69 "{}.{}".format(__name__, self.__class__.__name__)
70 )
71
72 def cmd_line_str(self):
73 cl = []
74 if self.command:
75 cl.append(self.command)
76 cl.extend(self.cmd_args())
77 return " ".join(cl)
78
79 def execute(self, log_out=sys.stdout, log_err=sys.stderr):
80 """! Generic component execution method.
81
82 Individual components may override this if specific behavior is required.
83
84 @param log_out name of log file for output
85 @param log_err name of log file for error
86 @return error code
87 """
88 proc = subprocess.Popen(
89 self.cmd_line_str(), shell=True, stdout=log_out, stderr=log_err
90 )
91 proc.communicate()
92 proc.wait()
93
94 return proc.returncode
95
96 def cmd_exists(self):
97 """! Check if the component's assigned command exists."""
98 return (
99 subprocess.call(
100 "type " + self.command,
101 shell=True,
102 stdout=subprocess.PIPE,
103 stderr=subprocess.PIPE,
104 )
105 == 0
106 )
107
108 def cmd_args(self):
109 """! Return the command arguments of this component."""
110 return []
111
112 def cmd_args_str(self):
113 """! Return list of arguments, making sure they are all converted to strings."""
114 return [str(c) for c in self.cmd_args()]
115
116 def setup(self):
117 """! Perform any necessary setup for this component to run such as making symlinks
118 to required directories.
119 """
120 pass
121
122 def cleanup(self):
123 """! Perform post-job cleanup such as deleting temporary files."""
124 pass
125
126 def config_logging(self, parser):
127 """!
128 Configure the logging for a component.
129
130 @param parser the ConfigParser object passed from the job manager
131 """
132 classname = self.__class__.__name__
133 if classname in parser:
134 if "loglevel" in parser[classname]:
135 loglevel = logging.getLevelName(parser[classname]["loglevel"])
136 self.logger.setLevel(loglevel)
137
138 def config(self, parser):
139 """! Automatic configuration
140
141 Automatically load attributes from config by reading in values from
142 the section with the same name as the class in the config file and
143 assigning them to class attributes with the same name.
144
145 @param parser config parser
146 """
147 section_name = self.__class__.__name__
148 if parser.has_section(section_name):
149 for name, value in parser.items(section_name):
150 setattr(self, name, convert_config_value(value))
151 self.logger.debug(
152 "%s:%s:%s=%s"
153 % (
154 self.name,
155 name,
156 getattr(self, name).__class__.__name__,
157 getattr(self, name),
158 )
159 )
160
161 def set_parameters(self, params):
162 """! Set class attributes for the component based on JSON parameters.
163
164 Components should not need to override this method.
165
166 @param params parameters to setup component
167 """
168
169 # Set required parameters.
170 for p in self.required_parameters():
171 if p not in params:
172 raise Exception(
173 "Required parameter '%s' is missing for component '%s'"
174 % (p, self.name)
175 )
176 else:
177 if p not in self.ignore_job_params:
178 setattr(self, p, params[p])
179 self.logger.debug("%s:%s=%s [required]" % (self.name, p, params[p]))
180 else:
181 self.logger.debug("Ignored job param '%s'" % p)
182
183 # Set optional parameters.
184 for p in self.optional_parameters():
185 if p in params:
186 if p not in self.ignore_job_params:
187 setattr(self, p, params[p])
188 self.logger.debug("%s:%s=%s [optional]" % (self.name, p, params[p]))
189 else:
190 self.logger.debug("Ignored job param '%s'" % p)
191
193 """!
194 Return a list of required parameters.
195
196 The job will fail if these are not present in the JSON file.
197 """
198 return []
199
201 """!
202 Return a list of optional parameters.
203
204 Optional parameters are: **nevents**, **seed**
205 """
206 return ["nevents", "seed"]
207
209 """!
210 Return a list of required configuration settings.
211
212 There are none by default.
213 """
214 return []
215
216 def check_config(self):
217 """! Raise an exception on the first missing config setting for this component."""
218 for c in self.required_config():
219 if not hasattr(self, c):
220 raise Exception(
221 "Missing required config attribute: %s:%s"
222 % (self.__class__.__name__, c)
223 )
224 if getattr(self, c) is None:
225 raise Exception(
226 "Config was not set: %s:%s" % (self.__class__.__name__, c)
227 )
228
229 def input_files(self):
230 """! Get a list of input files for this component."""
231 return self.inputs
232
233 def output_files(self):
234 """! Return a list of output files created by this component.
235
236 By default, a series of transformations will be performed on inputs to
237 transform them into outputs.
238 """
239 if self.outputs is not None and len(self.outputs):
240 return self.outputs
241 else:
242 return self._inputs_to_outputs()
243
245 """! This is the default method for automatically transforming input file names
246 to outputs when output file names are not explicitly provided.
247 """
248 outputs = []
249 for infile in self.input_files():
250 f, ext = os.path.splitext(infile)
251 if self.append_tok is not None:
252 f += "_%s" % self.append_tok
253 if self.output_ext is not None:
254 ext = self.output_ext
255 outputs.append("%s%s" % (f, ext))
256 return outputs
257
259 """! Configure component from environment variables which are just upper case
260 versions of the required config names set in the shell environment."""
261 for c in self.required_config():
262 self.logger.debug("Setting config '%s' from environ" % c)
263 if c.upper() in os.environ:
264 setattr(self, c, os.environ[c.upper()])
265 self.logger.debug(
266 "Set config '%s=%s' from env var '%s'"
267 % (c, getattr(self, c), c.upper())
268 )
269 else:
270 raise Exception("Missing config in environ for '%s'" % c)
271
272
274 """! A dummy component that just prints some information instead of executing a program."""
275
276 def __init__(self, **kwargs):
277 Component.__init__(self, "dummy", "dummy", **kwargs)
278
279 def execute(self, log_out=sys.stdout, log_err=sys.stderr):
280 self.logger.debug("dummy debug")
281 self.logger.info("dummy info")
282 self.logger.warning("dummy warn")
283 self.logger.critical("dummy critical")
284 self.logger.error("dummy error")
Base class for components in a job.
Definition component.py:15
output_files(self)
Return a list of output files created by this component.
Definition component.py:233
execute(self, log_out=sys.stdout, log_err=sys.stderr)
Generic component execution method.
Definition component.py:79
optional_parameters(self)
Return a list of optional parameters.
Definition component.py:200
cleanup(self)
Perform post-job cleanup such as deleting temporary files.
Definition component.py:122
config_logging(self, parser)
Configure the logging for a component.
Definition component.py:126
config_from_environ(self)
Configure component from environment variables which are just upper case versions of the required con...
Definition component.py:258
cmd_args_str(self)
Return list of arguments, making sure they are all converted to strings.
Definition component.py:112
required_parameters(self)
Return a list of required parameters.
Definition component.py:192
setup(self)
Perform any necessary setup for this component to run such as making symlinks to required directories...
Definition component.py:116
cmd_exists(self)
Check if the component's assigned command exists.
Definition component.py:96
set_parameters(self, params)
Set class attributes for the component based on JSON parameters.
Definition component.py:161
config(self, parser)
Automatic configuration.
Definition component.py:138
required_config(self)
Return a list of required configuration settings.
Definition component.py:208
_inputs_to_outputs(self)
This is the default method for automatically transforming input file names to outputs when output fil...
Definition component.py:244
cmd_args(self)
Return the command arguments of this component.
Definition component.py:108
check_config(self)
Raise an exception on the first missing config setting for this component.
Definition component.py:216
input_files(self)
Get a list of input files for this component.
Definition component.py:229
__init__(self, name, command=None, nevents=None, seed=1, inputs=[], outputs=None, append_tok=None, output_ext=None, ignore_job_params=[], **kwargs)
Definition component.py:49
A dummy component that just prints some information instead of executing a program.
Definition component.py:273
execute(self, log_out=sys.stdout, log_err=sys.stderr)
Generic component execution method.
Definition component.py:279