Exemple #1
0
    async def stream(self, animation_state):
        self.started = time.time()
        del self.ticker

        async def tick():
            async with self.ticker as ticks:
                async for result in ticks:
                    yield result

        def errors(e):
            if not isinstance(e, asyncio.CancelledError):
                log.error(hp.lc(error=e, error_type=type(e)))

        with hp.ChildOfFuture(
                self.final_future,
                name="Animation::streamer[stop_fut]") as stop_fut:
            async with hp.ResultStreamer(
                    stop_fut,
                    error_catcher=errors,
                    exceptions_only_to_error_catcher=True,
                    name=f"Animation({self.__class__.__name__})",
            ) as streamer:
                await streamer.add_generator(tick(),
                                             context=AnimationEvent.Types.TICK)
                await streamer.add_generator(
                    self.make_user_events(animation_state),
                    context=AnimationEvent.Types.USER_EVENT)
                streamer.no_more_work()

                async for result in streamer:
                    if result.value is hp.ResultStreamer.GeneratorComplete:
                        continue
                    yield result
Exemple #2
0
    def spawn(self, address, backoff=0.05, timeout=10):
        """Spawn a socket for this address"""

        if self.stop_fut.cancelled():
            raise PhotonsAppError("The target has been cancelled")

        # Don't care about port, only care about host
        if type(address) is tuple:
            address = address[0]

        if address in self.sockets:
            fut = self.sockets[address]
            if not fut.done():
                return fut

            if not fut.cancelled() and not fut.exception():
                transport = fut.result()
                if self.is_transport_active(transport):
                    return fut

            del self.sockets[address]

        # Initialize a spot for this address
        if address not in self.sockets:
            self.sockets[address] = hp.ChildOfFuture(self.stop_fut)

        # Ok, let's do this!
        self._spawn(address, self.sockets[address], backoff, timeout)

        # And return our future
        return self.sockets[address]
Exemple #3
0
    def __init__(
        self,
        sender,
        *,
        limit=30,
        finder=None,
        forget_after=30,
        final_future=None,
        search_interval=20,
        time_between_queries=None,
    ):
        self.sender = sender
        self.search_interval = search_interval
        self.time_between_queries = time_between_queries

        final_future = final_future or sender.stop_fut
        self.final_future = hp.ChildOfFuture(
            final_future, name="DeviceFinderDaemon::__init__[final_future]"
        )

        self.own_finder = not bool(finder)
        self.finder = finder or Finder(
            self.sender, self.final_future, forget_after=forget_after, limit=limit
        )

        self.ts = hp.TaskHolder(self.final_future, name="DeviceFinderDaemon::__init__[ts]")
        self.hp_tick = hp.tick
Exemple #4
0
    def __init__(self, target):
        self.transport_target = target

        self.found = Found()
        self.stop_fut = hp.ChildOfFuture(self.transport_target.final_future)
        self.receiver = Receiver()
        self.received_data_tasks = []

        self.make_plans = __import__(
            "photons_control.planner").planner.make_plans

        self.setup()
Exemple #5
0
 def __init__(self,
              stop_fut,
              transport_target,
              protocol_register,
              default_broadcast="255.255.255.255"):
     self.transport_target = transport_target
     self.found = {}
     self.stop_fut = hp.ChildOfFuture(stop_fut)
     self.device_source = self.generate_source()
     self.broadcast_source = self.generate_source()
     self.protocol_register = protocol_register
     self.default_broadcast = default_broadcast
Exemple #6
0
        def __init__(self, item, stop_fut, reference, sender, kwargs):
            self.item = item
            self.kwargs = kwargs
            self.reference = reference
            self.sender = sender

            self.stop_fut = hp.ChildOfFuture(
                stop_fut, name="FromGenerator>Runner::__init__[stop_fut]")

            self.streamer = hp.ResultStreamer(
                self.stop_fut,
                name="FromGenerator>Runner::__init__[streamer]",
                error_catcher=squash,
            )
