Source code for upsies.uis.prompts

"""
Generic user dialogs

Prompts take arbitrary keyword arguments that are used by the user interface
to create the dialog.

When the user makes a choice, the user interface must pass it on to the prompt
object via :meth:`~.Prompt.set_result`. The prompt object then takes care of
passing the result to any callbacks.
"""

import asyncio

import logging  # isort:skip
_log = logging.getLogger(__name__)


[docs] class Prompt: """ Base class of all prompts Every prompt takes a sequence of callbacks. Any other keyword arguments are specified by the subclass. The user interface can access them as :attr:`parameters` to create UI widgets. Prompt instances are awaitable. The `await` will return when the user provided input. The return value of the `await` call is the same as the :attr:`result` property. Prompts can be awaited multiple times at any time. """ def __init__(self, *, callbacks=(), **parameters): self._callbacks = list(callbacks) self._parameters = parameters self._result_arrived = asyncio.Event() self._result = None @property def parameters(self): """Keyword arguments from instantiation (except for `callbacks`)""" return self._parameters
[docs] async def wait(self): """Block until :meth:`set_result` is called""" await self._result_arrived.wait()
def __await__(self): async def get_result(): await self.wait() return self.result return get_result().__await__()
[docs] def on_result(self, callback): """Schedule `callback` to be called when :meth:`set_result` is called""" self._callbacks.append(callback)
[docs] def set_result(self, result): """ Take the result from the user dialog and make it available to callbacks and via the :attr:`result` property """ _log.debug('Setting result: %r', result) self._result = result # Call callbacks for callback in self._callbacks: _log.debug('Reporting result to %r: %r', callback, result) callback(result) # Unblock any wait() calls self._result_arrived.set()
@property def result(self): """Input from the user""" return self._result def __eq__(self, other): if isinstance(other, type(self)): return self._parameters == other._parameters else: return NotImplemented def __repr__(self): arguments = [] if self._parameters: arguments.append(', '.join(( f'{k}={v!r}' for k, v in self._parameters.items() ))) arguments.append(f'callbacks={self._callbacks}') arguments_string = ', '.join(arguments) return f'{type(self).__name__}({arguments_string})'
[docs] class RadioListPrompt(Prompt): """ Pick one of two or more options :param options: Sequence of choices :param question: Question to show alongside the options or `None` :param focused: One of the `options` to focus initially or `None` to focus the first option """ def __init__(self, *, callbacks=(), options, question=None, focused=None): super().__init__( callbacks=callbacks, options=options, question=question, focused=focused, )
[docs] class CheckListPrompt(Prompt): """ Pick multiple of two or more options :param options: Sequence of choices :param question: Question to show alongside the options or `None` :param focused: One of the `options` to focus initially or `None` to focus the first option """ def __init__(self, *, callbacks=(), options, question=None, focused=None): super().__init__( callbacks=callbacks, options=options, question=question, focused=focused, )
[docs] class TextPrompt(Prompt): """ Input of arbitrary text :param question: Question to show alongside the options or `None` :param text: Prefilled text the user can delete or edit """ def __init__(self, *, callbacks=(), question=None, text=''): super().__init__(callbacks=callbacks, question=question, text=text)