From 28f14fe3a7c08c1b3417b0627a5d32db990d3db8 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Fri, 5 Sep 2025 16:45:12 +0200 Subject: [PATCH] Derive proper User class from NickUserSet, with additional .modes field. --- ircplom/client.py | 59 +++++++++++++++++-------------- ircplom/client_tui.py | 7 ++-- ircplom/msg_parse_expectations.py | 4 +-- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ircplom/client.py b/ircplom/client.py index 69581e4..74f868c 100644 --- a/ircplom/client.py +++ b/ircplom/client.py @@ -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) diff --git a/ircplom/client_tui.py b/ircplom/client_tui.py index 42bd8c7..dc7c0fa 100644 --- a/ircplom/client_tui.py +++ b/ircplom/client_tui.py @@ -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} diff --git a/ircplom/msg_parse_expectations.py b/ircplom/msg_parse_expectations.py index 4d372b6..bd6d29d 100644 --- a/ircplom/msg_parse_expectations.py +++ b/ircplom/msg_parse_expectations.py @@ -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', -- 2.30.2