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