Exemple #7
0
    def __init__(self, sender, final_future=None, *, forget_after=30, limit=30):
        self.sender = sender
        self.forget_after = forget_after

        self.limit = limit
        if isinstance(self.limit, int):
            self.limit = asyncio.Semaphore(self.limit)

        self.devices = {}
        self.last_seen = {}
        self.searched = hp.ResettableFuture(name="Finder::__init__[searched]")
        self.collections = Collections()
        self.final_future = hp.ChildOfFuture(
            final_future or self.sender.stop_fut, name="Finder::__init__[final_future]"
        )
Exemple #8
0
    def __init__(self, target):
        self.transport_target = target

        self.found = Found()
        self.stop_fut = hp.ChildOfFuture(
            self.transport_target.final_future,
            name=f"{type(self).__name__}.__init__|stop_fut|")
        self.receiver = Receiver()
        self.received_data_tasks = hp.TaskHolder(
            self.stop_fut,
            name=f"{type(self).__name__}.__init__|received_data_tasks|")

        self.make_plans = __import__(
            "photons_control.planner").planner.make_plans

        self.setup()
Exemple #9
0
    def __init__(self, stop_fut, writer, retry_options):
        self.writer = writer

        self.results = []
        self.retry_options = retry_options
        self.final_future = hp.ChildOfFuture(stop_fut)

        def ignore(f):
            # Make sure we don't leak tasks
            if hasattr(self, "_writings"):
                self._writings.cancel()
                del self._writings
                del self._writings_cb
            self.results = []

            # I don't care about the exception from final_future
            if not f.cancelled():
                f.exception()
        self.add_done_callback(ignore)
Exemple #10
0
    def __init__(self,
                 sender,
                 final_future=None,
                 *,
                 forget_after=30,
                 limit=30):
        self.sender = sender
        self.forget_after = forget_after

        self.limit = limit
        if isinstance(self.limit, int):
            self.limit = asyncio.Semaphore(self.limit)

        self.devices = {}
        self.last_seen = {}
        self.searcher = Searcher(sender)
        self.collections = Collections()
        self.final_future = hp.ChildOfFuture(final_future
                                             or self.sender.stop_fut)
Exemple #11
0
    async def start(
        self,
        identity,
        reference,
        *,
        run_options=sb.NotSpecified,
        animations=sb.NotSpecified,
    ):
        pauser = asyncio.Semaphore()
        final_future = hp.ChildOfFuture(
            self.final_future,
            name=f"Animations::start({identity})[final_future]")

        if run_options is sb.NotSpecified:
            run_options = {}

        if animations is not sb.NotSpecified:
            run_options = MergedOptions.using(run_options, {
                "animations": animations
            }).as_dict()

        runner = AnimationRunner(
            self.sender,
            reference,
            run_options,
            final_future=final_future,
            error_catcher=errors,
            animation_options=self.animation_options,
        )

        runner.run_options.pauser = pauser

        def remove(res):
            if identity in self.animations:
                del self.animations[identity]

        self.animations[identity] = Animation(final_future, identity, runner,
                                              pauser).start(
                                                  self.tasks, remove)

        return self.info(started=identity)
Exemple #12
0
    def __init__(self,
                 sender,
                 reference,
                 run_options,
                 *,
                 final_future,
                 animation_options=None,
                 **kwargs):
        self.sender = sender
        self.kwargs = kwargs
        self.reference = reference
        self.run_options = make_run_options(run_options, animation_options)
        self.final_future = hp.ChildOfFuture(
            final_future, name="AnimationRunner::__init__[final_future]")
        self.original_canvas = Canvas()

        self.started = None
        self.collected = {}
        self.animations_ran = 0
        self.current_animation = None

        self.seen_serials = set()
        self.used_serials = set()
