Commit 2e0b167c2f for bind

commit 2e0b167c2f637c2791ea313b885efe6b9ca669e3
Author: Nicki Křížek <nicki@isc.org>
Date:   Wed Oct 21 15:05:24 2026 +0000

    Make VarLookup a read-only Mapping

    Subclassing ChainMap left VarLookup open to del, pop, clear and |=,
    all of which modify the first of the coalesced module dicts, and makes
    pylint 4.1 flag ALL as a dangerous default value in TemplateEngine.

    Assisted-by: Claude:claude-opus-5-5

diff --git a/bin/tests/system/isctest/vars/all.py b/bin/tests/system/isctest/vars/all.py
index 0726326359..465dbf747b 100644
--- a/bin/tests/system/isctest/vars/all.py
+++ b/bin/tests/system/isctest/vars/all.py
@@ -9,7 +9,8 @@
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.

-from collections import ChainMap
+from collections.abc import Iterator, Mapping
+from typing import Any

 from .algorithms import ALG_VARS, CRYPTO_SUPPORTED_VARS
 from .basic import BASIC_VARS
@@ -20,37 +21,37 @@ from .openssl import OPENSSL_VARS
 from .ports import PORT_VARS


-class VarLookup(ChainMap):
+class VarLookup(Mapping[str, Any]):
     """
-    A dictionary-like structure to coalesce the variables from different
-    modules without making a copy (which would prevent updating these values
-    from inside the modules). Values which are None are treated as unset when
+    A read-only mapping to coalesce the variables from different modules
+    without making a copy (which would prevent updating these values from
+    inside the modules). Values which are None are treated as unset when
     iterating.
     """

-    def __init__(self, *maps):
-        keys = set()
+    def __init__(self, *maps: Mapping[str, str | None]):
+        keys: set[str] = set()
         for m in maps:
             overlap = keys.intersection(m.keys())
             if overlap:
                 raise RuntimeError(f"key(s) are defined multiple times: {overlap}")
             keys = keys.union(m.keys())
-        super().__init__(*maps)
+        self._maps = maps

-    def __setitem__(self, *args, **kwargs):
-        raise RuntimeError("read-only structure")
+    def __getitem__(self, key: str) -> Any:
+        for m in self._maps:
+            if key in m:
+                return m[key]
+        raise KeyError(key)

-    def keys(self):
-        result = set()
-        for m in self.maps:
+    def __iter__(self) -> Iterator[str]:
+        for m in self._maps:
             for key, val in m.items():
-                if val is None:  # treat None as unset
-                    continue
-                result.add(key)
-        return list(result)
+                if val is not None:
+                    yield key

-    def __iter__(self):
-        return iter(self.keys())
+    def __len__(self) -> int:
+        return sum(1 for _ in self)


 ALL = VarLookup(