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
If you don't write the my_signal.send() call as blinker expects, you get a silent failure.
In my_signal.send(sender=MyObject()) means that sender is None. I'm on Python3, but I've rigged a simple example to show what is happening. The cases where you don't pass in a named arg it works, but otherwise sender sticks around in kwargs).
I'm not sure of a good solution but the way it works definitely caught me off guard.
In [2]: def foo(*sender, **kwargs):
...: print(f"len: {len(sender)} and sender is: {sender}")
...: print(f"kwargs is {kwargs}")
...:
In [3]: foo(123)
len: 1 and sender is: (123,)
kwargs is {}
In [4]: foo(sender=123)
len: 0 and sender is: ()
kwargs is {'sender': 123}
In [5]: foo([123, 'abc'])
len: 1 and sender is: ([123, 'abc'],)
kwargs is {}
Now, if you swap *sender, to sender=None, sender is always defined, even if the len() fails on an int.
In [6]: def bar(sender=None, **kwargs):
...: print(f"len: {len(sender)} and sender is: {sender}")
...: print(f"kwargs is {kwargs}")
...:
In [7]: bar(123)
TypeError Traceback (most recent call last)
<ipython> in <module>()
----> 1 bar(123)
<ipython> in bar(sender, **kwargs)
1 def bar(sender=None, **kwargs):
----> 2 print(f"len: {len(sender)} and sender is: {sender}")
3 print(f"kwargs is {kwargs}")
4
TypeError: object of type 'int' has no len()
In [8]: bar(sender=123)
TypeError Traceback (most recent call last)
<ipython> in <module>()
----> 1 bar(sender=123)
<ipython> in bar(sender, **kwargs)
1 def bar(sender=None, **kwargs):
----> 2 print(f"len: {len(sender)} and sender is: {sender}")
3 print(f"kwargs is {kwargs}")
4
TypeError: object of type 'int' has no len()
In [9]: bar([123, 'abc'])
len: 2 and sender is: [123, 'abc']
kwargs is {}
I'm not sure if there's a way to reconcile the two approaches, but I figure I might as well write it down.
The text was updated successfully, but these errors were encountered:
Python 3.8 positional-only parameters finally bring a portable way of fixing the (*args, **kwargs) hack on the send() method. If I were still actively working in Python (sadly I am not), I would look at making 3.8 the preferred native source version for Blinker and move all prior versions (2.7 and <3.8) to compatibility fallbacks.
my_signal.send(sender=MyObject()) means that sender is None
That's the intended behavior, to allow a keyword argument sender passed on to the receiver, separately from a single positional argument specifying the Blinker sender.
The implementation for this can be improved with Python 3.8 positional-only arguments, but it won't change the fact that you are not intended to pass the Blinker sender as a keyword argument.
https://github.com/jek/blinker/blob/42aad6110a02a86a9a51a77c75c2d638a50656b7/blinker/base.py#L261
If you don't write the
my_signal.send()
call as blinker expects, you get a silent failure.In
my_signal.send(sender=MyObject())
means thatsender
is None. I'm on Python3, but I've rigged a simple example to show what is happening. The cases where you don't pass in a named arg it works, but otherwisesender
sticks around inkwargs
).I'm not sure of a good solution but the way it works definitely caught me off guard.
Now, if you swap
*sender
, tosender=None
,sender
is always defined, even if thelen()
fails on an int.I'm not sure if there's a way to reconcile the two approaches, but I figure I might as well write it down.
The text was updated successfully, but these errors were encountered: