diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index 71262c6..188a151 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -1526,6 +1526,17 @@ cdef class _VoidPromise: if self.is_consumed: raise RuntimeError('Promise was already used in a consuming operation. You can no longer use this Promise object') + argspec = None + try: + argspec = _inspect.getargspec(func) + except: + pass + if argspec: + args_length = len(argspec.args) if argspec.args else 0 + defaults_length = len(argspec.defaults) if argspec.defaults else 0 + if args_length - defaults_length != 0: + raise ValueError('Function passed to `then` call must take no arguments') + return Promise()._init(helpers.then(deref(self.thisptr), func, error_func).attach(capnp.makePyRefCounter(func), capnp.makePyRefCounter(error_func)), self) cpdef as_pypromise(self) except +reraise_kj_exception: @@ -1587,6 +1598,17 @@ cdef class _RemotePromise: if self.is_consumed: raise RuntimeError('Promise was already used in a consuming operation. You can no longer use this Promise object') + argspec = None + try: + argspec = _inspect.getargspec(func) + except: + pass + if argspec: + args_length = len(argspec.args) if argspec.args else 0 + defaults_length = len(argspec.defaults) if argspec.defaults else 0 + if args_length - defaults_length != 1: + raise ValueError('Function passed to `then` call must take exactly one argument') + Py_INCREF(func) Py_INCREF(error_func) @@ -1656,16 +1678,21 @@ cpdef join_promises(promises) except +reraise_kj_exception: cdef class _Request(_DynamicStructBuilder): cdef Request * thisptr_child + cdef public bint is_consumed cdef _init_child(self, Request other, parent): self.thisptr_child = new Request(moveRequest(other)) self._init(deref(self.thisptr_child), parent) + self.is_consumed = False return self def __dealloc__(self): del self.thisptr_child cpdef send(self): + if self.is_consumed: + raise ValueError('Request has already been sent. You can only send a request once.') + self.is_consumed = True return _RemotePromise()._init(self.thisptr_child.send(), self._parent) cdef class _Response(_DynamicStructReader): diff --git a/test/test_capability.py b/test/test_capability.py index 7278f8d..5cd09a2 100644 --- a/test/test_capability.py +++ b/test/test_capability.py @@ -291,6 +291,17 @@ def test_timer(): joined.wait() +def test_double_send(): + client = capability.TestInterface._new_client(Server()) + + req = client._request('foo') + req.i = 5 + + req.send() + with pytest.raises(ValueError): + req.send() + + def test_then_args(): capnp.Promise(0).then(lambda x: 1) @@ -299,3 +310,18 @@ def test_then_args(): with pytest.raises(ValueError): capnp.Promise(0).then(lambda x, y: 1) + + capnp.getTimer().after_delay(1).then(lambda: 1) # after_delay is a VoidPromise + + with pytest.raises(ValueError): + capnp.getTimer().after_delay(1).then(lambda x: 1) + + client = capability.TestInterface._new_client(Server()) + + client.foo(i=5).then(lambda x: 1) + + with pytest.raises(ValueError): + client.foo(i=5).then(lambda: 1) + + with pytest.raises(ValueError): + client.foo(i=5).then(lambda x, y: 1)