home · contact · privacy
Refactor ClientDb type safety, disallow direct attribut setting.
authorChristian Heller <c.heller@plomlompom.de>
Thu, 14 Aug 2025 14:53:56 +0000 (16:53 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 14 Aug 2025 14:53:56 +0000 (16:53 +0200)
ircplom/client.py
ircplom/client_tui.py

index 563c69e1cacf0aed462c6ead439713fb419f813b..1cd66acda65714c4603c2f270eaac6b88855065a 100644 (file)
@@ -192,13 +192,20 @@ class ClientDbBase:
             return value
         return None
 
+    def __setattr__(self, key: str, value) -> None:
+        raise CrashingException('no direct attribute setting, use .set() etc.')
+
     @classmethod
-    def _typecheck(cls, key: str, value: ClientDbType) -> None:
+    def _type_for(cls, key):
         candidates = [c.__annotations__[key] for c in cls.__mro__
                       if c is not object and key in c.__annotations__]
         if not candidates:
             raise CrashingException(f'{cls} lacks annotation for {key}')
-        type_ = candidates[0]
+        return candidates[0]
+
+    @classmethod
+    def _typecheck(cls, key: str, value: ClientDbType) -> None:
+        type_ = cls._type_for(key)
         fail = True
         type_found = str(type(value))
         if not isinstance(type_, type):              # gotta be GenericAlias, …
@@ -275,14 +282,13 @@ class _ClientDb(ClientDbBase):
     def conn_setup(self) -> IrcConnSetup:
         'Constructed out of stored entries *including* unconfirmed ones.'
         kwargs: dict[str, ClientDbType] = {}
-        for field_name in IrcConnSetup._fields:
-            val = self._dict.get(field_name, None)
+        for name in IrcConnSetup._fields:
+            val = self._dict.get(name, None)
             if val is None:
-                raise CrashingException(f'field not set: {field_name}')
-            if not isinstance(val, IrcConnSetup.__annotations__[field_name]):
-                raise CrashingException(
-                    f'wrong type for {field_name}: {type(val)} (value: {val})')
-            kwargs[field_name] = val
+                raise CrashingException(f'field not set: {name}')
+            assert self._type_for(name) == IrcConnSetup.__annotations__[name]
+            self._typecheck(name, val)
+            kwargs[name] = val
         return IrcConnSetup(**kwargs)  # type: ignore  # enough tests above
 
     @property
index 0a639cd17898c06e6f2fa89f4841609ce3a8a6f2..b7541fe1f4a97d5eca6718df0f79ade8acdfa69e 100644 (file)
@@ -105,7 +105,6 @@ class _ChatWindow(_ClientWindow):
     def set_prompt_prefix(self) -> None:
         'Look up relevant DB data to update prompt prefix.'
         retrieval = self._get_nick_data()
-        assert isinstance(retrieval[0], str)
         self.prompt.set_prefix_data(*retrieval)
 
     def cmd__chat(self, msg: str) -> None: