home · contact · privacy
Derive proper User class from NickUserSet, with additional .modes field.
authorChristian Heller <c.heller@plomlompom.de>
Fri, 5 Sep 2025 14:45:12 +0000 (16:45 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Fri, 5 Sep 2025 14:45:12 +0000 (16:45 +0200)
ircplom/client.py
ircplom/client_tui.py
ircplom/msg_parse_expectations.py

index 69581e436d6bf98b496a2c38581f588f6a64d93d..74f868c06e6ccf876ae86106c09d1a4441dec42a 100644 (file)
@@ -249,7 +249,6 @@ class SharedClientDbFields(IrcConnSetup):
     isupport: Dict[str]
     sasl_account: str = ''
     sasl_auth_state: str = ''
-    user_modes: str = ''
 
     def is_chan_name(self, name: str) -> bool:
         'Tests name to match CHANTYPES prefixes.'
@@ -360,12 +359,12 @@ class _Channel:
     topic: _CompletableTopic
 
     def __init__(self,
-                 id_for_nickuserhost: Callable,
+                 userid_for_nickuserhost: Callable,
                  get_membership_prefixes: Callable,
                  purge_users: Callable,
                  **kwargs
                  ) -> None:
-        self._id_for_nickuserhost = id_for_nickuserhost
+        self._userid_for_nickuserhost = userid_for_nickuserhost
         self._get_membership_prefixes = get_membership_prefixes
         self.purge_users = purge_users
         super().__init__(**kwargs)
@@ -374,19 +373,18 @@ class _Channel:
         'Add to .user_ids items assumed as nicknames with membership prefixes.'
         for item in items:
             nickname = item.lstrip(self._get_membership_prefixes())
-            self.user_ids.append(
-                    self._id_for_nickuserhost(_NickUserHost(nickname),
-                                              create_if_none=True))
-
-    def append_nick(self, nickuserhost: '_NickUserHost') -> None:
-        'To .user_ids append .nickname and declare .user_ids complete.'
-        user_id = self._id_for_nickuserhost(nickuserhost, create_if_none=True,
-                                            updating=True)
+            self.user_ids.append(self._userid_for_nickuserhost(
+                NickUserHost(nickname), create_if_none=True))
+
+    def append_user(self, user: '_User') -> None:
+        'To .user_ids append user.nickname and declare .user_ids complete.'
+        user_id = self._userid_for_nickuserhost(user, create_if_none=True,
+                                                updating=True)
         self.user_ids.append(user_id, complete=True)
 
-    def remove_nick(self, nickuserhost: '_NickUserHost') -> None:
+    def remove_user(self, user: '_User') -> None:
         'From .user_ids remove .nickname and declare .user_ids complete.'
-        user_id = self._id_for_nickuserhost(nickuserhost)
+        user_id = self._userid_for_nickuserhost(user)
         self.user_ids.remove(user_id, complete=True)
         self.purge_users()
 
@@ -430,6 +428,15 @@ class _NickUserHost(NickUserHost):
         return name + str(0 if not digits else (int(digits) + 1))
 
 
+class _User(NickUserHost):
+    modes: str = '?'
+
+    @classmethod
+    def from_nickuserhost(cls, nuh: NickUserHost) -> Self:
+        'Create with nuh fields set.'
+        return cls(nuh.nick, nuh.user, nuh.host)
+
+
 class _UpdatingServerCapability(_UpdatingMixin, ServerCapability):
     pass
 
@@ -443,7 +450,7 @@ class _UpdatingChannel(_UpdatingMixin, _Channel):
     topic: _UpdatingCompletableTopic
 
 
-class _UpdatingNickUserHost(_UpdatingMixin, _NickUserHost):
+class _UpdatingUser(_UpdatingMixin, _User):
     pass
 
 
@@ -453,7 +460,7 @@ class _ClientDb(_UpdatingMixin, SharedClientDbFields):
     channels: _UpdatingDict[_UpdatingChannel]
     isupport: _UpdatingDict[str]
     motd: _UpdatingCompletableStringsList
-    users: _UpdatingDict[_UpdatingNickUserHost]
+    users: _UpdatingDict[_UpdatingUser]
 
     def __getattribute__(self, key: str):
         attr = super().__getattribute__(key)
@@ -461,7 +468,7 @@ class _ClientDb(_UpdatingMixin, SharedClientDbFields):
             attr._defaults = ISUPPORT_DEFAULTS
         elif key == 'channels' and not attr._create_if_none:
             attr._create_if_none = {
-                    'id_for_nickuserhost': self.userid_for_nickuserhost,
+                    'userid_for_nickuserhost': self.userid_for_nickuserhost,
                     'get_membership_prefixes': self._get_membership_prefixes,
                     'purge_users': self.purge_users}
         return attr
@@ -503,16 +510,14 @@ class _ClientDb(_UpdatingMixin, SharedClientDbFields):
         assert toks[0][0] == '('
         return toks[1]
 
-    def chans_of_user(self,
-                      nickuserhost: _NickUserHost
-                      ) -> dict[str, _UpdatingChannel]:
+    def chans_of_user(self, user: _User) -> dict[str, _UpdatingChannel]:
         'Return dictionary of channels user is in.'
-        id_ = self.userid_for_nickuserhost(nickuserhost)
+        id_ = self.userid_for_nickuserhost(user)
         return {k: self.channels[k] for k in self.channels.keys()
                 if id_ in self.channels[k].user_ids.completed}
 
     def userid_for_nickuserhost(self,
-                                nickuserhost: _NickUserHost,
+                                nickuserhost: NickUserHost,
                                 create_if_none=False,
                                 allow_none=False,
                                 updating=False
@@ -547,7 +552,7 @@ class _ClientDb(_UpdatingMixin, SharedClientDbFields):
                 assert stored.user != '?'
         elif create_if_none:
             id_ = str(uuid4())
-            self.users.set_updating(id_, nickuserhost)
+            self.users.set_updating(id_, _User.from_nickuserhost(nickuserhost))
         else:
             return None
         return id_
@@ -652,7 +657,7 @@ class Client(ABC, ClientQueueMixin):
 
     def _on_connect(self) -> None:
         assert self.conn is not None
-        self.db.users.set_updating('me', _NickUserHost('?', getuser(), '?'))
+        self.db.users.set_updating('me', _User('?', getuser(), '?'))
         self.db.connection_state = 'connected'
         self.caps.start_negotation()
         self.send(IrcMessage(verb='USER', params=(
@@ -716,7 +721,7 @@ class Client(ABC, ClientQueueMixin):
         if '_verb' not in ret:
             self._log(f'PLEASE IMPLEMENT HANDLER FOR: {msg.raw}')
             return
-        for n_u_h in ret['_nickuserhosts']:  # update, ensure identities
+        for n_u_h in ret['_nickuserhosts']:  # update, turn into proper users
             if (id_ := self.db.userid_for_nickuserhost(n_u_h, allow_none=True,
                                                        updating=True)):
                 for ret_name in [k for k in ret if ret[k] is n_u_h]:
@@ -775,7 +780,7 @@ class Client(ABC, ClientQueueMixin):
                 else:
                     self.caps.end_negotiation()
         elif ret['_verb'] == 'JOIN' and ret['joiner'] != self.db.users['me']:
-            self.db.channels[ret['channel']].append_nick(ret['joiner'])
+            self.db.channels[ret['channel']].append_user(ret['joiner'])
         elif ret['_verb'] == 'NICK':
             user_id = self.db.userid_for_nickuserhost(ret['named'],
                                                       updating=True)
@@ -792,7 +797,7 @@ class Client(ABC, ClientQueueMixin):
                                   else ret['channel'])}
             self._log(ret['message'], out=False, **kw)
         elif ret['_verb'] == 'PART':
-            self.db.channels[ret['channel']].remove_nick(ret['parter'])
+            self.db.channels[ret['channel']].remove_user(ret['parter'])
             if 'message' in ret:
                 self._log(f'{ret["parter"]} parts: {ret["message"]}',
                           LogScope.CHAT, target=ret['channel'])
@@ -803,7 +808,7 @@ class Client(ABC, ClientQueueMixin):
             self.send(IrcMessage(verb='PONG', params=(ret['reply'],)))
         elif ret['_verb'] == 'QUIT':
             for ch_name, ch in self.db.chans_of_user(ret['quitter']).items():
-                ch.remove_nick(ret['quitter'])
+                ch.remove_user(ret['quitter'])
                 self._log(f'{ret["quitter"]} quits: {ret["message"]}',
                           LogScope.CHAT, target=ch_name)
 
index 42bd8c7830679bce2d6c1b9159179759753c6b91..dc7c0fa1ed978ef4d53a62904ef19e2e168270e7 100644 (file)
@@ -222,9 +222,10 @@ class _UpdatingChannel(_UpdatingNode):
         return None
 
 
-class _UpdatingNickUserHost(_UpdatingNode, NickUserHost):
+class _UpdatingUser(_UpdatingNode, NickUserHost):
     log_scopes = {('nick',): LogScope.NICKNAME}
     prev_nick = '?'
+    modes = '?'
 
     @property
     def prev(self) -> str:
@@ -241,14 +242,14 @@ class _UpdatingServerCapability(_UpdatingNode, ServerCapability):
     pass
 
 
-_UPDATING_DATACLASSES = (_UpdatingNickUserHost, _UpdatingServerCapability)
+_UPDATING_DATACLASSES = (_UpdatingUser, _UpdatingServerCapability)
 
 
 class _TuiClientDb(_UpdatingNode, SharedClientDbFields):
     caps: _UpdatingDict[_UpdatingServerCapability]
     isupport: _UpdatingDict[str]
     motd: tuple[str, ...] = tuple()
-    users: _UpdatingDict[_UpdatingNickUserHost]
+    users: _UpdatingDict[_UpdatingUser]
     channels: _UpdatingDict[_UpdatingChannel]
     log_scopes = {('connection_state',): LogScope.ALL}
 
index 4d372b6337202dd5f944523330c2df44e0ac0b43..bd6d29db69f7209bceef2e1120d7baa1c326ae8a 100644 (file)
@@ -529,12 +529,12 @@ MSG_EXPECTATIONS: list[_MsgParseExpectation] = [
         'MODE',
         (_MsgTok.NICK_USER_HOST, 'setattr_db.users.me:nickuserhost'),
         ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
-         (_MsgTok.ANY, 'setattr_db:user_modes'))),
+         (_MsgTok.ANY, 'setattr_db.users.me:modes'))),
     _MsgParseExpectation(
         'MODE',
         _MsgTok.NICKNAME,
         ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
-         (_MsgTok.ANY, 'setattr_db:user_modes'))),
+         (_MsgTok.ANY, 'setattr_db.users.me:modes'))),
 
     _MsgParseExpectation(
         'PING',