diff --git a/pyhocon/config_parser.py b/pyhocon/config_parser.py index cc1c1de..39b19a3 100644 --- a/pyhocon/config_parser.py +++ b/pyhocon/config_parser.py @@ -467,17 +467,18 @@ def _resolve_variable(cls, config, substitution): @classmethod def _fixup_self_references(cls, config, accept_unresolved=False): if isinstance(config, ConfigTree) and config.root: - for key in config: # Traverse history of element - history = config.history[key] + for key in list(config.keys()): # Use list to avoid mutation error during iteration + history = config.history.get(key) + if not history: + continue previous_item = history[0] for current_item in history[1:]: for substitution in cls._find_substitutions(current_item): prop_path = ConfigTree.parse_key(substitution.variable) if len(prop_path) > 1 and config.get(substitution.variable, None) is not None: - continue # If value is present in latest version, don't do anything + continue if prop_path[0] == key: if isinstance(previous_item, ConfigValues) and not accept_unresolved: - # We hit a dead end, we cannot evaluate raise ConfigSubstitutionException( "Property {variable} cannot be substituted. Check for cycles.".format( variable=substitution.variable @@ -493,13 +494,13 @@ def _fixup_self_references(cls, config, accept_unresolved=False): for substitution in cls._find_substitutions(previous_item): prop_path = ConfigTree.parse_key(substitution.variable) if len(prop_path) > 1 and config.get(substitution.variable, None) is not None: - continue # If value is present in latest version, don't do anything + continue if prop_path[0] == key: value = os.environ.get(key) if value is not None: cls._do_substitute(substitution, value) continue - if substitution.optional: # special case, when self optional referencing without existing + if substitution.optional: cls._do_substitute(substitution, None) # traverse config to find all the substitutions