You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CallbackRegistry should not silently drop duplicate callbacks #20210
This seems not so nice and a bit surprising (as in #15785 (comment)); we should deprecate that behavior and either
(preferred) just always perform the connection, even if duplicated; it's the user's job to keep track of duplicates if they want; or
(less preferred) add something like keep_duplicates={None,True,False} where None (default) raises an exception for duplicates, True keeps them, False drops them.
I agree that silently dropping the second connection request is bad style.
What I don't understand is your choice of preference (preferred/less preferred). I don't where it could be useful to have duplicated connects. OTOH I can imagine scenarios in which certain actions that connect an event can happen multiple times, but you don't want multiple registrations. So requireing the user to track duplicates seems like an unnecessary burden. I'd Intuitively go for keep_duplicates (naming t.b.d.). But I'm not the event expert and maybe I'm missing something here.
I guess defaulting to raising-on-duplicate is fine, but my point of view is that you shouldn't really rely on CallbackRegistry doing the dedupe for you anyways. For example, imagine (grossly simplified):
defhandler():
# do whateverfig.canvas.mpl_connect("foo_event", lambdaevent: handler()) # indirectly through other functionsfig.canvas.mpl_connect("foo_event", lambdaevent: handler()) # indirectly somewhere else
(Assume that for whatever reason you indeed wanted handler to be called twice.) Some time later, you realize that your handler needs to take event as argument, so you write
defhandler(event):
# do whateverfig.canvas.mpl_connect("foo_event", lambdaevent: handler(event))
fig.canvas.mpl_connect("foo_event", lambdaevent: handler(event))
and then you realize that you can rewrite this as
defhandler(event):
# do whateverfig.canvas.mpl_connect("foo_event", handler)
fig.canvas.mpl_connect("foo_event", handler)
All of a sudden, the last version has different semantics, which I think is a bit unexpected... (IOW, I think one should normally be able to replace func by lambda *args, **kwargs: func(*args, **kwargs) without changing the semantics of a program.)
OTOH I don't have a super strong opinion there either.
I can see why it would be useful to do this de-duplication ("please connect this function" "it already is! here is its cid") and as Elliott points out the GUI toolkits are split on this. On the other hand, I can see why "do exactly what I said" is nice.
I would not block a PR to start this deprecation cycle.
If we can’t guess what the desired behavior is, likely, there is no universal answer and making the behavior configurable is reasonable. Apart form the (limited) implementation effort, I don‘t see any downside with this.
Activity
timhoffm commentedon May 13, 2021
I agree that silently dropping the second connection request is bad style.
What I don't understand is your choice of preference (preferred/less preferred). I don't where it could be useful to have duplicated connects. OTOH I can imagine scenarios in which certain actions that connect an event can happen multiple times, but you don't want multiple registrations. So requireing the user to track duplicates seems like an unnecessary burden. I'd Intuitively go for
keep_duplicates(naming t.b.d.). But I'm not the event expert and maybe I'm missing something here.anntzer commentedon May 16, 2021
I guess defaulting to raising-on-duplicate is fine, but my point of view is that you shouldn't really rely on CallbackRegistry doing the dedupe for you anyways. For example, imagine (grossly simplified):
(Assume that for whatever reason you indeed wanted handler to be called twice.) Some time later, you realize that your handler needs to take event as argument, so you write
and then you realize that you can rewrite this as
All of a sudden, the last version has different semantics, which I think is a bit unexpected... (IOW, I think one should normally be able to replace
funcbylambda *args, **kwargs: func(*args, **kwargs)without changing the semantics of a program.)OTOH I don't have a super strong opinion there either.
QuLogic commentedon May 18, 2021
In GTK and Qt, connecting a second time to an event simply connects again. In Tk, you can only bind once, it seems like.
tacaswell commentedon Dec 20, 2023
I'm of two minds on this.
I can see why it would be useful to do this de-duplication ("please connect this function" "it already is! here is its cid") and as Elliott points out the GUI toolkits are split on this. On the other hand, I can see why "do exactly what I said" is nice.
I would not block a PR to start this deprecation cycle.
timhoffm commentedon Dec 21, 2023
If we can’t guess what the desired behavior is, likely, there is no universal answer and making the behavior configurable is reasonable. Apart form the (limited) implementation effort, I don‘t see any downside with this.