Exemple #13
0
    def __init__(
        self,
        sender,
        *,
        limit=30,
        finder=None,
        forget_after=30,
        final_future=None,
        search_interval=20,
        time_between_queries=None,
    ):
        self.sender = sender
        self.search_interval = search_interval
        self.time_between_queries = time_between_queries

        final_future = final_future or sender.stop_fut
        self.final_future = hp.ChildOfFuture(final_future)

        self.own_finder = not bool(finder)
        self.finder = finder or Finder(self.sender,
                                       self.final_future,
                                       forget_after=forget_after,
                                       limit=limit)
Exemple #14
0
    async def animate(self, ts, cannon, state, animations):
        ans = iter(animations())
        animation = None

        while True:
            self.animations_ran += 1

            try:
                make_animation, background = ans.send(animation)
            except StopIteration:
                break

            with hp.ChildOfFuture(
                    self.final_future,
                    name="AnimationRunner::animate[animation_fut]"
            ) as animation_fut:
                animation = make_animation(animation_fut,
                                           self.run_options.pauser)
                self.current_animation = animation

                try:
                    await state.set_animation(animation, background)

                    async for messages in state.messages():
                        by_serial = defaultdict(list)
                        for msg in messages:
                            by_serial[msg.serial].append(msg)

                        for serial, msgs in by_serial.items():
                            ts.add(cannon.fire(ts, serial, msgs))
                except asyncio.CancelledError:
                    raise
                except Finish:
                    pass
                except Exception:
                    log.exception("Unexpected error running animation")
Exemple #15
0
    async def start_session(self, final_future, parent_ts):
        self.last_final_future = final_future
        self.parent_ts = parent_ts

        self.final_future = hp.ChildOfFuture(
            final_future,
            name=
            f"{self.__class__.__name__}({self.device.serial}::start_session[final_future]",
        )

        self.ts = hp.TaskHolder(
            self.final_future,
            name=
            f"{self.__class__.__name__}({self.device.serial}::start_session[ts]",
        )

        self.incoming = hp.Queue(
            self.final_future,
            name=
            f"{self.__class__.__name__}({self.device.serial}::start_session[incoming]",
        )

        await self.ts.start()
        self.ts.add(self.incoming_loop())
import asyncio
import pytest


@pytest.fixture()
def final_future():
    fut = hp.create_future(name="final")
    try:
        yield fut
    finally:
        fut.cancel()


