Skip to content

Commit

Permalink
#256 - Process substitution overrides in order
Browse files Browse the repository at this point in the history
  • Loading branch information
JettJones committed Mar 13, 2021
1 parent 07758b8 commit 84344e0
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
11 changes: 10 additions & 1 deletion pyhocon/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,10 @@ def _do_substitute(cls, substitution, resolved_value, is_optional_resolved=True)
if transformation is None and not is_optional_resolved \
else transformation

# When the result is None, remove the key.
if result is None and config_values.key in config_values.parent:
del config_values.parent[config_values.key]
else:
elif result is not None:
config_values.parent[config_values.key] = result
s = cls._find_substitutions(result)
if s:
Expand Down Expand Up @@ -670,6 +671,12 @@ def resolve_substitutions(cls, config, accept_unresolved=False):
_substitutions = substitutions[:]

for substitution in _substitutions:
# If this substitution is an override, and the parent is still being processed,
# skip this entry, it will be processed on the next loop.
if substitution.parent.overriden_value:
if substitution.parent.overriden_value in [s.parent for s in substitutions]:
continue

is_optional_resolved, resolved_value = cls._resolve_variable(config, substitution)

# if the substitution is optional
Expand All @@ -695,6 +702,8 @@ def resolve_substitutions(cls, config, accept_unresolved=False):

unresolved, new_substitutions, result = cls._do_substitute(substitution, resolved_value, is_optional_resolved)
any_unresolved = unresolved or any_unresolved
# Detected substitutions may already be listed to process
new_substitutions = [n for n in new_substitutions if n not in substitutions]
substitutions.extend(new_substitutions)
if not isinstance(result, ConfigValues):
substitutions.remove(substitution)
Expand Down
3 changes: 3 additions & 0 deletions pyhocon/config_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,12 @@ def has_substitution(self):
return len(self.get_substitutions()) > 0

def get_substitutions(self):
# Returns a list of ConfigSubstitution tokens, in string order
lst = []
node = self
while node:
# walking up the override chain and append overrides to the front.
# later, parent overrides will be processed first, followed by children
lst = [token for token in node.tokens if isinstance(token, ConfigSubstitution)] + lst
if hasattr(node, 'overriden_value'):
node = node.overriden_value
Expand Down
14 changes: 14 additions & 0 deletions tests/test_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,20 @@ def test_substitution_flat_override(self):
assert config['database.name'] == 'peopledb'
assert config['database.pass'] == 'peoplepass'

def test_substitution_multiple_override(self):
config = ConfigFactory.parse_string(
"""
a: 1
b: foo
c: ${a} ${b}
c: ${b} ${a}
d: ${a} ${b}
d: ${a} bar
""")

assert config['c'] == 'foo 1'
assert config['d'] == '1 bar'

def test_substitution_nested_override(self):
config = ConfigFactory.parse_string(
"""
Expand Down

0 comments on commit 84344e0

Please sign in to comment.