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