Skip to content

Commit

Permalink
Backends now reraise deadlocks as the appropriate exception.
Browse files Browse the repository at this point in the history
  • Loading branch information
rgalanakis committed Jul 11, 2014
1 parent 0f4db79 commit 93bcc02
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
33 changes: 30 additions & 3 deletions goless/backends.py
@@ -1,8 +1,22 @@
import contextlib
import os
import platform
import sys


class Deadlock(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)


@contextlib.contextmanager
def _as_deadlock(*errtypes):
try:
yield
except errtypes as e:
raise Deadlock(repr(e))


class Backend(object):

def shortname(self):
Expand Down Expand Up @@ -39,6 +53,15 @@ def propagate_exc(self, errtype, *args):
def _make_stackless(): # pragma: no cover
import stackless

class StacklessChannel(stackless.channel):
def send(self, value):
with _as_deadlock(RuntimeError):
return stackless.channel.send(self, value)

def receive(self):
with _as_deadlock(RuntimeError):
return stackless.channel.receive(self)

class StacklessBackend(Backend):
def shortname(self):
return 'stackless'
Expand All @@ -52,7 +75,7 @@ def run(self, func, *args, **kwargs):
return t

def channel(self):
return stackless.channel()
return StacklessChannel()

def yield_(self):
return stackless.schedule()
Expand All @@ -68,14 +91,18 @@ def propagate_exc(self, errtype, *args):

def _make_gevent():
import gevent
import gevent.hub
import gevent.queue
deadlock_errtype = SystemError if os.name == 'nt' else gevent.hub.LoopExit

class Channel(gevent.queue.Channel):
def send(self, value):
self.put(value)
with _as_deadlock(deadlock_errtype):
self.put(value)

def receive(self):
return self.get()
with _as_deadlock(deadlock_errtype):
return self.get()

class GeventBackend(Backend):
def shortname(self):
Expand Down
15 changes: 15 additions & 0 deletions tests/test_backends.py
Expand Up @@ -69,3 +69,18 @@ def test_novalidbackend_msg(self):
self.fail('Should have raised!')
except backends.NoValidBackend as ex:
self.assertEqual(ex.args, (backends.NO_VALID_BACKEND_MSG,))


class CurrentBackendTests(BaseTests):
"""
Tests that ensure the active backend adheres to its contract.
Would need to be run for every backend for full coverage.
"""

def testRecvWithNoWaitersRaisesDeadlock(self):
with self.assertRaises(backends.Deadlock):
backends.current.channel().receive()

def testSendWithNoWaitersRaisesDeadlock(self):
with self.assertRaises(backends.Deadlock):
backends.current.channel().send(1)

0 comments on commit 93bcc02

Please sign in to comment.