Просмотр исходного кода

Development: add util to detect possible duplicate config files.

Due to the large number of configs, there is an increasing likelihood
that a config already exists, or a close enough one can be easily modified.
When logs are provided this can be easily checked, but for pull requests
and submitted config files without any other info, this is harder, as
the dps need to be synthsised for matching.

The new util/duplicates.py script synthesises representative dps itself
so the check can be done more easily.

Current implementation is simplistic, just checking dps types like the
config matching of the integration, so relies on manual checking to confirm
whether there is really a match there. Any >50% match will be listed, as
older configs may be missing some dps.

In future the checking could be expanded to compare ranges and mapping
values, and entity types to narrow it down to the point where reported
matches are almost certainly duplicates, so this can be used in CI for pull
requests.
Jason Rumney 1 год назад
Родитель
Сommit
4b327221b6
1 измененных файлов с 55 добавлено и 0 удалено
  1. 55 0
      util/duplicates.py

+ 55 - 0
util/duplicates.py

@@ -0,0 +1,55 @@
+"""Check for duplicates of the supplied file."""
+
+import sys
+
+from custom_components.tuya_local.helpers.device_config import (
+    possible_matches,
+    get_config,
+)
+
+
+class FakeDevice:
+    def __init__(self, dps):
+        self._dps = dps
+
+    def get_property(self, id):
+        return self._dps.get(id)
+
+    @property
+    def name(self):
+        return "cmdline"
+
+def representation(dp):
+    """Return a represenative value for the dp."""
+    if dp.type is bool:
+        return True
+    if dp.type is int:
+        if dp._config.get(range):
+            return dp._config.get(range)["min"]
+        return 0
+    if dp.type is str:
+        return ""
+    if dp.type is float:
+        return 0.0
+
+def main():
+
+    for filename in sys.argv[1:]:
+        if filename.endswith(".yaml"):
+            filename = filename[:-5]
+        if "/" in filename:
+            filename = filename.split("/")[-1]
+
+        config = get_config(filename)
+        all_dps = config._get_all_dps()
+        sample_dps = {dp.id: representation(dp) for dp in all_dps}
+
+        device = FakeDevice(sample_dps)
+        for m in possible_matches(sample_dps):
+            if m.config_type == filename:
+                continue
+            if m.match_quality(sample_dps) > 50:
+                print(f"{m.config_type} matched {filename} {m.match_quality(sample_dps)}%")
+
+if __name__ == "__main__":
+    sys.exit(main())