Skip to content

Commit

Permalink
Merge pull request #34 from chimpler/substitution-override-fix
Browse files Browse the repository at this point in the history
fixed substitutions override by traversing the tree at the end to find the actual substitutions to resolve (#29)
  • Loading branch information
darthbear committed May 16, 2015
2 parents d0535ee + ffb4a6b commit a657950
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 a657950

Please sign in to comment.