1 # Copyright (C) 2011 W. Trevor King <wking@drexel.edu>
3 # This file is part of h5config.
5 # h5config is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation, either version 3 of the License, or (at your
8 # option) any later version.
10 # h5config is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with h5config. If not, see <http://www.gnu.org/licenses/>.
18 """Tools for setting up a package using config files.
20 The benefit of subclassing `PackageConfig` over using something like
21 `configparser` is that you can easily store default `h5config` values
22 in the configuration file. Consider the following example:
28 import logging as _logging
29 import os.path as _os_path
32 from . import config as _config
33 from . import log as _log
34 from .storage.hdf5 import HDF5_Storage as _HDF5_Storage
35 from .storage.yaml import YAML_Storage as _YAML_Storage
38 class PackageConfig (_config.Config):
39 """Configure package operation
41 This basic implementation just creates and manages a package-wide
42 `LOG` instance. If you create this instance on your own (for
43 example, to work around bootstrapping issues), just pass your
44 instance in as `logger` when you initialize this class.
46 possible_storage = [_HDF5_Storage, _YAML_Storage]
48 _config.ChoiceSetting(
50 help='Module logging level.',
51 default=_logging.WARN,
53 ('critical', _logging.CRITICAL),
54 ('error', _logging.ERROR),
55 ('warn', _logging.WARN),
56 ('info', _logging.INFO),
57 ('debug', _logging.DEBUG),
59 _config.BooleanSetting(
61 help='Log to syslog (otherwise log to stderr).',
65 def __init__(self, package_name, namespace=None, logger=None, **kwargs):
66 super(PackageConfig, self).__init__(**kwargs)
67 self._package_name = package_name
69 namespace = _sys.modules[package_name]
70 self._namespace = namespace
72 logger = _log.get_basic_logger(package_name, level=_logging.WARN)
74 if 'LOG' not in dir(namespace):
75 namespace.LOG = logger
78 self._logger.setLevel(self['log-level'])
80 if 'syslog' not in self._logger._handler_cache:
81 _syslog_handler = _logging_handlers.SysLogHandler()
82 _syslog_handler.setLevel(_logging.DEBUG)
83 self._logger._handler_cache['syslog'] = _syslog_handler
84 self._logger.handlers = [self._logger._handler_cache['syslog']]
86 self._logger.handlers = [self._logger._handler_cache['stream']]
87 self._logger.info('setup {} packge config:\n{}'.format(
88 self._package_name, self.dump()))
91 "Replace self with a non-backed version with default settings."
92 super(PackageConfig, self).clear()
95 def _base_paths(self):
96 user_basepath = _os_path.join(
97 _os_path.expanduser('~'), '.{}rc'.format(self._package_name))
98 system_basepath = _os_path.join('/etc', self._package_name, 'config')
99 distributed_basepath = _os_path.join(
100 '/usr', 'share', self._package_name, 'config')
101 return [user_basepath, system_basepath, distributed_basepath]
103 def load_system(self):
104 "Return the best `PackageConfig` match after scanning the filesystem"
105 self._logger.info('looking for package config file')
106 basepaths = self._base_paths()
107 for basepath in basepaths:
108 for storage in self.possible_storage:
109 filename = '{}.{}'.format(basepath, storage.extension)
110 if _os_path.exists(filename):
112 'base_config file found at {}'.format(filename))
113 self._storage = storage(filename=filename)
119 'no base_config file at {}'.format(filename))
120 # create (but don't save) the preferred file
121 basepath = basepaths[0]
122 storage = self.possible_storage[0]
123 filename = '{}.{}'.format(basepath, storage.extension)
124 self._logger.info('new base_config file at {}'.format(filename))
125 self._storage = storage(filename=filename)