Every driver is defined by a string:
module:function
that instructs vhc to load the module module and execute the function, having the signature libvhc.function_signature().
The majority of drivers act on single fits files and have this structure:
Since the above pattern is very common, we provide the module libvhc.factories, that provides three functions that automatize the creation of a driver.
Simple commands, that don’t require any external information, can be easily setup providing a string with the command to execute.
# in common.py
command = "{curebin}/checkheader -E -r {recipe} {fname}"
# ``exptime`` is the callable implementing the driver
exptime = command_line_factory(command)
The variables within {...} are expanded in the body of the factory as the driver is executed. The available variables are
curebin | cure binaries directory |
recipe | recipe at hand |
driver | driver at hand |
fname | name of the file to test |
ifuid | id of the ifu from the fname header |
headkey | instruct cure to write in the fits headers whether the check is successful or not |
If by chance your command needs to have a set of curly brackets, you can escape them doubling them {{...}}.
Sometimes you need to build the string programmatically, e.g. reading information for some configuration file, do some computation, etc. This factory allow to easily do this
# in common.py
import libvhc.reference_file_parser as vhcrfp
[...]
def _check_overscan_cmd(vcheck, fname, log, conf):
"""Build the call for the overscan check
Parameters
----------
vcheck : instance of :class:`~libvhc.VCheck`
store the recipe name and the check currently
executing
fname : string
name of the file to check
log : instance of :class:`logging.LoggerAdapter`
logger
conf : instance of :class:`configparser.ConfigParser`
configuration object
Returns
-------
cmd : string
string of the command to execute
"""
# get the overscan reference value(s) from configuration file
header = fits.getheader(fname)
spectid = vhcutils.get_specid(header)
channel = vhcutils.get_channel(header)
amplifier = vhcutils.get_amplifier(header)
vals = vhcrfp.picker("overscan").get_value(spectid, channel, amplifier)
mean, stddev, dev_mean, dev_stddev = vals
# build the checkheader call
cmd_str = "{curebin}/checkheader -O -r {recipe}"
# expected mean and standard deviation
cmd_str += " --ovc_mean {} --ovc_stddev {}".format(mean, stddev)
# maximum deviation from them
cmd_str += " --max_ovc_dev_mean {} --max_ovc_dev_rms {}".format(dev_mean,
dev_stddev)
cmd_str += " {fname}"
return cmd_str
# ``check_overscan`` is the callable implementing the driver
check_overscan = factories.command_func_factory(_check_overscan_cmd)
As before, the variables within {...} are expanded in the body of the factory.
In case the standard checks do not suite you, we also provide a low level factory, which loop through the fits files and call the provided function on each of the files. But you have to implement yourself the communication the success or failure of the checks with the output files and the html renderer.
import subprocess as sp
import libvhc.loggers as vhclog
# in foo.py
def _bar(vcheck, fname, lpath):
"run ls on all files"
log = vhclog.getLogger(fname[:lpath-1]) # vhc logger
p = sp.Popen(["ls", "-l", fname], stdout=sp.PIPE, stderr=sp.PIPE)
stdout, stderr = p.communicate()
log.info(stdout) # will got to the ``log.txt`` file
html = "success"
if stderr: # if there is some error appears on standard error
# will got to the ``log.txt`` and the ``v_results.txt`` file
log.error(stderr)
html = "fail"
# tell the html renderer whether the test worked or not
[...]
# catch errors?
[...]
bar = factories.function_factory(_bar)