docs/compose/config/interpolation.py

85 lines
2.3 KiB
Python

from __future__ import absolute_import
from __future__ import unicode_literals
import logging
import os
from string import Template
import six
from .errors import ConfigurationError
log = logging.getLogger(__name__)
def interpolate_environment_variables(config, section):
mapping = BlankDefaultDict(os.environ)
def process_item(name, config_dict):
return dict(
(key, interpolate_value(name, key, val, section, mapping))
for key, val in (config_dict or {}).items()
)
return dict(
(name, process_item(name, config_dict or {}))
for name, config_dict in config.items()
)
def interpolate_value(name, config_key, value, section, mapping):
try:
return recursive_interpolate(value, mapping)
except InvalidInterpolation as e:
raise ConfigurationError(
'Invalid interpolation format for "{config_key}" option '
'in {section} "{name}": "{string}"'.format(
config_key=config_key,
name=name,
section=section,
string=e.string))
def recursive_interpolate(obj, mapping):
if isinstance(obj, six.string_types):
return interpolate(obj, mapping)
elif isinstance(obj, dict):
return dict(
(key, recursive_interpolate(val, mapping))
for (key, val) in obj.items()
)
elif isinstance(obj, list):
return [recursive_interpolate(val, mapping) for val in obj]
else:
return obj
def interpolate(string, mapping):
try:
return Template(string).substitute(mapping)
except ValueError:
raise InvalidInterpolation(string)
class BlankDefaultDict(dict):
def __init__(self, *args, **kwargs):
super(BlankDefaultDict, self).__init__(*args, **kwargs)
self.missing_keys = []
def __getitem__(self, key):
try:
return super(BlankDefaultDict, self).__getitem__(key)
except KeyError:
if key not in self.missing_keys:
log.warn(
"The {} variable is not set. Defaulting to a blank string."
.format(key)
)
self.missing_keys.append(key)
return ""
class InvalidInterpolation(Exception):
def __init__(self, string):
self.string = string