appdaemon
appdaemon copied to clipboard
Throw an error / refuse to load if apps.yaml has a duplicate top-level key
Is there an existing feature request for this?
- [X] I have searched the existing issues
Your feature request
A couple times I've accidentally repeated the same apps.yaml top-level key. AppDaemon picks one and ignores the other (maybe this is just YAML load behavior). This has led to confusing errors for me, such as a new app working fine but an old one no longer working somewhat mysteriously until I figure out what I did. I would rather AppDaemon treat this as an error and refuse to load the new apps.yaml file.
Example:
my_app:
module: my_app
class: MyApp
argument: value_one
# ... many lines ...
my_app:
module: my_app
class: MyApp
argument: a_different_value
In the above case, I would like an error, but AppDaemon loads the file with only one my_app.
PyYAML has issues open for this since 2016 so I doubt we'll see a library solution, but there are a number of workarounds mentioned like creating a customized loader.
As you guessed, this is a limitation of YAML. By the time this situation gets through to AD code, the YAML libraries have already ignored one of the entries as a duplicate and we never get to see it.
Thanks for taking a look!
What do you think of the approach of customizing the yaml Loader? Here's an example from a gist discussion thread:
class UniqueKeyLoader(yaml.SafeLoader):
def construct_mapping(self, node, deep=False):
mapping = set()
for key_node, value_node in node.value:
if ':merge' in key_node.tag:
continue
key = self.construct_object(key_node, deep=deep)
if key in mapping:
raise ValueError(f"Duplicate {key!r} key found in YAML.")
mapping.add(key)
return super().construct_mapping(node, deep)
# other code
yaml_dic=yaml.load(yaml_file,Loader=UniqueKeyLoader)
Poking around AppDaemon's code, would that fit into utils.read_yaml_config, as a possible replacement for Loader=yaml.SafeLoader (which gets called from app_management.py) ?
By the way I'm really enjoying AppDaemon, very easy to get started, helpful examples, and flexible enough to handle as much complexity as I've come up with so far.