# Virus Data Analysis Tool: a data reduction GUI for HETDEX/VIRUS data
# Copyright (C) 2016, 2017, 2018 "The HETDEX collaboration"
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
'''Configuration and support files versioning and checking'''
import configparser as cp
import os
import sys
from pyhetdex.cure import distortion
from pyhetdex.het import fplane, ifu_centers
from pyhetdex.tools.configuration import ConfigParser
import six
import yaml
COPY_FILES = ['vdat_setting.cfg',
'vdat_commands.yml',
'tasks.yml',
'fplane.txt',
os.path.join('extra_files', 'defaultL.dist'),
os.path.join('extra_files', 'defaultR.dist'),
os.path.join('extra_files', 'dither_positions.txt'),
os.path.join('extra_files', 'IFUcen_HETDEX.txt'),
os.path.join('extra_files', 'lines_L.par'),
os.path.join('extra_files', 'lines_R.par'),
]
'files to copy'
IMPORTANT_FILES = ['vdat_setting.cfg',
'vdat_commands.yml',
'tasks.yml',
'fplane.txt'
]
'''Files essential to run VDAT but that can have different names and be however
passed to the code via configuration or command line options'''
VERSION_VDAT_SETTING = '2.0.0'
'version of the vdat_setting file'
VERSION_VDAT_COMMANDS = '1.3.0'
'version of the vdat_commands file'
VERSION_TASKS = '1.3.0'
'version of the tasks file'
[docs]def version_name(filename):
'''Return the name of the variable storing the version of ``filename``
Parameters
----------
filename : string
name of the file for which to find the version
Returns
-------
string
name of the variable storing the configuration file
'''
file_name = os.path.splitext(filename)[0].replace(os.path.sep, '_')
return "VERSION_" + file_name.upper()
[docs]def version_of_file(filename):
'''If available, returns the version string for the ``filename`` as defined
in :mod:`vdat.config.versions`
Parameters
----------
filename : string
name of the file for which to find the version
Returns
-------
version : string
version or None, if no version is available
'''
name = version_name(filename)
thismodule = sys.modules[__name__]
try:
version = getattr(thismodule, name)
except AttributeError:
version = None
return version
[docs]def version_from_file(path, filename):
'''Try to extract the version number from ``path + filename``
Parameters
----------
path : string
path where the file resides
filename : string
name of the file
Returns
-------
version : string
version as extracted from the file or None, if no version is found
'''
vname = version_name(filename)
version = None
with open(os.path.join(path, filename)) as f:
for l in f:
if vname in l:
version = l.split('=')[1].strip()
break
return version
[docs]def files_with_version():
'''Return the list of file names, that can be copied, that have an
associated version.
Returns
-------
list of strings
file names
'''
return [fn for fn in COPY_FILES if version_of_file(fn)]
# loaders
[docs]class LoaderError(Exception):
'Raised when a loader fails for any reason'
pass
[docs]def configparser_loader(fname):
'''Try to load the file using configparser
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
c = ConfigParser()
try:
c.read(fname)
except cp.Error as e:
six.raise_from(LoaderError(e), e)
[docs]def yaml_loader(fname):
'''Try to load the file using yaml
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
with open(fname) as f:
yaml.safe_load(f)
except yaml.error.YAMLError as e:
six.raise_from(LoaderError(e), e)
[docs]def fplane_loader(fname):
'''Try to load the file as a fplane file.
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
fplane.FPlane(fname)
except (ValueError, IndexError) as e:
six.raise_from(LoaderError(e), e)
[docs]def dist_loader(fname):
'''Try to load the file as a distortion file.
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
distortion.Distortion(fname)
except Exception as e:
six.raise_from(LoaderError(e), e)
[docs]def ifucent_loader(fname):
'''Try to load the file as an ifu center file.
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
ifu_centers.IFUCenter(fname)
except (ValueError, ) as e:
six.raise_from(LoaderError(e), e)
[docs]def lines_loader(fname):
'''Try to load the file as an line file.
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
with open(fname) as f:
for l in f:
if l.startswith('#'):
continue
else:
l, x, ac = l.split()
except ValueError as e:
six.raise_from(LoaderError(e), e)
[docs]def dither_position_loader(fname):
'''Try to load the file as dither position file.
Parameters
----------
fname : string
file to load
Raises
------
LoaderError
if it fails to load
'''
try:
with open(fname) as f:
for line in f:
if line.startswith('#'):
continue
else:
line = line.split()
line[0]
if len(line[1:]) % 2 != 0:
raise ValueError('The number of x/y dither shifts must'
' be even not {} as in line "{}"'
.format(len(line[1:]), line))
except (IndexError, ValueError) as e:
six.raise_from(LoaderError(e), e)
LOADERS_FILES = {
'vdat_setting.cfg': configparser_loader,
'vdat_commands.yml': yaml_loader,
'tasks.yml': yaml_loader,
'fplane.txt': fplane_loader,
os.path.join('extra_files', 'defaultL.dist'): dist_loader,
os.path.join('extra_files', 'defaultR.dist'): dist_loader,
os.path.join('extra_files', 'dither_positions.txt'):
dither_position_loader,
os.path.join('extra_files', 'IFUcen_HETDEX.txt'):
ifucent_loader,
os.path.join('extra_files', 'lines_L.par'): lines_loader,
os.path.join('extra_files', 'lines_R.par'): lines_loader
}