Numergy / signalslot

Simple signal slot implementation in Python
http://signalslot.rtfd.org
MIT License
47 stars 14 forks source link

supporting callables? #7

Open TTimo opened 9 years ago

TTimo commented 9 years ago

nifty little module!

Would it be possible to support callables instead of just functions - I ran into this use case:

class FuncToolsTest( unittest.TestCase ):
    def test( self ):
        def f( a, b ):
            logging.info( 'a: %s b: %s' % ( repr( a ), repr( b ) ) )

        g = functools.partial( f, 'a' )
        g('b')

        def fp( a, **kwargs ):
            logging.info( 'a: %s kwargs: %s' % ( repr( a ), repr( kwargs ) ) )
        gp = functools.partial( fp, 'a' )
        gp( b = 'b', c = 'c' )

        s = signalslot.Signal()
        s.connect( gp )
        s.emit()

Basically I wanted to specialize a signal handler from a generic function with a partial application in between. Error is:

INFO:root:a: 'a' b: 'b'
INFO:root:a: 'a' kwargs: {'c': 'c', 'b': 'b'}
E..
======================================================================
ERROR: test (main.FuncToolsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "main.py", line 1410, in test
    s.connect( gp )
  File "lib/signalslot/signal.py", line 57, in connect
    if inspect.getargspec(slot).keywords is None:
  File "/usr/lib/python2.7/inspect.py", line 816, in getargspec
    raise TypeError('{!r} is not a Python function'.format(func))
TypeError: <functools.partial object at 0x7fe65f4889f0> is not a Python function
sjlongland commented 9 years ago

I suspect the problem is knowing whether a callable supports keyword arguments. The inspect library doesn't seem to know how to check this.

One possibility is to take the Erlang approach and just "let it crash" if it turns out a callable doesn't support keywords. Trouble is the signal in question might be a very rare one and it'll only be some time later that you find there's a problem.

I made a fork of signalslot that accepts a Slot object which doesn't actually bother to check whether the thing it is passed takes keywords, then I found I had to add a special case to handle this very problem in the Signal class.

jpic commented 9 years ago

Could you curry your callable maybe ?​

sjlongland commented 9 years ago

Okay, I'm a little lost, what is meant by "curry your callable"?

jpic commented 9 years ago

I was thinking of this curry command https://github.com/django/django/blob/master/django/utils/functional.py#L10

Just suggesting as a temporary workaround.