def bench_workgroup_empty(b): bg = context.background() def _(ctx): return for i in xrange(b.N): wg = sync.WorkGroup(bg) wg.go(_) wg.wait()
def bench_workgroup_raise(b): bg = context.background() def _(ctx): raise RuntimeError('aaa') for i in xrange(b.N): wg = sync.WorkGroup(bg) wg.go(_) try: wg.wait() except RuntimeError: pass else: # NOTE not using `with raises` since it affects benchmark timing assert False, "did not raise"
def test_workgroup(): ctx, cancel = context.with_cancel(context.background()) mu = sync.Mutex() # t1=ok, t2=ok wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): with mu: l[i] = i + 1 wg.go(_, i) wg.wait() assert l == [1, 2] # WorkGroup must catch/propagate all exception classes. # Python2 allows to raise old-style classes not derived from BaseException. # Python3 allows to raise only BaseException derivatives. if six.PY2: class MyError: def __init__(self, *args): self.args = args else: class MyError(BaseException): pass # t1=fail, t2=ok, does not look at ctx wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): Iam__ = 0 with mu: l[i] = i + 1 if i == 0: raise MyError('aaa') def f(ctx, i): Iam_f = 0 _(ctx, i) wg.go(f, i) with raises(MyError) as exc: wg.wait() assert exc.type is MyError assert exc.value.args == ('aaa', ) if PyErr_Restore_traceback_ok: assert 'Iam__' in exc.traceback[-1].locals assert 'Iam_f' in exc.traceback[-2].locals assert l == [1, 2] # t1=fail, t2=wait cancel, fail wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): Iam__ = 0 with mu: l[i] = i + 1 if i == 0: raise MyError('bbb') if i == 1: ctx.done().recv() raise ValueError('ccc') # != MyError def f(ctx, i): Iam_f = 0 _(ctx, i) wg.go(f, i) with raises(MyError) as exc: wg.wait() assert exc.type is MyError assert exc.value.args == ('bbb', ) if PyErr_Restore_traceback_ok: assert 'Iam__' in exc.traceback[-1].locals assert 'Iam_f' in exc.traceback[-2].locals assert l == [1, 2] # t1=ok,wait cancel t2=ok,wait cancel # cancel parent wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): with mu: l[i] = i + 1 ctx.done().recv() wg.go(_, i) cancel() # parent cancel - must be propagated into workgroup wg.wait() assert l == [1, 2]
assert isinstance(ctx, _context.PyContext) assert ctx.deadline() == deadline assert ctx.err() == err ctxdone = ctx.done() assert ready(ctxdone) == done tctxAssertChildren(ctx, children) for i in range(10): # repeated .done() returns the same pyobject assert ctx.done() is ctxdone Z = set() # empty set C = context.canceled D = context.deadlineExceeded Y = True bg = context.background() # keys for context values class Key: def __init__(self, key): self._key = key def __repr__(self): return "Key(%r)" % (self._key, ) # __hash__ and __eq__ so that Key(x) == Key(x) to verify that keys are # compared by identity, _not_ equality. def __hash__(self): return hash(self._key)
def test_workgroup_with(): # verify with support for sync.WorkGroup ctx, cancel = context.with_cancel(context.background()) defer(cancel) mu = sync.Mutex() # t1=ok, t2=ok l = [0, 0] with sync.WorkGroup(ctx) as wg: for i in range(2): def _(ctx, i): with mu: l[i] = i+1 wg.go(_, i) assert l == [1, 2] # t1=fail, t2=wait cancel, fail with raises(MyError) as exci: with sync.WorkGroup(ctx) as wg: def _(ctx): Iam_t1 = 0 raise MyError('hello (fail)') wg.go(_) def _(ctx): ctx.done().recv() raise MyError('world (after zzz)') wg.go(_) e = exci.value assert e.__class__ is MyError assert e.args == ('hello (fail)',) assert e.__cause__ is None assert e.__context__ is None assert e.__suppress_context__ == False if PyErr_Restore_traceback_ok: assert 'Iam_t1' in exci.traceback[-1].locals # t=ok, but code from under with raises l = [0] with raises(MyError) as exci: with sync.WorkGroup(ctx) as wg: def _(ctx): l[0] = 1 wg.go(_) def bad(): raise MyError('wow') bad() e = exci.value assert e.__class__ is MyError assert e.args == ('wow',) assert e.__cause__ is None assert e.__context__ is None assert e.__suppress_context__ == False assert exci.traceback[-1].name == 'bad' assert l[0] == 1 # t=fail, code from under with also raises with raises(MyError) as exci: with sync.WorkGroup(ctx) as wg: def f(ctx): raise MyError('fail from go') wg.go(f) def g(): raise MyError('just raise') g() e = exci.value assert e.__class__ is MyError assert e.args == ('fail from go',) assert e.__cause__ is None assert e.__context__ is not None assert e.__suppress_context__ == False assert exci.traceback[-1].name == 'f' e2 = e.__context__ assert e2.__class__ is MyError assert e2.args == ('just raise',) assert e2.__cause__ is None assert e2.__context__ is None assert e2.__suppress_context__ == False assert e2.__traceback__ is not None t2 = Traceback(e2.__traceback__) assert t2[-1].name == 'g'
def test_workgroup(): ctx, cancel = context.with_cancel(context.background()) mu = sync.Mutex() # t1=ok, t2=ok wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): with mu: l[i] = i+1 wg.go(_, i) wg.wait() assert l == [1, 2] # t1=fail, t2=ok, does not look at ctx wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): Iam__ = 0 with mu: l[i] = i+1 if i == 0: raise MyError('aaa') def f(ctx, i): Iam_f = 0 _(ctx, i) wg.go(f, i) with raises(MyError) as exc: wg.wait() assert exc.type is MyError assert exc.value.args == ('aaa',) if PyErr_Restore_traceback_ok: assert 'Iam__' in exc.traceback[-1].locals assert 'Iam_f' in exc.traceback[-2].locals assert l == [1, 2] # t1=fail, t2=wait cancel, fail wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): Iam__ = 0 with mu: l[i] = i+1 if i == 0: raise MyError('bbb') if i == 1: ctx.done().recv() raise ValueError('ccc') # != MyError def f(ctx, i): Iam_f = 0 _(ctx, i) wg.go(f, i) with raises(MyError) as exc: wg.wait() assert exc.type is MyError assert exc.value.args == ('bbb',) if PyErr_Restore_traceback_ok: assert 'Iam__' in exc.traceback[-1].locals assert 'Iam_f' in exc.traceback[-2].locals assert l == [1, 2] # t1=ok,wait cancel t2=ok,wait cancel # cancel parent wg = sync.WorkGroup(ctx) l = [0, 0] for i in range(2): def _(ctx, i): with mu: l[i] = i+1 ctx.done().recv() wg.go(_, i) cancel() # parent cancel - must be propagated into workgroup wg.wait() assert l == [1, 2]