Add yaml config env defaults parsing

This commit is contained in:
Roman Mogylatov 2021-06-12 14:42:11 -04:00
parent d39fdfe2e9
commit 20dd4108a3
3 changed files with 7977 additions and 7562 deletions

File diff suppressed because it is too large Load Diff

View File

@ -91,10 +91,25 @@ else:
if yaml:
# TODO: use SafeLoader without env interpolation by default in version 5.*
yaml_env_marker_pattern = re.compile(r'\$\{([^}^{]+)\}')
yaml_env_marker_pattern = re.compile(
r'\${(?P<name>[^}^{:]+)(?P<separator>:?)(?P<default>.*?)}',
)
def yaml_env_marker_constructor(_, node):
""""Replace environment variable marker with its value."""
return os.path.expandvars(node.value)
node_value = node.value
for match in reversed(list(yaml_env_marker_pattern.finditer(node.value))):
has_default = match.group('separator') == ':'
value = os.getenv(match.group('name'))
if value is None:
if not has_default:
continue
value = match.group('default')
span_min, span_max = match.span()
node_value = f'{node_value[:span_min]}{value}{node_value[span_max:]}'
return node_value
yaml.add_implicit_resolver('!path', yaml_env_marker_pattern)
yaml.add_constructor('!path', yaml_env_marker_constructor)

View File

@ -882,6 +882,30 @@ class ConfigFromYamlWithEnvInterpolationTests(unittest.TestCase):
self.assertEqual(self.config.section1.value1(), '${CONFIG_TEST_ENV}')
self.assertEqual(self.config.section1.value2(), '${CONFIG_TEST_PATH}/path')
@unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
def test_default_values(self):
os.environ['DEFINED'] = 'defined'
self.addCleanup(os.environ.pop, 'DEFINED')
with open(self.config_file, 'w') as config_file:
config_file.write(
'section:\n'
' defined_with_default: ${DEFINED:default}\n'
' undefined_with_default: ${UNDEFINED:default}\n'
' complex: ${DEFINED}/path/${DEFINED:default}/${UNDEFINED}/${UNDEFINED:default}\n'
)
self.config.from_yaml(self.config_file)
self.assertEqual(
self.config.section(),
{
'defined_with_default': 'defined',
'undefined_with_default': 'default',
'complex': 'defined/path/defined/${UNDEFINED}/default',
},
)
@unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
def test_option_env_variable_interpolation(self):
self.config.option.from_yaml(self.config_file)