Exemple #1
0
 def __and__(self, other):
     """Parallel composition of runnable components returns new Branches."""
     if isinstance(other, Branches):
         return Branches(self, *other)
     elif isinstance(other, Runnable):
         return Branches(self, other)
     else:
         raise TypeError("only Runnables can be composed into Branches")
Exemple #2
0
 def test_look_and_feel(self):
     br = Runnable(), Runnable()
     pb = Branches(*br)
     self.assertEqual(pb.name, 'Branches')
     self.assertEqual(str(pb), '(Runnable) & (Runnable)')
     self.assertEqual(repr(pb), 'Branches(Runnable(), Runnable())')
     self.assertEqual(tuple(pb), br)
Exemple #3
0
    def test_continuity(self):
        class Fast(Runnable):
            def next(self, state):
                time.sleep(0.1)
                return state.updated(x=state.x + 1)

        class Slow(Runnable):
            def next(self, state):
                time.sleep(0.2)
                return state.updated(x=state.x + 2)

        bs = Branches(Slow(), Fast(), Slow())
        ss = States(*[State(x=0) for _ in range(3)])
        res = bs.run(ss).result()
        self.assertEqual([s.x for s in res], [2, 1, 2])
Exemple #4
0
    def test_parallel_independent_execution(self):
        class Component(Runnable):
            def __init__(self, runtime):
                super(Component, self).__init__()
                self.runtime = runtime

            def next(self, state):
                time.sleep(self.runtime)
                return state

        # make sure all branches really run in parallel
        n = 5
        bs = Branches(*[Component(1) for _ in range(n)])
        ss = States(*[State() for _ in range(n)])
        with tictoc() as tt:
            bs.run(ss).result()

        # total runtime has to be smaller that the sum of individual runtimes
        self.assertTrue(1 <= tt.dt <= 2)
Exemple #5
0
    def test_composition(self):
        class A(Runnable):
            def next(self, state):
                return state.updated(x=state.x + 1)

        class B(Runnable):
            def next(self, state):
                return state.updated(x=state.x * 7)

        a, b = A(), B()

        # single branch

        b1 = Branches(a)
        ss = States(State(x=1))
        res = b1.run(ss).result()

        self.assertEqual(b1.branches, (a, ))
        self.assertEqual(len(res), 1)
        self.assertEqual(res[0].x, ss[0].x + 1)

        # two branches, explicit and implicit construction

        for b2 in [Branches(a, b), a & b]:
            ss = States(State(x=1), State(x=1))
            res = b2.run(ss).result()

            self.assertEqual(b2.branches, (a, b))
            self.assertEqual(len(res), 2)
            self.assertEqual(res[0].x, ss[0].x + 1)
            self.assertEqual(res[1].x, ss[1].x * 7)

        # appending a branch to branches

        b3 = b2 & a
        ss = States(*[State(x=1) for _ in range(3)])
        res = b3.run(ss).result()

        self.assertEqual(b3.branches, (a, b, a))
        self.assertEqual(len(res), 3)
        self.assertEqual(res[0].x, ss[0].x + 1)
        self.assertEqual(res[1].x, ss[1].x * 7)
        self.assertEqual(res[2].x, ss[2].x + 1)

        # prepending a branch to branches
        b4 = b & b2
        ss = States(*[State(x=1) for _ in range(3)])
        res = b4.run(ss).result()

        self.assertEqual(b4.branches, (b, a, b))
        self.assertEqual(len(res), 3)
        self.assertEqual(res[0].x, ss[0].x * 7)
        self.assertEqual(res[1].x, ss[1].x + 1)
        self.assertEqual(res[2].x, ss[2].x * 7)

        # invalid type

        with self.assertRaises(TypeError):
            b & 1
        with self.assertRaises(TypeError):
            b1 & 1
Exemple #6
0
 def test_empty(self):
     with self.assertRaises(ValueError):
         Branches()