describe "ChildOfFuture":
    async it "takes in an original future", final_future:
        with hp.ChildOfFuture(final_future) as fut:
            assert fut.original_fut is final_future
            assert fut.name is None
            assert isinstance(fut.fut, asyncio.Future)

            assert fut.fut.name == "ChildOfFuture(None)::__init__[fut]"
            assert repr(fut) == "<ChildOfFuture#None((pending))<Future#final(pending)>>"

        with hp.ChildOfFuture(final_future, name="FUTZ") as fut:
            assert fut.original_fut is final_future
            assert fut.name == "FUTZ"
            assert isinstance(fut.fut, asyncio.Future)

            assert fut.fut.name == "ChildOfFuture(FUTZ)::__init__[fut]"
            assert repr(fut) == "<ChildOfFuture#FUTZ((pending))<Future#final(pending)>>"
            task.cancel()

            with assertRaises(asyncio.CancelledError):
                await task

            finish.assert_called_once_with(asyncio.CancelledError, mock.ANY, mock.ANY)

    describe "finishing by final_future":

        async it "stops retrieving if there is results left to yield":
            called = []

            gen_fut = hp.create_future()
            func_fut = hp.create_future()
            func3_fut = hp.create_future()
            final_future = hp.ChildOfFuture(hp.create_future())

            async def gen():
                called.append(("started", "gen"))
                try:
                    yield 1
                    yield 2
                    await gen_fut
                    yield 3
                except asyncio.CancelledError:
                    called.append(("cancelled", "gen"))
                    raise

            async def func():
                called.append(("started", "func"))
                await func_fut
    def start(self,
              animation,
              target,
              serials,
              reference,
              afr,
              options,
              stop_conflicting=False):
        repeat = False
        shuffle = False

        if animation in self.presets:
            animations = list(self.presets[animation])
            repeat = options.get("repeat", True)
            shuffle = options.get("shuffle", True)
        elif animation in self.animators:
            animations = [
                PresetAnimation(animation=animation, options=options)
            ]
        else:
            raise NoSuchAnimation(wanted=animation,
                                  available=list(self.animators))

        conflicting = set()
        for aid, info in self.animations.items():
            if not info["task_future"].done():
                for s in info["serials"]:
                    if s in serials:
                        if stop_conflicting:
                            self.stop(aid)
                        else:
                            conflicting.add(s)

        remaining = set(serials) - conflicting
        if not remaining:
            raise AllSerialsAlreadyAnimating(want=serials,
                                             conflicting=list(conflicting))
        serials = list(remaining)

        animation_id = str(uuid.uuid4())

        pauser = asyncio.Condition()
        final_future = hp.ChildOfFuture(afr.stop_fut)
        info = {
            "pauser": pauser,
            "paused": False,
            "final_future": final_future,
            "started": time.time(),
            "serials": serials,
            "name": animations[0].animation,
        }

        async def coro():
            while True:
                if shuffle:
                    random.shuffle(animations)

                for i, a in enumerate(animations):
                    if final_future.done():
                        return

                    if info["name"] != a.animation:
                        info["name"] = a.animation
                        self.activate_listeners()

                    opts = dict(a.options)
                    if "combine_tiles" not in a.options and options.get(
                            "combine_tiles"):
                        opts["combine_tiles"] = True

                    try:
                        await self.animators[a.animation].animate(
                            target,
                            afr,
                            final_future,
                            reference,
                            opts,
                            pauser=info["pauser"],
                            global_options=self.global_options,
                        )
                    except Finish:
                        pass
                    except asyncio.CancelledError:
                        raise
                    except Exception as error:
                        log.exception(error)
                        await asyncio.sleep(1)

                    if final_future.done():
                        return

                    if len(animations) > 1 and (i < (len(animations) - 1)
                                                or repeat):
                        info["name"] = "transition"
                        self.activate_listeners()
                        try:
                            await transition_animation.animate(
                                target, afr, final_future, reference, options,
                                self.global_options)
                        except Finish:
                            pass
                        except asyncio.CancelledError:
                            raise
                        except Exception as error:
                            log.exception(error)
                            await asyncio.sleep(1)

                if not repeat:
                    return

        task_future = asyncio.ensure_future(hp.async_as_background(coro()))

        info["task_future"] = task_future

        async def remove_after_a_minute():
            await asyncio.sleep(60)
            self.remove(animation_id)

        def activate(*args):
            self.activate_listeners()
            if "stopped" not in info:
                info["stopped"] = time.time()
            self.removers.append(
                hp.async_as_background(remove_after_a_minute()))
            self.removers = [t for t in self.removers if not t.done()]

        info["task_future"].add_done_callback(activate)

        self.animations[animation_id] = info
        self.activate_listeners()
        return animation_id
Exemple #19
0
 def cof(s):
     return hp.ChildOfFuture(s.orig_fut)
            V.received(
                LightMessages.GetColor(),
                LightMessages.GetColor(),
                LightMessages.GetColor(),
                DeviceMessages.GetHostFirmware(),
                keep_duplicates=True,
            )

            ff.cancel()

        checker_task = None
        time_between_queries = {"FIRMWARE": 100}

        await FoundSerials().find(V.sender, timeout=1)

        with hp.ChildOfFuture(V.final_future) as ff:
            async with hp.TaskHolder(ff, name="TEST") as ts:
                checker_task = ts.add(checker(ff))
                ts.add(
                    V.device.refresh_information_loop(
                        V.sender, time_between_queries, V.finder.collections
                    )
                )

        await checker_task

    async it "can start an information loop for a switch", fake_time, sender, finder, final_future:
        V = VBase(fake_time, sender, finder, final_future)
        await V.choose_device("switch")
        fake_time.set(1)
