Skip to content

Add support for optional channels in Select #12

@leandro-lucarella-frequenz

Description

What's needed?

There might be cases when one wants to do a Select loop with some channels that are optional and if they are not present the handling of those channels will just not be used. Right now there is no trivial way to do this.

Proposed solution

Create a Select.with_optional() method like (maybe incomplete and untested):

   def with_optional(self, **optional_receivers: Optional[AsyncIterator[Any]]) -> Select:
       # TODO: check name clashing with self._receivers
       for name, recv in optional_receivers.items():
           self._result[name] = None
           if recv is None:
               continue
           self._receivers[name] = recv
           # can replace __anext__() to anext() (Only Python 3.10>=)
           msg = recv.__anext__()  # pylint: disable=unnecessary-dunder-call
           self._pending.add(asyncio.create_task(msg, name=name))  # type: ignore

       return self

With the intended use:

# chan1 can't be None, chan_none can
select = Select(chan1=chan1).with_optional(chan_none=None)
while await select.ready():
    if select.chan1:
        pass
    elif select.chan_none:  # will always be None if chan_none is None
        pass

Use cases

Yet to be seen

Alternatives and workarounds

  1. Handle the optional channel explicitly:
chan_none = None
optional_channels = {}
if chan_none is not None:
    optional_channels["chan_none"] = chan_none
select = Select(chan1=chan1, **optional_channels)
while await select.ready():
    if select.chan1:  # OK
        pass
    elif chan_none and select.chan_none:  # OK too
        pass
  1. Create a dummy channel, use the receiver in the Select and never call send to the sender of the channel.
chan_none = Broadcast[int]("chan_none").get_receiver()
select = Select(chan1=chan1, chan_none=chan_none)
while await select.ready():
    if select.chan1:  # OK
        pass
    elif select.chan_none:  # OK too, will never be True
        pass

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    part:synchronizationAffects the synchronization of multiple sources (`select`, `merge`)type:enhancementNew feature or enhancement visitble to users

    Type

    No type

    Projects

    Status

    Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions