cache_path: tuple[str, ...] = tuple()
for step in path[:-1]:
cache_path = cache_path + (step,)
- if cache_path in self._updates_cache:
- del self._updates_cache[cache_path]
+ if cache_path in self._updates_cache: # un-cache any path steps
+ del self._updates_cache[cache_path] # to node we deem updated
parent = (parent[step] if isinstance(parent, Dict)
else getattr(parent, step))
last_step = path[-1]
val_at_path = ((parent[last_step] if last_step in parent.keys()
else None) if isinstance(parent, Dict)
else getattr(parent, last_step))
+
+ # treat anything without UpdatingMixin as single endnode to return
+ # (NB: this would include None!)
if not isinstance(val_at_path, UpdatingMixin):
return update_unless_cached(path, val_at_path)
+
+ # for completable, only return its .completed
if isinstance(val_at_path, Completable):
if val_at_path.completed is not None:
return update_unless_cached(path, val_at_path.completed)
return []
+
+ # for empty Dict, return clearing signal
if isinstance(val_at_path, Dict) and not val_at_path.keys():
for cache_path in [p for p in self._updates_cache
if len(p) > len(path)
and p[:len(path)] == path]:
del self._updates_cache[cache_path]
return update_unless_cached(path, None)
+
+ # if node at path has children, (only) return _their_ endnode updates
if isinstance(val_at_path, Dict):
sub_items = val_at_path.keys()
else:
else self.__orig_bases__[0])
return orig_cls.__args__[0]
- # NB: Some of below wrappers around ._dict method calls were previously
- # replaced by .__getattribute__ simply returning getattr(self._dict, key).
- # This however confused subclasses super() (which doesn't check instance's
- # .__getattribute__ but looks at class method definitions), and wouldn't
- # satisfy abstractmethod slots such as for Clearable.clear.
+ # NB, not to repeat this mistake: Some of below wrappers around ._dict
+ # method calls were previously replaced by .__getattribute__ simply
+ # returning getattr(self._dict, key). This however confused subclasses'
+ # super() (which won't check instance's .__getattribute__, rather looks
+ # at class method definitions), nor satisfy abstractmethod slots such as
+ # for Clearable.clear.
def __setitem__(self, key: str, val: DictItem) -> None:
assert isinstance(val, self._item_cls), (type(val), self._item_cls)
if UpdatingMixin in self._item_cls.__mro__:
kw |= {'on_update':
lambda *steps: self._on_update(key, *steps)}
- self[key] = self._item_cls(**kw)
+ self._dict[key] = self._item_cls(**kw)
return super().__getitem__(key)
def __setitem__(self, key: str, val: DictItem) -> None:
insert ./lib/connect-to-connected
insert ./lib/cap-msg
insert ./lib/caps-neg-empty
-insert ./lib/caps-data-set
insert ./lib/cmd-disconnect
# for: cmd-disconnect
insert ./lib/disconnect
log 1 $ caps:zba:data set to: []
log 1 > CAP :LIST
insert cap-msg : + CAPMSG :foo LIST * :foo rab oof
-insert user-set-to :3 + USER_ID=me USERNICK :foo
+insert user-set-to :1 + USER_ID=me USERNICK :foo
insert cap-msg : + CAPMSG :foo LIST :zab rba
log 1 $ caps:foo:enabled set to: [True]
log 1 $ caps:oof:enabled set to: [True]
# check NEW, DEL working after CAP :END
insert cap-msg : + CAPMSG :foo NEW :foo bar=baz
-insert caps-data-set : + CAPNAME=bar CAPVAL :baz
+log 1 $ caps:bar:data set to: [baz]
log 1 $ caps:foo:data set to: []
insert cap-msg : + CAPMSG :foo DEL :sasl foo
log 1 $ caps:foo cleared
insert ./lib/join-empty
# for: join-channel-0, join-channel-1, join-empty
insert ./lib/part
-# for: exit-channel, part, parts-core, quit
+# for: exit-channel, part, part-0, part-1, parts-core, quit
insert ./lib/privmsg
insert ./lib/retry-in
insert ./lib/servermsglogged
# check /join to, and part from, channel with one other user
insert join-channel-0 : + CHANNEL=#ch_test0 RESIDENT_NAMES :foo bar
-insert user-set-to :3 + USER_ID=1 USERNICK :bar
+insert user-set-to :1 + USER_ID=1 USERNICK :bar
insert join-channel-1 : + CHANNEL=#ch_test0 RESIDENT_IDS :[1], [me]
log 3 $ residents: bar, foo
insert part : + CHANNEL=#ch_test0 CHAN_WIN_ID=3 USERIDS_CLEAR :set to: [1]
# check /join into channel with many other users, with multi-line 353
insert join-channel-0 : + CHANNEL=#ch_test0 RESIDENT_NAMES :foo baz oof
-insert user-set-to :3 + USER_ID=2 USERNICK :baz
-insert user-set-to :3 + USER_ID=3 USERNICK :oof
+insert user-set-to :1 + USER_ID=2 USERNICK :baz
+insert user-set-to :1 + USER_ID=3 USERNICK :oof
insert servermsglogged : + MSG ::foo.bar.baz 353 foo = #ch_test0 :rab zab
-insert user-set-to :3 + USER_ID=4 USERNICK :rab
-insert user-set-to :3 + USER_ID=5 USERNICK :zab
+insert user-set-to :1 + USER_ID=4 USERNICK :rab
+insert user-set-to :1 + USER_ID=5 USERNICK :zab
insert join-channel-1 : + CHANNEL=#ch_test0 RESIDENT_IDS :[2], [3], [4], [5], [me]
log 3 $ residents: baz, oof, rab, zab, foo
insert part-empty : + CHAN_WIN_ID=4 CHANNEL :#ch_test1
insert join-channel-0-0 : + CHANNEL :#ch_test1
insert servermsglogged : + MSG ::foo.bar.baz 332 foo #ch_test1 :foo bar baz
-log 1 $ channels:#ch_test1:exits cleared
insert servermsglogged : + MSG ::foo.bar.baz 333 foo #ch_test1 baz!~baz@OLD.baz.baz 1234567890
insert topic-set-to : + baz.baz=OLD.baz.baz CHANNEL=#ch_test1 NEWTOPIC :foo bar baz
-insert join-channel-0-1 :-1 + CHANNEL=#ch_test1 RESIDENT_NAMES :foo baz
+insert join-channel-0-1 : + CHANNEL=#ch_test1 RESIDENT_NAMES :foo baz
insert join-channel-1 : + CHANNEL=#ch_test1 RESIDENT_IDS :[2], [me]
log 4 $ residents: baz, foo
# check _observed_ topic change _does_ affect users database, and …
insert servermsglogged : + MSG ::baz!~baz@baz.baz TOPIC #ch_test1 :foo bar baz
-insert user-set-to 3: + USER_ID=2 USERNAME=~baz USERHOST :baz.baz
+insert user-set-to 1: + USER_ID=2 USERNAME=~baz USERHOST :baz.baz
# … is echoed into channel window _if_ either content or setter change
insert topic-set-to : + CHANNEL=#ch_test1 NEWTOPIC :foo bar baz
insert servermsglogged : + MSG ::baz!~baz@baz.baz PRIVMSG #ch_test0 :msg_test3 msg_test4
log 3 < [baz] msg_test3 msg_test4
insert servermsglogged : + MSG ::oof!~oof@oof.oof NOTICE #ch_test0 :msg_test5 msg_test6
-insert user-set-to 3: + USER_ID=3 USERNAME=~oof USERHOST :oof.oof
+insert user-set-to 1: + USER_ID=3 USERNAME=~oof USERHOST :oof.oof
log 3 < (oof) msg_test5 msg_test6
# check effect of server NOTICE to channel
# check part of user visible, and of user NOT visible in other channel
insert part-other : + NICK=baz USER_ID=2 REMAINING_IDS :[3], [4], [5], [me]
-insert part-other : + NICK=oof USER_ID=3 REMAINING_IDS :[4], [5], [me]
+# !!!!
+insert part-other :2 + NICK=oof USER_ID=3 REMAINING_IDS :[4], [5], [me]
+insert part-other 3: + NICK=oof USER_ID=3 REMAINING_IDS :[4], [5], [me]
log 1 $ users:3 cleared
# check other-user part with exit message
insert servermsglogged : + MSG ::zab!~zab@zab.zab PART #ch_test0 :goodbye
-insert user-set-to 3: + USER_ID=5 USERNAME=~zab USERHOST :zab.zab
-insert parts-core : + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=5 NICK=zab exitPREFIX=:§ exitMSG=goodbye USERIDS_CLEAR=set§to:§[4],§[me] § :
+insert user-set-to 1: + USER_ID=5 USERNAME=~zab USERHOST :zab.zab
+insert parts-core 1: + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=5 NICK=zab exitPREFIX=:§ exitMSG=goodbye USERIDS_CLEAR=set§to:§[4],§[me] § :
log 1 $ users:5 cleared
# check re-join of user kept visible in other channel
insert servermsglogged : + MSG ::baz!~baz@baz.baz QUIT :Client Quit
log 1 $ users:2:exit_msg set to: [QClient Quit]
log , $ baz!~baz@baz.baz quits: Client Quit
-insert quit : + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=2 NICK=baz REMAINING_IDS :[4], [6], [me]
+insert quit 1: + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=2 NICK=baz REMAINING_IDS :[4], [6], [me]
insert quit : + CHAN_WIN_ID=4 CHANNEL=#ch_test1 USER_ID=2 NICK=baz REMAINING_IDS :[me]
log 1 $ users:2 cleared
# check effects of own QUIT while present in one channel
-insert part-empty : + CHAN_WIN_ID=4 CHANNEL :#ch_test1
+insert part-0 : + CHANNEL :#ch_test1
+insert part-1 1: + CHAN_WIN_ID=4 USERIDS_CLEAR=cleared CHANNEL :#ch_test1
insert cmd-disconnect-0
-insert quit : + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=me NICK=foo foo@foo.foo=baz@baz.bar.foo REMAINING_IDS :[4], [6]
+insert quit 1: + CHAN_WIN_ID=3 CHANNEL=#ch_test0 USER_ID=me NICK=foo foo@foo.foo=baz@baz.bar.foo REMAINING_IDS :[4], [6]
insert cmd-disconnect-1 :-1
insert disconnect1 : + WIN_IDS :2,3,4
# test effect of PREFIX
insert join-channel-0 : +0 CHANNEL=#ch_test6 RESIDENT_NAMES :foo @bar +baz =quux
-insert user-set-to :3 +1 USER_ID=1 USERNICK :bar
-insert user-set-to :3 +1 USER_ID=2 USERNICK :baz
-insert user-set-to :3 +1 USER_ID=3 USERNICK :=quux
+insert user-set-to :1 +1 USER_ID=1 USERNICK :bar
+insert user-set-to :1 +1 USER_ID=2 USERNICK :baz
+insert user-set-to :1 +1 USER_ID=3 USERNICK :=quux
insert join-channel-1 : +0 CHANNEL=#ch_test6 RESIDENT_IDS :[1], [2], [3], [me]
log 7 $ residents: bar, baz, =quux, foo
insert un-default : +0 KEY=PREFIX VALUE :(vE)+=
insert join-channel-0 : +0 CHANNEL=#ch_test7 RESIDENT_NAMES :foo @bar +baz =quux
-insert user-set-to :3 +1 USER_ID=4 USERNICK :@bar
-insert user-set-to :3 +1 USER_ID=5 USERNICK :quux
+insert user-set-to :1 +1 USER_ID=4 USERNICK :@bar
+insert user-set-to :1 +1 USER_ID=5 USERNICK :quux
insert join-channel-1 : +0 CHANNEL=#ch_test7 RESIDENT_IDS :[2], [4], [5], [me]
log 8 $ residents: baz, @bar, quux, foo
× 001-setting-nick
insert servermsglogged : +0 MSG ::foo.bar.baz 001 foo :Welcome to the foo.bar.baz network
-insert user-set-to :3 +1 USER_ID=me USERNICK :foo
+insert user-set-to :1 +1 USER_ID=me USERNICK :foo
+++ /dev/null
-× caps-data-set
-log 1 $ caps:CAPNAME:data set to: []
-log 1 $ caps:CAPNAME:data set to: [CAPVAL]
× join-channel-0-1
insert servermsglogged : + MSG ::foo.bar.baz 353 foo = CHANNEL :RESIDENT_NAMES
-log 1 $ channels:CHANNEL:exits cleared
× join-channel-0
insert join-channel-0-0
insert ./lib/servermsglogged
× exit-channel
+log 1 $ channels:CHANNEL:exits cleared
log 1 $ channels:CHANNEL:exits:USER_ID set to: [exitTYPEexitMSG]
log 1 $ channels:CHANNEL:user_ids USERIDS_CLEAR
log CHAN_WIN_ID $ NICK!~NICK@NICK.NICK exitDESCexitPREFIXexitMSG
× parts-core
insert exit-channel : + exitTYPE=P exitDESC :parts
-× part
+× part-0
> /part
log 1 > PART :CHANNEL
insert servermsglogged : + MSG ::foo!~baz@baz.bar.foo PART :CHANNEL
+
+× part-1
insert parts-core : + exitPREFIX= exitMSG= USER_ID=me NICK=foo foo@foo.foo :baz@baz.bar.foo
log 1 $ channels:CHANNEL cleared
+× part
+insert part-0
+insert part-1
+
× quits
insert exit-channel : + exitTYPE=Q exitDESC=quits exitPREFIX=:§ exitMSG=Client§Quit § :
insert ./lib/cap-msg
-insert ./lib/caps-data-set
insert ./lib/user-set-to
× req-sasl
log 1 > CAP REQ :sasl
log 1 > CAP :LIST
insert cap-msg : +0 CAPMSG :foo REPLY :sasl
-insert user-set-to :3 + USER_ID=me USERNICK :foo
+insert user-set-to :1 + USER_ID=me USERNICK :foo
insert cap-msg : +0 CAPMSG :foo LIST :CAPLIST
× get-sasl-plain
insert cap-msg : + CAPMSG :* LS :sasl=PLAIN
-insert caps-data-set : + CAPNAME=sasl CAPVAL :PLAIN
+log 1 $ caps:sasl:data set to: [PLAIN]
insert req-sasl : + REPLY=ACK CAPLIST :sasl
log 1 $ caps:sasl:enabled set to: [True]
× user-set-to
-log 1 $ users:USER_ID:nick set to: [?]
-log 1 $ users:USER_ID:modes set to: []
log 1 $ users:USER_ID:nick set to: [USERNICK]
log 1 $ users:USER_ID:user set to: [USERNAME]
log 1 $ users:USER_ID:host set to: [USERHOST]
× usermode
insert servermsglogged : +0 MSG ::foo!~baz@baz.bar.foo MODE foo +ABC
-insert user-set-to 3: +1 USER_ID=me USERNAME=~baz USERHOST :baz.bar.foo
+insert user-set-to 1: +1 USER_ID=me USERNAME=~baz USERHOST :baz.bar.foo
log 1 $ users:me:modes set to: [ABC]
insert ./lib/attempting-to-connected
insert ./lib/cap-msg
-insert ./lib/caps-data-set
insert ./lib/cmd-disconnect
insert ./lib/cmd-nick
insert ./lib/conn
# for: join-channel-0, join-channel-1
insert ./lib/no-handler
insert ./lib/part
-# for: part, quit, quits
+# for: part-0, part-1, quit, quits
insert ./lib/pingpong
insert ./lib/privmsg
insert ./lib/req-sasl
log 1 $ caps:baz:data set to: []
log 1 $ caps:cap-notify:data set to: []
log 1 $ caps:foo:data set to: []
-insert caps-data-set : +1 CAPNAME=sasl CAPVAL :IGNORE
+log 1 $ caps:sasl:data set to: [IGNORE]
insert req-sasl : +0 foo=foo1 REPLY=ACK CAPLIST :cap-notify sasl
log 1 $ caps:cap-notify:enabled set to: [True]
log 1 $ caps:sasl:enabled set to: [True]
# join channel with other user
insert join-channel-0 : +0 CHANNEL=#test RESIDENT_NAMES :foo @baz
-insert user-set-to :3 +1 USER_ID=1 USERNICK :baz
+insert user-set-to :1 +1 USER_ID=1 USERNICK :baz
insert join-channel-1 : +0 CHANNEL=#test RESIDENT_IDS :[1], [me]
log 4 $ residents: baz, foo
# handle self-PART: clear channel, and its squatters
> /window 4
-insert part : +0 CHAN_WIN_ID=4 CHANNEL=#test USERIDS_CLEAR :set to: [1]
+insert part-0 : + CHANNEL :#test
+insert part-1 1: + CHAN_WIN_ID=4 CHANNEL=#test USERIDS_CLEAR :set to: [1]
log 1 $ users:1 cleared
# handle lack of implementation
# handle /disconnect, clear all
insert cmd-disconnect-0 :-1
log 3,6,7 $ foo!~baz@baz.bar.foo quits: Client Quit
-insert quits : + CHAN_WIN_ID=5 CHANNEL=#testtest USER_ID=me NICK=foo foo@foo.foo=baz@baz.bar.foo USERIDS_CLEAR :cleared
+insert quits 1: + CHAN_WIN_ID=5 CHANNEL=#testtest USER_ID=me NICK=foo foo@foo.foo=baz@baz.bar.foo USERIDS_CLEAR :cleared
insert cmd-disconnect-1 : +0
insert disconnect1 :-1 +1 WIN_IDS :2,3,4,5,6,7
log 1 $ motd cleared
insert cap-msg : +0 CAPMSG :* LS :
log 1 > CAP :LIST
insert cap-msg : +0 CAPMSG :foo LIST :
-insert user-set-to :3 + USER_ID=me USERNICK :foo
+insert user-set-to :1 + USER_ID=me USERNICK :foo
log 1 > CAP :END
#
insert cmd-disconnect-0 :-2 + ~baz@baz.bar.foo :~foo@foo.foo
-insert user-set-to 3: + USER_ID=me USERNAME=~foo USERHOST :foo.foo
+insert user-set-to 1: + USER_ID=me USERNAME=~foo USERHOST :foo.foo
insert cmd-disconnect-0 -2: + ~baz@baz.bar.foo :~foo@foo.foo
insert cmd-disconnect-1 :-1
insert disconnect1 1: + WIN_IDS :2
insert end-auth : + NUMERIC=904 SASL_STATE :failed
#
insert cmd-disconnect-0 :-2 + ~baz@baz.bar.foo :~foo@foo.foo
-insert user-set-to 3: + USER_ID=me USERNAME=~foo USERHOST :foo.foo
+insert user-set-to 1: + USER_ID=me USERNAME=~foo USERHOST :foo.foo
insert cmd-disconnect-0 -2: + ~baz@baz.bar.foo :~foo@foo.foo
insert cmd-disconnect-1
insert disconnect1 1:-1 + WIN_IDS :2
insert connecting-to-nick
insert cap-to-auth
insert servermsglogged : + MSG ::foo.bar.baz 900 foo foo!foo@foo.foo foo :You are now logged in as foo
-insert user-set-to 3: + USER_ID=me USERNAME=foo USERHOST :foo.foo
+insert user-set-to 1: + USER_ID=me USERNAME=foo USERHOST :foo.foo
log 1 $ sasl_account set to: [foo]
insert end-auth : + NUMERIC=903 SASL_STATE :successful