#
# DRAGONS
#
# cal_service
# ------------------------------------------------------------------------------
from os.path import basename
from os.path import expanduser
from os.path import exists
from ..config import globalConf
from ..config import STANDARD_REDUCTION_CONF
from ..config import DEFAULT_DIRECTORY
from . import transport_request
try:
from . import localmanager
localmanager_available = True
except ImportError as e:
localmanager_available = False
import_error = str(e)
# ------------------------------------------------------------------------------
# BEGIN Setting up the calibs section for config files
CONFIG_SECTION = 'calibs'
globalConf.update_translation({
(CONFIG_SECTION, 'standalone'): bool
})
globalConf.update_exports({
CONFIG_SECTION: ('standalone', 'database_dir')
})
# END Setting up the calibs section for config files
# ------------------------------------------------------------------------------
[docs]def load_calconf(conf_path=STANDARD_REDUCTION_CONF):
"""
Load the configuration from the specified path to file (or files), and
initialize it with some defaults.
Parameters
----------
conf_path: <str>, Path of configuration file. Default is
STANDARD_REDUCTION_CONF -> '~/.geminidr/rsys.cfg'
Return
------
<ConfigObject>
"""
globalConf.load(conf_path,
defaults = {
CONFIG_SECTION: {
'standalone': False,
'database_dir': expanduser(DEFAULT_DIRECTORY)
}
})
return get_calconf()
[docs]def update_calconf(items):
globalConf.update(CONFIG_SECTION, items)
[docs]def get_calconf():
try:
return globalConf[CONFIG_SECTION]
except KeyError:
# This will happen if CONFIG_SECTION has not been defined in any
# config file, and no defaults have been set (shouldn't happen if
# the user has called 'load_calconf' before.
pass
[docs]def is_local():
try:
if get_calconf().standalone:
if not localmanager_available:
raise RuntimeError(
"Local calibs manager has been chosen, but there "
"are missing dependencies: {}".format(import_error))
return True
except AttributeError:
# This may happen if there's no calibration config section or, in
# case there is one, if either calconf.standalone or calconf.database_dir
# are not defined
pass
return False
[docs]def handle_returns_factory():
return (
localmanager.handle_returns
if is_local() else
transport_request.handle_returns
)
[docs]def cal_search_factory():
"""
This function returns the proper calibration search function, depending on
the user settings.
Defaults to `prsproxyutil.calibration_search` if there is missing calibs
setup, or if the `[calibs]`.`standalone` option is turned off.
Returns
-------
calibration_search: <func>
The appropriate (local or fitsstore) search function indicated by
a given configuration.
"""
return (
localmanager.LocalManager(get_calconf().database_dir).calibration_search
if is_local() else
transport_request.calibration_search
)
[docs]def set_calservice(local_db_dir=None, config_file=STANDARD_REDUCTION_CONF):
"""
Update the calibration service global configuration stored in
:data:`recipe_system.config.globalConf` by changing the path to the
configuration file and to the data base directory.
Parameters
----------
local_db_dir: <str>
Name of the directory where the database will be stored.
config_file: <str>
Name of the configuration file that will be loaded.
"""
globalConf.load(expanduser(config_file))
if localmanager_available:
if local_db_dir is None:
local_db_dir = globalConf['calibs'].database_dir
globalConf.update(
CONFIG_SECTION, dict(
database_dir=expanduser(local_db_dir),
config_file=expanduser(config_file)
)
)
globalConf.export_section(CONFIG_SECTION)
[docs]class CalibrationService:
"""
The CalibrationService class provides a limited API on the LocalManager
class. The CalibrationService is meant for public use, as opposed to the
lower level LocalManager class, and provides limited access to let
users/callers easy configuration and use of the local calibration database.
Methods
-------
config(db_dir=None, verbose=True, config_file=STANDARD_REDUCTION_CONF)
configure a session with the database via the rsys.conf file.
init(wipe=True)
initialize a calibration database.
add_cal(path)
Add a calibration file to the database.
remove_cal(path)
Delete a calibration from the database.
list_files()
List files in the database. Returns a generator object.
E.g.,
>>> from recipe_system.cal_service import CalibrationService
>>> caldb = CalibrationService()
>>> caldb.config()
Using configuration file: ~/.geminidr/rsys.cfg
The active database directory is: ~/.geminidr
The database file to be used: ~/.geminidr/cal_manager.db
The 'standalone' flag is active; local calibrations will be used.
>>> caldb.add_cal('calibrations/processed_bias/S20141013S0163_bias.fits')
>>> for f in caldb.list_files():
f
FileData(name='N20120212S0073_flat.fits', path='NIRI/calibrations/processed_flat')
FileData(name='N20131214S0097_dark.fits', path='NIRI')
FileData(name='N20150419S0224_flat.fits', path='GMOS_N_TWILIGHT_FLATS')
FileData(name='S20141013S0020_stackd_flat.fits', path='gband_demo')
FileData(name='S20141013S0163_bias.fits', path='gband_demo')
FileData(name='S20141013S0163_flats_bias.fits', path='../gband_demo')
FileData(name='S20141103S0123_image_bias.fits', path='../gband_demo')
>>> caldb.remove_cal('N20120212S0073_flat.fits')
>>> for f in caldb.list_files():
f
FileData(name='N20131214S0097_dark.fits', path='NIRI')
FileData(name='N20150419S0224_flat.fits', path='GMOS_N_TWILIGHT_FLATS')
FileData(name='S20141013S0020_stackd_flat.fits', path='gband_demo')
FileData(name='S20141013S0163_bias.fits', path='gband_demo')
FileData(name='S20141013S0163_flats_bias.fits', path='../gband_demo')
FileData(name='S20141103S0123_image_bias.fits', path='../gband_demo')
"""
def __init__(self):
self.conf = None
self._mgr = None
[docs] def config(self, db_dir=None, verbose=False,
config_file=STANDARD_REDUCTION_CONF):
"""
Configure the Calibration Service and database.
Parameters
----------
db_dir: <str>
Path to the local calibration database. If the database has not been
initialized, call this method and then init() the database. If not
passed (None), the path specified in a user's rsys.conf file is used.
verbose: <bool>
Configuration information will be displayed to stdout.
Default is True.
config_file: str
Path to the configuration file.
"""
set_calservice(local_db_dir=db_dir, config_file=config_file)
conf = get_calconf()
if not conf.standalone:
print("CalibrationService is not configured as standalone.")
else:
print("CalibrationService is configured as standalone.")
print("The configured local database will be used.")
self._mgr = localmanager.LocalManager(expanduser(conf.database_dir))
if verbose:
self._config_info(conf)
return
[docs] def config_info(self):
try:
self._config_info(get_calconf())
except AttributeError as err:
print("No configuration information available.")
print("You must configure the CalibrationService with config()")
return
[docs] def init(self, wipe=True):
"""
Initialize a calibration database. Callers will usually only want to do
this once. But if called again, will wipe the old database.
Parameters
----------
wipe: <bool>, optional
If the database exists and this parameter is `True` (default
value), the file will be removed and recreated before
initializing.
Raises
------
IOError
If the file exists and there a system error when trying to
remove it (eg. lack of permissions).
LocalManagerError
If the file exists and `wipe` was `False`
"""
return self._mgr.init_database(wipe=wipe)
[docs] def add_cal(self, path):
"""
Registers a calibration file specified by 'apath' into the database
Parameters
----------
path: <str>
Path to the file. It can be either absolute or relative.
"""
return self._mgr.ingest_file(path)
[docs] def remove_cal(self, path):
"""
Removes a calibration file from the database. Note that only the filename
is relevant. All duplicate copies in the database will be removed.
Parameters
----------
path: <str>
Path to the file. It can be either absolute or relative
"""
return self._mgr.remove_file(basename(path))
[docs] def list_files(self):
"""
List all files in the local calibration database.
Parameters
----------
<void>
Returns
-------
LocalManager.list_files: <generator>.
(See class docstring for example of how to use this generator.)
Raises
------
LocalManagerError
Raised when unable to read database.
"""
return self._mgr.list_files()
def _config_info(self, conf):
path = self._mgr._db_path
is_active = (
"The 'standalone' flag is \033[1mactive\033[0m; local calibrations"
"will be used."
)
inactive = (
"The 'standalone' flag is not active; remote calibrations will be"
" downloaded."
)
print()
print("Using configuration file: \033[1m{}\033[0m".format(conf.config_file))
print("Active database directory: \033[1m{}\033[0m".format(conf.database_dir))
print("Database file: \033[1m{}\033[0m".format(path))
print()
print("configuration standalone: {}".format(conf.standalone))
if conf.standalone:
print(is_active)
else:
print(inactive)
if not exists(path):
print(" NB: The database does not exist. Please initialize it.")
print(" (see init() below.)")
print()
return