Exemple #21
0
    def __init__(self, stop_fut, data_receiver):
        self.stop_fut = hp.ChildOfFuture(stop_fut)
        self.data_receiver = data_receiver

        self.sockets = {}
Exemple #22
0
    async def send_single(self,
                          original,
                          packet,
                          *,
                          timeout,
                          no_retry=False,
                          broadcast=False,
                          connect_timeout=10):

        transport, is_broadcast = await self._transport_for_send(
            None, packet, original, broadcast, connect_timeout)

        retry_gaps = self.retry_gaps(original, transport)

        writer = Writer(
            self,
            transport,
            self.receiver,
            original,
            packet,
            retry_gaps,
            did_broadcast=is_broadcast,
            connect_timeout=connect_timeout,
        )

        results = []

        unlimited = False
        if hasattr(original, "Meta"):
            unlimited = original.Meta.multi == -1

        async def wait_for_remainders(tick_fut, streamer_fut):
            try:
                await hp.wait_for_all_futures(tick_fut)
            finally:
                if unlimited and any(result.wait_for_result()
                                     for result in results):
                    await hp.wait_for_first_future(*results)
                streamer_fut.cancel()

        tick_fut = hp.ChildOfFuture(
            self.stop_fut,
            name=
            f"SendPacket({original.pkt_type, packet.serial})::send_single[tick_fut]",
        )
        streamer_fut = hp.ChildOfFuture(
            self.stop_fut,
            name=
            f"SendPacket({original.pkt_type, packet.serial})::send_single[streamer_fut]",
        )

        retry_ticker = retry_gaps.retry_ticker(
            name=
            f"{type(self).__name__}({type(transport).__name__})::retry_ticker")

        with tick_fut, streamer_fut:
            async with hp.ResultStreamer(
                    streamer_fut,
                    name=
                    f"SendPacket({original.pkt_type, packet.serial}).send_single"
            ) as streamer:
                await streamer.add_generator(
                    retry_ticker.tick(tick_fut, timeout),
                    context="tick",
                    on_done=lambda res: tick_fut.cancel(),
                )
                await streamer.add_coroutine(
                    wait_for_remainders(tick_fut, streamer_fut))
                streamer.no_more_work()

                async for result in streamer:
                    if not result.successful:
                        try:
                            raise result.value
                        finally:
                            del result

                    if result.context == "tick":
                        if not no_retry or not results:
                            result = await writer()
                            results.append(result)
                            await streamer.add_task(result, context="write")
                    elif result.context == "write":
                        return result.value

        raise TimedOut(
            "Waiting for reply to a packet",
            serial=packet.serial,
            sent_pkt_type=packet.pkt_type,
            source=packet.source,
            sequence=packet.sequence,
        )
Exemple #23
0
describe "ChildOfFuture":

    @pytest.fixture()
    def V(self):
        class V:
            orig_fut = asyncio.Future()

            @hp.memoized_property
            def cof(s):
                return hp.ChildOfFuture(s.orig_fut)

        return V()

    async it "ensure_future returns the ChildOfFuture as is":
        fut = asyncio.Future()
        fut = hp.ChildOfFuture(fut)
        assert asyncio.ensure_future(fut) is fut

    describe "set_result":
        async it "complains if the original fut is already cancelled", V:
            V.orig_fut.cancel()
            with assertRaises(hp.InvalidStateError, "CANCELLED: .+"):
                V.cof.set_result(True)

        async it "Otherwise sets a result on the fut", V:
            assert not V.cof.done()
            V.cof.set_result(True)
            assert V.cof.done()
            assert not V.orig_fut.done()
            assert await V.cof is True