Skip to content

Commit

Permalink
fixed substitutions override by traversing the tree at the end to fin…
Browse files Browse the repository at this point in the history
…d the actual substitutions to resolve (#29)
  • Loading branch information
darthbear committed May 16, 2015
1 parent d0535ee commit ffb4a6b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 7 deletions.
31 changes: 25 additions & 6 deletions pyhocon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,13 @@ def convert_number(tokens):
# ${path} or ${?path} for optional substitution
SUBSTITUTION = "\$\{(?P<optional>\?)?(?P<variable>[^}]+)\}(?P<ws>\s*)"

substitutions = []

def create_substitution(instring, loc, token):
# remove the ${ and }
match = re.match(SUBSTITUTION, token[0])
variable = match.group('variable')
ws = match.group('ws')
optional = match.group('optional') == '?'
substitution = ConfigSubstitution(variable, optional, ws, instring, loc)
substitutions.append(substitution)
return substitution

def include_config(token):
Expand Down Expand Up @@ -217,7 +214,7 @@ def include_config(token):
# the file can be { ... } where {} can be omitted or []
config_expr = ZeroOrMore(comment_eol | eol) + (list_expr | dict_expr | inside_dict_expr) + ZeroOrMore(comment_eol | eol_comma)
config = config_expr.parseString(content, parseAll=True)[0]
ConfigParser._resolve_substitutions(config, substitutions)
ConfigParser._resolve_substitutions(config)
return config

@staticmethod
Expand Down Expand Up @@ -254,15 +251,37 @@ def _resolve_variable(config, substitution):
return True, value

@staticmethod
def _resolve_substitutions(config, substitutions):
def _resolve_substitutions(config):
# traverse config to find all the substitutions
def find_substitutions(item):
"""Convert HOCON input into a JSON output
:return: JSON string representation
:type return: basestring
"""
if isinstance(item, ConfigValues):
return item.get_substitutions()

substitutions = []
if isinstance(item, ConfigTree):
for key, child in item.items():
substitutions += find_substitutions(child)
elif isinstance(item, list):
for child in item:
substitutions += find_substitutions(child)

return substitutions

substitutions = find_substitutions(config)

if len(substitutions) > 0:
_substitutions = set(substitutions)
for i in range(len(substitutions)):
unresolved = False
for substitution in list(_substitutions):
is_optional_resolved, resolved_value = ConfigParser._resolve_variable(config, substitution)

# if the substitition is optional
# if the substitution is optional
if not is_optional_resolved and substitution.optional:
resolved_value = None

Expand Down
5 changes: 4 additions & 1 deletion pyhocon/config_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,10 @@ def __init__(self, tokens, instring, loc):
self.tokens[-1] = self.tokens[-1].rstrip()

def has_substitution(self):
return next((True for token in self.tokens if isinstance(token, ConfigSubstitution)), False)
return len(self.get_substitutions()) > 0

def get_substitutions(self):
return [token for token in self.tokens if isinstance(token, ConfigSubstitution)]

def transform(self):
def determine_type(token):
Expand Down
36 changes: 36 additions & 0 deletions tests/test_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,3 +1000,39 @@ def test_assign_dict_strings_no_equal_sign_with_eol(self):
assert config['a'] == {'a': 1, 'b': 2}
assert config['b'] == {'c': 3, 'd': 4}
assert config['c'] == {'e': 5, 'f': 6}

def test_substitutions_overwrite(self):
config1 = ConfigFactory.parse_string(
"""
a = 123
a = ${?test}
a = 5
"""
)

assert config1['a'] == 5

config2 = ConfigFactory.parse_string(
"""
{
database {
host = "localhost"
port = 8000
url = ${database.host}":"${database.port}
}
database {
host = ${?DB_HOST}
}
database {
host = "other.host.net"
port = 433
}
}
"""
)

assert config2['database']['host'] == 'other.host.net'
assert config2['database']['port'] == 433
assert config2['database']['url'] == 'other.host.net:433'

0 comments on commit ffb4a6b

Please sign in to comment.