Source code for pymlconf.config_manager
import os
from pymlconf.config_nodes import ConfigDict
from pymlconf.yaml_helper import load_yaml
from pymlconf.compat import basestring
from pymlconf.errors import ConfigFileNotFoundError
import warnings
IGNORE = 0
ERROR = 1
WARNING = 2
missing_file_behaviors = [IGNORE,
ERROR,
WARNING]
[docs]class ConfigManager(ConfigDict):
"""
The main class which exposes pymlconf package.
Example::
from pymlconf import ConfigManager
from os import path
config = ConfigManager('''
server:
host: localhost
port: 4455
''','conf','builtins/defaults.conf')
print config.server.host
print config.server.port
"""
default_extension = ".conf"
def __init__(self, init_value=None, dirs=None, files=None, filename_as_namespace=True,
extension='.conf', root_file_name='root', missing_file_behavior=WARNING, encoding='utf-8',
context=None, builtin=None):
"""
:param init_value: Initial configuration value that you can pass it before reading the files and directories.can
be 'yaml string' or python dictionary.
:type init_value: str or dict
:param dirs: Python list or a string that contains semi-colon separated list of directories which contains
configuration files with specified extension(default \*.conf).
:type dirs: str or list
:param files: Python list or a string that contains semi-colon separated list of files which contains yaml
configuration entries.
:type files: str or list
:param filename_as_namespace: when loading dirs, use the filename as a namespace. default: true.
:type filename_as_namespace: bool
:param extension: File extension to search for configuration files, in dirs parameter, default '.conf'
:type extension: str
:param root_file_name: Filename to treat as root configuration file, so it loads first, and do not uses the
filename as namespaces.
:type root_file_name: str
:param missing_file_behavior: What should do when a file was not found, set to 0 (zero) to ignore. default to
``warning(2)``
:type missing_file_behavior: integer 0:ignore, 1:throw error, 2:warning
:param context: dictionary to format the yaml before parsing in pre processor.
:type context: dict
:param builtin: Same as the ``init_value``, but it will be loaded before the loading the ``init_value``,
helps to implement builtin config pattern.
:type builtin: str or dict
.. versionadded:: 0.6.0a
The ``builtin`` parameter was added.
"""
self.default_extension = extension
self.root_file_name = root_file_name
self.missing_file_behavior = missing_file_behavior
self.encoding = encoding
# Loading the instance with built-in config
super(ConfigManager, self).__init__(data=builtin, context=context)
# Loading init_value
if init_value:
self.merge(init_value)
if dirs:
self.load_dirs(dirs, filename_as_namespace=filename_as_namespace)
if files:
self.load_files(files)
[docs] def load_files(self, files, filename_as_namespace=False):
"""
load files which contains yaml configuration entries.and merge it by current ConfigManager instance
:param files: files to load and merge into existing configuration instance
:type files: list
:param filename_as_namespace: when loading files, use the filename as a namespace. default: false.
:type filename_as_namespace: bool
"""
files = [f.strip() for f in files.split(';')] if isinstance(files, basestring) else files
for f in files:
if not os.path.exists(f):
if self.missing_file_behavior == ERROR:
raise ConfigFileNotFoundError(f)
elif self.missing_file_behavior == WARNING:
warnings.warn('File not found: %s' % f)
continue
if filename_as_namespace:
assert f.endswith(self.default_extension), \
'Invalid configuration filename.expected: ns1.ns2.*%s' % self.default_extension
namespace = os.path.splitext(os.path.split(f)[1])[0]
if namespace == self.root_file_name:
node = self
else:
node = self._ensure_namespaces(*namespace.split('.'))
else:
node = self
loaded_yaml = load_yaml(f, self.context, encoding=self.encoding)
if loaded_yaml:
node.merge(loaded_yaml)
loadfiles = load_files
[docs] def load_dirs(self, dirs, filename_as_namespace=True):
"""
load directories which contains configuration files with specified extension, and merge it by current
ConfigManager instance
:param dirs: Dirs to search for configuration files.
:type dirs: list,string
:param filename_as_namespace: when loading dirs, use the filename as a namespace. default: true.
:type filename_as_namespace: bool
"""
dirs = [d.strip() for d in dirs.split(';')] if isinstance(dirs, basestring) else dirs
candidate_files = []
for d in dirs:
full_paths = (os.path.join(d, f) for f in os.listdir(d))
conf_files = (f for f in full_paths if
(os.path.isfile(f) or os.path.islink(f)) and f.endswith(self.default_extension))
candidate_files.extend(sorted(conf_files))
root_file_name = None
for f in candidate_files:
if f.endswith(self.root_file_name + self.default_extension):
root_file_name = f
break
# remove and insert root.conf in index 0.
if root_file_name:
candidate_files = [root_file_name] + [f for f in candidate_files if f != root_file_name]
self.load_files(candidate_files, filename_as_namespace=filename_as_namespace)
loaddirs = load_dirs