From 09430aa4610093a9eec138a2d4a806064aab50aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:24:50 +0000 Subject: [PATCH 1/2] Initial plan From fa33a7cda8dc814d99f7ffef0ad7ac5e5894b033 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 05:29:45 +0000 Subject: [PATCH 2/2] Move fallback_definitions from tag_types.py to const.py Co-authored-by: Misiu <1741838+Misiu@users.noreply.github.com> --- .github/workflows/sync-tag-definitions.yml | 4 +- custom_components/opendisplay/const.py | 95 ++++++++++++++++++++++ custom_components/opendisplay/tag_types.py | 95 +--------------------- scripts/generate_tag_types.py | 26 +++--- tests/scripts/test_sync_tag_types.py | 86 ++++++++++---------- 5 files changed, 153 insertions(+), 153 deletions(-) diff --git a/.github/workflows/sync-tag-definitions.yml b/.github/workflows/sync-tag-definitions.yml index 317ea06..bfb4373 100644 --- a/.github/workflows/sync-tag-definitions.yml +++ b/.github/workflows/sync-tag-definitions.yml @@ -31,7 +31,7 @@ jobs: id: fetch run: python3 scripts/fetch_tag_types.py new_tag_types.json - - name: Generate updated tag_types.py + - name: Generate updated const.py id: generate run: | python3 scripts/generate_tag_types.py new_tag_types.json @@ -78,7 +78,7 @@ jobs: branch: 'automated/sync-tag-definitions' delete-branch: true add-paths: | - custom_components/opendisplay/tag_types.py + custom_components/opendisplay/const.py labels: | automated dependencies diff --git a/custom_components/opendisplay/const.py b/custom_components/opendisplay/const.py index 024f11d..6fe1160 100644 --- a/custom_components/opendisplay/const.py +++ b/custom_components/opendisplay/const.py @@ -4,3 +4,98 @@ SIGNAL_AP_UPDATE = f"{DOMAIN}_ap_update" OEPL_CONFIG_URL = "https://config.openepaperlink.org/" ATC_CONFIG_URL = "https://atc1441.github.io/ATC_BLE_OEPL_Image_Upload.html" + +# Fallback tag type definitions +# These definitions are automatically synced from OpenEPaperLink repository +# See: https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes +FALLBACK_TAG_DEFINITIONS = { + 0: {"version": 4, "name": "M2 1.54\"", "width": 152, "height": 152}, + 1: {"version": 5, "name": "M2 2.9\"", "width": 296, "height": 128}, + 2: {"version": 5, "name": "M2 4.2\"", "width": 400, "height": 300}, + 3: {"version": 6, "name": "M2 2.2\"", "width": 212, "height": 104}, + 4: {"version": 4, "name": "M2 2.6\"", "width": 296, "height": 152}, + 5: {"version": 4, "name": "M2 7.4\"", "width": 640, "height": 384}, + 6: {"version": 4, "name": "Opticon 2.2\"", "width": 250, "height": 128}, + 7: {"version": 4, "name": "Opticon 2.9\"", "width": 296, "height": 128}, + 8: {"version": 2, "name": "Opticon 4.2\"", "width": 400, "height": 300}, + 9: {"version": 2, "name": "Opticon 7.5\"", "width": 640, "height": 384}, + 17: {"version": 3, "name": "M2 2.9\" (UC8151)", "width": 296, "height": 128}, + 18: {"version": 3, "name": "M2 4.2\" UC", "width": 400, "height": 300}, + 33: {"version": 2, "name": "ST‐GM29XXF 2.9\"", "width": 296, "height": 128}, + 34: {"version": 2, "name": "M2 2.7\"", "width": 264, "height": 176}, + 38: {"version": 1, "name": "M2 7.5\" BW", "width": 640, "height": 384}, + 39: {"version": 3, "name": "ST‐GM29MT1 2.9\"", "width": 296, "height": 128}, + 40: {"version": 2, "name": "M3 1.6\" BWRY", "width": 168, "height": 168}, + 41: {"version": 1, "name": "M3 2.4\" BWRY", "width": 296, "height": 168}, + 42: {"version": 1, "name": "M3 3.0\" BWRY", "width": 400, "height": 168}, + 43: {"version": 1, "name": "M3 2.9\" BWRY", "width": 384, "height": 168}, + 44: {"version": 1, "name": "M3 4.3\" BWRY", "width": 522, "height": 152}, + 45: {"version": 2, "name": "M3 12.2\"", "width": 960, "height": 768}, + 46: {"version": 5, "name": "M3 9.7\"", "width": 960, "height": 672}, + 47: {"version": 4, "name": "M3 4.3\"", "width": 522, "height": 152}, + 48: {"version": 2, "name": "M3 1.6\"", "width": 200, "height": 200}, + 49: {"version": 1, "name": "M3 2.2\"", "width": 296, "height": 160}, + 50: {"version": 1, "name": "M3 2.6\"", "width": 360, "height": 184}, + 51: {"version": 3, "name": "M3 2.9\"", "width": 384, "height": 168}, + 52: {"version": 2, "name": "M3 4.2\"", "width": 400, "height": 300}, + 53: {"version": 2, "name": "M3 6.0\"", "width": 600, "height": 448}, + 54: {"version": 5, "name": "M3 7.5\"", "width": 800, "height": 480}, + 55: {"version": 3, "name": "M3 11.6\"", "width": 960, "height": 640}, + 60: {"version": 3, "name": "M3 4.2\" BWY", "width": 400, "height": 300}, + 64: {"version": 1, "name": "M3 2.9\" BW", "width": 384, "height": 168}, + 65: {"version": 1, "name": "M3 5.85\"", "width": 792, "height": 272}, + 66: {"version": 1, "name": "M3 5.85\" BW", "width": 792, "height": 272}, + 67: {"version": 2, "name": "M3 1.3\" Peghook", "width": 144, "height": 200}, + 68: {"version": 2, "name": "M3 5.81\" BW", "width": 720, "height": 256}, + 69: {"version": 3, "name": "M3 2.2 Lite\"", "width": 250, "height": 128}, + 70: {"version": 1, "name": "M3 2.2\" BW", "width": 296, "height": 160}, + 71: {"version": 4, "name": "M3 2.7\"", "width": 300, "height": 200}, + 72: {"version": 1, "name": "M3 5.81\" BWR", "width": 720, "height": 256}, + 73: {"version": 2, "name": "M3 5.81\" V2 BWR", "width": 720, "height": 256}, + 74: {"version": 1, "name": "M3 1.6\" 200px BWRY", "width": 200, "height": 200}, + 75: {"version": 1, "name": "M3 2.2\" BWRY", "width": 296, "height": 160}, + 76: {"version": 1, "name": "M3 7.5\" BWRY", "width": 800, "height": 480}, + 77: {"version": 3, "name": "M3 11.6\" BWRY", "width": 960, "height": 640}, + 78: {"version": 2, "name": "M3 2.6\" BW", "width": 360, "height": 184}, + 80: {"version": 2, "name": "HD150 5.83\" BWR", "width": 648, "height": 480}, + 84: {"version": 4, "name": "HS BW 2.13\"", "width": 256, "height": 128}, + 85: {"version": 5, "name": "HS BWR 2.13\"", "width": 256, "height": 128}, + 86: {"version": 6, "name": "HS BWR 2.66\"", "width": 296, "height": 152}, + 87: {"version": 3, "name": "TLSR BWR 1.54\"", "width": 200, "height": 200}, + 88: {"version": 3, "name": "TLSR BW 2.13\"", "width": 256, "height": 128}, + 89: {"version": 3, "name": "TLSR BWR 2.13\"", "width": 264, "height": 136}, + 90: {"version": 1, "name": "HS BW 2.13\" LowRes", "width": 212, "height": 104}, + 96: {"version": 6, "name": "HS BWY 3.5\"", "width": 384, "height": 184}, + 97: {"version": 4, "name": "HS BWR 3.5\"", "width": 384, "height": 184}, + 98: {"version": 4, "name": "HS BW 3.5\"", "width": 384, "height": 184}, + 99: {"version": 6, "name": "TLSR BWR 4.2\"", "width": 400, "height": 300}, + 102: {"version": 2, "name": "HS BWY 7,5\"", "width": 800, "height": 480}, + 103: {"version": 3, "name": "HS 2.00\" BWY", "width": 152, "height": 200}, + 104: {"version": 4, "name": "HS BWY 3.46\"", "width": 480, "height": 176}, + 105: {"version": 4, "name": "TLSR BW 2.13\"", "width": 250, "height": 136}, + 106: {"version": 1, "name": "HS BWR 5,83\"", "width": 648, "height": 480}, + 107: {"version": 3, "name": "HS BWRY 7,5\"", "width": 800, "height": 480}, + 108: {"version": 3, "name": "HS BWRY 2,00\"", "width": 152, "height": 200}, + 109: {"version": 3, "name": "HS BWRY 3,5\"", "width": 384, "height": 184}, + 110: {"version": 3, "name": "HS BWRY 2,9\"", "width": 296, "height": 128}, + 111: {"version": 2, "name": "HS BWRY 2,60\"", "width": 296, "height": 152}, + 128: {"version": 1, "name": "Chroma 7.4\"", "width": 640, "height": 384}, + 129: {"version": 2, "name": "Chroma Aeon 74 7.4\"", "width": 800, "height": 480}, + 130: {"version": 2, "name": "Chroma29 2.9\"", "width": 296, "height": 128}, + 131: {"version": 2, "name": "Chroma42 4.2\"", "width": 400, "height": 300}, + 176: {"version": 5, "name": "Gicisky BLE EPD BW 2.13\"", "width": 250, "height": 128}, + 177: {"version": 5, "name": "Gicisky BLE EPD BWR 2.13\"", "width": 250, "height": 128}, + 178: {"version": 2, "name": "Gicisky BLE EPD BW 2.9\"", "width": 296, "height": 128}, + 179: {"version": 2, "name": "Gicisky BLE EPD BWR 2.9\"", "width": 296, "height": 128}, + 181: {"version": 2, "name": "Gicisky BLE EPD BWR 4.2\"", "width": 400, "height": 300}, + 186: {"version": 5, "name": "Gicisky BLE TFT 2.13\"", "width": 250, "height": 136}, + 189: {"version": 2, "name": "BLE EPD BWR 2.9\" Silabs", "width": 384, "height": 168}, + 190: {"version": 1, "name": "ATC MiThermometer BLE", "width": 6, "height": 8}, + 192: {"version": 2, "name": "BWRY example", "width": 360, "height": 180}, + 226: {"version": 1, "name": "LILYGO TPANEL 4\"", "width": 480, "height": 480}, + 227: {"version": 1, "name": "GDEM1085Z51 10.85\"", "width": 1360, "height": 480}, + 228: {"version": 1, "name": "BLE TFT 128x128", "width": 128, "height": 128}, + 229: {"version": 1, "name": "TFT 240x320", "width": 320, "height": 172}, + 240: {"version": 2, "name": "SLT‐EM007 Segmented", "width": 0, "height": 0}, + 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0}, +} diff --git a/custom_components/opendisplay/tag_types.py b/custom_components/opendisplay/tag_types.py index 6a1595b..25f4776 100644 --- a/custom_components/opendisplay/tag_types.py +++ b/custom_components/opendisplay/tag_types.py @@ -12,7 +12,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import storage -from .const import DOMAIN +from .const import DOMAIN, FALLBACK_TAG_DEFINITIONS _LOGGER = logging.getLogger(__name__) @@ -475,99 +475,8 @@ def _load_fallback_types(self) -> None: The fallback types include all tag definitions from the OpenEPaperLink repository at: https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/resources/tagtypes """ - fallback_definitions = { - 0: {"version": 4, "name": "M2 1.54\"", "width": 152, "height": 152}, - 1: {"version": 5, "name": "M2 2.9\"", "width": 296, "height": 128}, - 2: {"version": 5, "name": "M2 4.2\"", "width": 400, "height": 300}, - 3: {"version": 6, "name": "M2 2.2\"", "width": 212, "height": 104}, - 4: {"version": 4, "name": "M2 2.6\"", "width": 296, "height": 152}, - 5: {"version": 4, "name": "M2 7.4\"", "width": 640, "height": 384}, - 6: {"version": 4, "name": "Opticon 2.2\"", "width": 250, "height": 128}, - 7: {"version": 4, "name": "Opticon 2.9\"", "width": 296, "height": 128}, - 8: {"version": 2, "name": "Opticon 4.2\"", "width": 400, "height": 300}, - 9: {"version": 2, "name": "Opticon 7.5\"", "width": 640, "height": 384}, - 17: {"version": 3, "name": "M2 2.9\" (UC8151)", "width": 296, "height": 128}, - 18: {"version": 3, "name": "M2 4.2\" UC", "width": 400, "height": 300}, - 33: {"version": 2, "name": "ST‐GM29XXF 2.9\"", "width": 296, "height": 128}, - 34: {"version": 2, "name": "M2 2.7\"", "width": 264, "height": 176}, - 38: {"version": 1, "name": "M2 7.5\" BW", "width": 640, "height": 384}, - 39: {"version": 3, "name": "ST‐GM29MT1 2.9\"", "width": 296, "height": 128}, - 40: {"version": 2, "name": "M3 1.6\" BWRY", "width": 168, "height": 168}, - 41: {"version": 1, "name": "M3 2.4\" BWRY", "width": 296, "height": 168}, - 42: {"version": 1, "name": "M3 3.0\" BWRY", "width": 400, "height": 168}, - 43: {"version": 1, "name": "M3 2.9\" BWRY", "width": 384, "height": 168}, - 44: {"version": 1, "name": "M3 4.3\" BWRY", "width": 522, "height": 152}, - 45: {"version": 2, "name": "M3 12.2\"", "width": 960, "height": 768}, - 46: {"version": 5, "name": "M3 9.7\"", "width": 960, "height": 672}, - 47: {"version": 4, "name": "M3 4.3\"", "width": 522, "height": 152}, - 48: {"version": 2, "name": "M3 1.6\"", "width": 200, "height": 200}, - 49: {"version": 1, "name": "M3 2.2\"", "width": 296, "height": 160}, - 50: {"version": 1, "name": "M3 2.6\"", "width": 360, "height": 184}, - 51: {"version": 3, "name": "M3 2.9\"", "width": 384, "height": 168}, - 52: {"version": 2, "name": "M3 4.2\"", "width": 400, "height": 300}, - 53: {"version": 2, "name": "M3 6.0\"", "width": 600, "height": 448}, - 54: {"version": 5, "name": "M3 7.5\"", "width": 800, "height": 480}, - 55: {"version": 3, "name": "M3 11.6\"", "width": 960, "height": 640}, - 60: {"version": 3, "name": "M3 4.2\" BWY", "width": 400, "height": 300}, - 64: {"version": 1, "name": "M3 2.9\" BW", "width": 384, "height": 168}, - 65: {"version": 1, "name": "M3 5.85\"", "width": 792, "height": 272}, - 66: {"version": 1, "name": "M3 5.85\" BW", "width": 792, "height": 272}, - 67: {"version": 2, "name": "M3 1.3\" Peghook", "width": 144, "height": 200}, - 68: {"version": 2, "name": "M3 5.81\" BW", "width": 720, "height": 256}, - 69: {"version": 3, "name": "M3 2.2 Lite\"", "width": 250, "height": 128}, - 70: {"version": 1, "name": "M3 2.2\" BW", "width": 296, "height": 160}, - 71: {"version": 4, "name": "M3 2.7\"", "width": 300, "height": 200}, - 72: {"version": 1, "name": "M3 5.81\" BWR", "width": 720, "height": 256}, - 73: {"version": 2, "name": "M3 5.81\" V2 BWR", "width": 720, "height": 256}, - 74: {"version": 1, "name": "M3 1.6\" 200px BWRY", "width": 200, "height": 200}, - 75: {"version": 1, "name": "M3 2.2\" BWRY", "width": 296, "height": 160}, - 76: {"version": 1, "name": "M3 7.5\" BWRY", "width": 800, "height": 480}, - 77: {"version": 3, "name": "M3 11.6\" BWRY", "width": 960, "height": 640}, - 78: {"version": 2, "name": "M3 2.6\" BW", "width": 360, "height": 184}, - 80: {"version": 2, "name": "HD150 5.83\" BWR", "width": 648, "height": 480}, - 84: {"version": 4, "name": "HS BW 2.13\"", "width": 256, "height": 128}, - 85: {"version": 5, "name": "HS BWR 2.13\"", "width": 256, "height": 128}, - 86: {"version": 6, "name": "HS BWR 2.66\"", "width": 296, "height": 152}, - 87: {"version": 3, "name": "TLSR BWR 1.54\"", "width": 200, "height": 200}, - 88: {"version": 3, "name": "TLSR BW 2.13\"", "width": 256, "height": 128}, - 89: {"version": 3, "name": "TLSR BWR 2.13\"", "width": 264, "height": 136}, - 90: {"version": 1, "name": "HS BW 2.13\" LowRes", "width": 212, "height": 104}, - 96: {"version": 6, "name": "HS BWY 3.5\"", "width": 384, "height": 184}, - 97: {"version": 4, "name": "HS BWR 3.5\"", "width": 384, "height": 184}, - 98: {"version": 4, "name": "HS BW 3.5\"", "width": 384, "height": 184}, - 99: {"version": 6, "name": "TLSR BWR 4.2\"", "width": 400, "height": 300}, - 102: {"version": 2, "name": "HS BWY 7,5\"", "width": 800, "height": 480}, - 103: {"version": 3, "name": "HS 2.00\" BWY", "width": 152, "height": 200}, - 104: {"version": 4, "name": "HS BWY 3.46\"", "width": 480, "height": 176}, - 105: {"version": 4, "name": "TLSR BW 2.13\"", "width": 250, "height": 136}, - 106: {"version": 1, "name": "HS BWR 5,83\"", "width": 648, "height": 480}, - 107: {"version": 3, "name": "HS BWRY 7,5\"", "width": 800, "height": 480}, - 108: {"version": 3, "name": "HS BWRY 2,00\"", "width": 152, "height": 200}, - 109: {"version": 3, "name": "HS BWRY 3,5\"", "width": 384, "height": 184}, - 110: {"version": 3, "name": "HS BWRY 2,9\"", "width": 296, "height": 128}, - 111: {"version": 2, "name": "HS BWRY 2,60\"", "width": 296, "height": 152}, - 128: {"version": 1, "name": "Chroma 7.4\"", "width": 640, "height": 384}, - 129: {"version": 2, "name": "Chroma Aeon 74 7.4\"", "width": 800, "height": 480}, - 130: {"version": 2, "name": "Chroma29 2.9\"", "width": 296, "height": 128}, - 131: {"version": 2, "name": "Chroma42 4.2\"", "width": 400, "height": 300}, - 176: {"version": 5, "name": "Gicisky BLE EPD BW 2.13\"", "width": 250, "height": 128}, - 177: {"version": 5, "name": "Gicisky BLE EPD BWR 2.13\"", "width": 250, "height": 128}, - 178: {"version": 2, "name": "Gicisky BLE EPD BW 2.9\"", "width": 296, "height": 128}, - 179: {"version": 2, "name": "Gicisky BLE EPD BWR 2.9\"", "width": 296, "height": 128}, - 181: {"version": 2, "name": "Gicisky BLE EPD BWR 4.2\"", "width": 400, "height": 300}, - 186: {"version": 5, "name": "Gicisky BLE TFT 2.13\"", "width": 250, "height": 136}, - 189: {"version": 2, "name": "BLE EPD BWR 2.9\" Silabs", "width": 384, "height": 168}, - 190: {"version": 1, "name": "ATC MiThermometer BLE", "width": 6, "height": 8}, - 192: {"version": 2, "name": "BWRY example", "width": 360, "height": 180}, - 226: {"version": 1, "name": "LILYGO TPANEL 4\"", "width": 480, "height": 480}, - 227: {"version": 1, "name": "GDEM1085Z51 10.85\"", "width": 1360, "height": 480}, - 228: {"version": 1, "name": "BLE TFT 128x128", "width": 128, "height": 128}, - 229: {"version": 1, "name": "TFT 240x320", "width": 320, "height": 172}, - 240: {"version": 2, "name": "SLT‐EM007 Segmented", "width": 0, "height": 0}, - 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0}, - } self._tag_types = { - type_id: TagType(type_id, data) for type_id, data in fallback_definitions.items() + type_id: TagType(type_id, data) for type_id, data in FALLBACK_TAG_DEFINITIONS.items() } self._last_update = datetime.now() _LOGGER.warning("Loaded fallback tag definitions") diff --git a/scripts/generate_tag_types.py b/scripts/generate_tag_types.py index a467bb3..07b7f60 100644 --- a/scripts/generate_tag_types.py +++ b/scripts/generate_tag_types.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -"""Generate updated tag_types.py from fetched tag type definitions. +"""Generate updated const.py from fetched tag type definitions. Reads a JSON file of tag type definitions (produced by fetch_tag_types.py), -compares them against the current fallback definitions in tag_types.py, +compares them against the current fallback definitions in const.py, and updates the file if there are changes. Sets GitHub Actions outputs for downstream workflow steps. @@ -14,9 +14,9 @@ import sys -TAG_TYPES_PATH = "custom_components/opendisplay/tag_types.py" +CONST_PATH = "custom_components/opendisplay/const.py" FALLBACK_PATTERN = re.compile( - r"( fallback_definitions = \{)\n(.*?)\n( \})", re.DOTALL + r"(FALLBACK_TAG_DEFINITIONS = \{)\n(.*?)\n(\})", re.DOTALL ) ENTRY_PATTERN = re.compile(r"\s+(\d+):") @@ -29,10 +29,10 @@ def load_new_tag_types(input_file): def parse_current_definitions(content): - """Extract current fallback definitions from tag_types.py content.""" + """Extract current fallback definitions from const.py content.""" match = FALLBACK_PATTERN.search(content) if not match: - print("Error: Could not find fallback_definitions in tag_types.py") + print("Error: Could not find FALLBACK_TAG_DEFINITIONS in const.py") sys.exit(1) current_types = {} @@ -67,20 +67,20 @@ def compute_changes(current_types, new_tag_types): def generate_fallback_content(new_tag_types): - """Generate the new fallback_definitions dict content.""" + """Generate the new FALLBACK_TAG_DEFINITIONS dict content.""" lines = [] for type_id in sorted(new_tag_types.keys()): type_data = new_tag_types[type_id] - line = f" {type_id}: {json.dumps(type_data, ensure_ascii=False)}," + line = f" {type_id}: {json.dumps(type_data, ensure_ascii=False)}," lines.append(line) return "\n".join(lines) def update_tag_types_file(content, new_fallback): - """Replace fallback_definitions content in tag_types.py.""" + """Replace FALLBACK_TAG_DEFINITIONS content in const.py.""" match = FALLBACK_PATTERN.search(content) if not match: - print("Error: Could not find fallback_definitions in tag_types.py") + print("Error: Could not find FALLBACK_TAG_DEFINITIONS in const.py") sys.exit(1) start = match.start(2) @@ -119,12 +119,12 @@ def set_github_output(changed, summary): def main(): - """Generate updated tag_types.py from fetched definitions.""" + """Generate updated const.py from fetched definitions.""" input_file = sys.argv[1] if len(sys.argv) > 1 else "new_tag_types.json" new_tag_types = load_new_tag_types(input_file) - with open(TAG_TYPES_PATH, "r") as f: + with open(CONST_PATH, "r") as f: content = f.read() current_types = parse_current_definitions(content) @@ -138,7 +138,7 @@ def main(): new_fallback = generate_fallback_content(new_tag_types) new_content = update_tag_types_file(content, new_fallback) - with open(TAG_TYPES_PATH, "w") as f: + with open(CONST_PATH, "w") as f: f.write(new_content) summary = build_summary(added, removed, modified) diff --git a/tests/scripts/test_sync_tag_types.py b/tests/scripts/test_sync_tag_types.py index f35eeff..71e4475 100644 --- a/tests/scripts/test_sync_tag_types.py +++ b/tests/scripts/test_sync_tag_types.py @@ -22,26 +22,23 @@ # Fixtures # --------------------------------------------------------------------------- -SAMPLE_TAG_TYPES_PY = textwrap.dedent("""\ - class Foo: - def _load_fallback_types(self): - fallback_definitions = { - 0: {"version": 4, "name": "M2 1.54\\"", "width": 152, "height": 152}, - 1: {"version": 5, "name": "M2 2.9\\"", "width": 296, "height": 128}, - 240: {"version": 2, "name": "SLT\u2010EM007 Segmented", "width": 0, "height": 0}, - 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0}, - } - self._tag_types = { - type_id: TagType(type_id, data) for type_id, data in fallback_definitions.items() - } +SAMPLE_CONST_PY = textwrap.dedent("""\ + DOMAIN = "opendisplay" + + FALLBACK_TAG_DEFINITIONS = { + 0: {"version": 4, "name": "M2 1.54\\"", "width": 152, "height": 152}, + 1: {"version": 5, "name": "M2 2.9\\"", "width": 296, "height": 128}, + 240: {"version": 2, "name": "SLT\u2010EM007 Segmented", "width": 0, "height": 0}, + 250: {"version": 1, "name": "ConfigMode", "width": 0, "height": 0}, + } """) @pytest.fixture -def tag_types_file(tmp_path): - """Write a minimal tag_types.py and return its path.""" - p = tmp_path / "tag_types.py" - p.write_text(SAMPLE_TAG_TYPES_PY) +def const_file(tmp_path): + """Write a minimal const.py and return its path.""" + p = tmp_path / "const.py" + p.write_text(SAMPLE_CONST_PY) return p @@ -83,23 +80,23 @@ def test_values_preserved(self, new_types_json): # --------------------------------------------------------------------------- class TestParseCurrentDefinitions: - """Tests for parsing fallback_definitions from tag_types.py.""" + """Tests for parsing FALLBACK_TAG_DEFINITIONS from const.py.""" - def test_parses_all_entries(self, tag_types_file): - """Should parse all entries from the fallback_definitions block.""" - content = tag_types_file.read_text() + def test_parses_all_entries(self, const_file): + """Should parse all entries from the FALLBACK_TAG_DEFINITIONS block.""" + content = const_file.read_text() result = generate_tag_types.parse_current_definitions(content) assert len(result) == 4 assert set(result.keys()) == {0, 1, 240, 250} - def test_keys_are_integers(self, tag_types_file): + def test_keys_are_integers(self, const_file): """Parsed keys must be integers.""" - content = tag_types_file.read_text() + content = const_file.read_text() result = generate_tag_types.parse_current_definitions(content) assert all(isinstance(k, int) for k in result.keys()) def test_exits_on_missing_block(self): - """Should exit if fallback_definitions block is not found.""" + """Should exit if FALLBACK_TAG_DEFINITIONS block is not found.""" with pytest.raises(SystemExit): generate_tag_types.parse_current_definitions("no such block here") @@ -166,13 +163,13 @@ def test_sorting(self): # --------------------------------------------------------------------------- class TestGenerateFallbackContent: - """Tests for generating the fallback_definitions dict content.""" + """Tests for generating the FALLBACK_TAG_DEFINITIONS dict content.""" def test_format(self): - """Each line should have 12-space indent, type_id, JSON data, and trailing comma.""" + """Each line should have 4-space indent, type_id, JSON data, and trailing comma.""" data = {0: {"version": 1, "name": "Tag", "width": 10, "height": 20}} content = generate_tag_types.generate_fallback_content(data) - assert content.startswith(" 0:") + assert content.startswith(" 0:") assert content.endswith(",") def test_sorted_numerically(self): @@ -203,39 +200,38 @@ def test_unicode_chars_preserved(self): # --------------------------------------------------------------------------- class TestUpdateTagTypesFile: - """Tests for replacing fallback_definitions in file content.""" + """Tests for replacing FALLBACK_TAG_DEFINITIONS in file content.""" - def test_replaces_content(self, tag_types_file): + def test_replaces_content(self, const_file): """The fallback block should be replaced with new content.""" - content = tag_types_file.read_text() - new_fallback = ' 999: {"version": 1, "name": "New", "width": 1, "height": 1},' + content = const_file.read_text() + new_fallback = ' 999: {"version": 1, "name": "New", "width": 1, "height": 1},' result = generate_tag_types.update_tag_types_file(content, new_fallback) assert "999:" in result # Old entries removed assert "250:" not in result - def test_preserves_surrounding_code(self, tag_types_file): - """Code around fallback_definitions should be unchanged.""" - content = tag_types_file.read_text() - new_fallback = ' 999: {"version": 1, "name": "New", "width": 1, "height": 1},' + def test_preserves_surrounding_code(self, const_file): + """Code around FALLBACK_TAG_DEFINITIONS should be unchanged.""" + content = const_file.read_text() + new_fallback = ' 999: {"version": 1, "name": "New", "width": 1, "height": 1},' result = generate_tag_types.update_tag_types_file(content, new_fallback) - assert "class Foo:" in result - assert "self._tag_types" in result + assert "DOMAIN" in result - def test_unicode_in_replacement(self, tag_types_file): + def test_unicode_in_replacement(self, const_file): """Unicode escape sequences in replacement must not cause regex errors. This is the primary bug that was fixed: json.dumps() produces \\uXXXX sequences which re.sub() would interpret as bad regex escapes. """ - content = tag_types_file.read_text() + content = const_file.read_text() # This would fail with re.sub() because \u2010 is a bad regex escape - new_fallback = ' 240: {"version": 2, "name": "SLT\\u2010EM007", "width": 0, "height": 0},' + new_fallback = ' 240: {"version": 2, "name": "SLT\\u2010EM007", "width": 0, "height": 0},' result = generate_tag_types.update_tag_types_file(content, new_fallback) assert "\\u2010" in result def test_exits_on_missing_block(self): - """Should exit if fallback_definitions block is not found.""" + """Should exit if FALLBACK_TAG_DEFINITIONS block is not found.""" with pytest.raises(SystemExit): generate_tag_types.update_tag_types_file("no such block", "replacement") @@ -289,17 +285,17 @@ def test_no_op_without_env(self, tmp_path): class TestMainIntegration: """Integration tests for the full generate_tag_types.main() flow.""" - def test_no_change_run(self, tag_types_file, new_types_json, tmp_path): + def test_no_change_run(self, const_file, new_types_json, tmp_path): """When data matches, output changed=false.""" output_file = tmp_path / "output.txt" output_file.write_text("") - with patch.object(generate_tag_types, "TAG_TYPES_PATH", str(tag_types_file)), \ + with patch.object(generate_tag_types, "CONST_PATH", str(const_file)), \ patch.dict(os.environ, {"GITHUB_OUTPUT": str(output_file)}), \ patch("sys.argv", ["prog", str(new_types_json)]): generate_tag_types.main() assert "changed=false" in output_file.read_text() - def test_added_type_run(self, tag_types_file, tmp_path): + def test_added_type_run(self, const_file, tmp_path): """When a new type is added, output changed=true and file is updated.""" data = { 0: {"version": 4, "name": 'M2 1.54"', "width": 152, "height": 152}, @@ -313,12 +309,12 @@ def test_added_type_run(self, tag_types_file, tmp_path): output_file = tmp_path / "output.txt" output_file.write_text("") - with patch.object(generate_tag_types, "TAG_TYPES_PATH", str(tag_types_file)), \ + with patch.object(generate_tag_types, "CONST_PATH", str(const_file)), \ patch.dict(os.environ, {"GITHUB_OUTPUT": str(output_file)}), \ patch("sys.argv", ["prog", str(json_file)]): generate_tag_types.main() assert "changed=true" in output_file.read_text() - updated = tag_types_file.read_text() + updated = const_file.read_text() assert "999:" in updated assert "Brand New" in updated