diff --git a/docs/source/autodoc/engineer.rst b/docs/source/autodoc/engineer.rst index 341479bc..f854005c 100644 --- a/docs/source/autodoc/engineer.rst +++ b/docs/source/autodoc/engineer.rst @@ -17,7 +17,7 @@ ``conversation`` ------------ +---------------- .. automodule:: royalnet.engineer.conversation @@ -32,6 +32,7 @@ ---------- .. automodule:: royalnet.engineer.sentry + :special-members: __or__ ``teleporter`` @@ -43,7 +44,7 @@ ``wrench`` ---------- -.. automodule:: royalnet.engineer.sentry +.. automodule:: royalnet.engineer.wrench ``discard`` diff --git a/royalnet/engineer/bullet.py b/royalnet/engineer/bullet.py index 46d623f1..00bde19f 100644 --- a/royalnet/engineer/bullet.py +++ b/royalnet/engineer/bullet.py @@ -6,9 +6,10 @@ They exclusively use coroutine functions to access data, as it may be required t it is available. **All** coroutine functions can have three different results: + - :exc:`.exc.BulletException` is raised, meaning that something went wrong during the data retrieval. - - :exc:`.exc.NotSupportedError` is raised, meaning that the frontend does not support the feature the requested data - is about (asking for :meth:`.Message.reply_to` in an IRC frontend, for example). + - :exc:`.exc.NotSupportedError` is raised, meaning that the frontend does not support the feature the requested data + is about (asking for :meth:`.Message.reply_to` in an IRC frontend, for example). - :data:`None` is returned, meaning that there is no data in that field (if a message is not a reply to anything, :meth:`Message.reply_to` will be :data:`None`. - The data is returned. @@ -31,10 +32,14 @@ if t.TYPE_CHECKING: class Bullet(metaclass=abc.ABCMeta): """ - The abstract base class for Bullet models. + The abstract base class for :mod:`~royalnet.engineer.bullet` models. """ def __init__(self, mag: "magazine.Magazine"): + """ + Instantiate a new :class:`.Bullet` . + """ + self.mag: "magazine.Magazine" = mag """ The :class:`.magazine.Magazine` to use when instantiating new :class:`.Bullet`\\ s. diff --git a/royalnet/engineer/command.py b/royalnet/engineer/command.py index 0e551717..1f843fba 100644 --- a/royalnet/engineer/command.py +++ b/royalnet/engineer/command.py @@ -24,11 +24,18 @@ log = logging.getLogger(__name__) # Code class Command(c.Conversation): """ - A Command is a :class:`~.c.Conversation` which is started by a :class:`~.b.Message` having a text matching - the :attr:`.pattern`; the named capture groups of the pattern are then passed as keyword arguments to :attr:`.f`. + A Command is a :class:`~.conversation.Conversation` which is started by a :class:`~.bullet.Message` having a text + matching the :attr:`.pattern`; the named capture groups of the pattern are then passed as keyword arguments to + :attr:`.f`. + + .. info:: Usually you don't directly instantiate commands, you define :class:`.PartialCommand`\\ s in packs which + are later completed by a runner. """ def __init__(self, f: c.ConversationProtocol, *, names: t.List[str] = None, pattern: re.Pattern): + """ + Create a new :class:`.Command` . + """ log.debug(f"Teleporting function: {f!r}") teleported = tp.Teleporter(f, validate_input=True, validate_output=False) @@ -95,7 +102,7 @@ class Command(c.Conversation): def help(self) -> t.Optional[str]: """ - Get help about this command. This defaults to returning the docstring of :field:`.f` . + Get help about this command. This defaults to returning the docstring of :attr:`.f` . :return: The help :class:`str` for this command, or :data:`None` if the command has no docstring. """ @@ -110,6 +117,12 @@ class PartialCommand: They can specified later using :meth:`.complete`. """ def __init__(self, f: c.ConversationProtocol, syntax: str): + """ + Create a new :class:`.PartialCommand` . + + .. seealso:: :meth:`.new` + """ + self.f: c.ConversationProtocol = f """ The function to pass to :attr:`.c.Conversation.f`. @@ -137,12 +150,12 @@ class PartialCommand: def complete(self, *, names: t.List[str] = None, pattern: str) -> Command: """ - Complete the PartialCommand with a pattern, creating a :class:`Command` object. + Complete the :class:`.PartialCommand` with names and a pattern, creating a :class:`Command` object. :param names: The names of the command. See :attr:`.Command.names` . - :param pattern: The pattern to add to the PartialCommand. It is first :meth:`str.format`\\ ted with the keyword - arguments ``name`` and ``syntax`` and later :func:`re.compile`\\ d with the - :const:`re.IGNORECASE` flag. + :param pattern: The pattern to add to the PartialCommand. It is first :meth:`~str.format`\\ ted with the keyword + arguments ``name`` and ``syntax`` and later :func:`~re.compile`\\ d with the + :data:`re.IGNORECASE` flag. :return: The complete :class:`Command`. """ if names is None: diff --git a/royalnet/engineer/conversation.py b/royalnet/engineer/conversation.py index 4a92e1be..b67b360f 100644 --- a/royalnet/engineer/conversation.py +++ b/royalnet/engineer/conversation.py @@ -63,9 +63,9 @@ class Conversation: async def run(self, *, _sentry: s.Sentry, **kwargs) -> t.Optional[ConversationProtocol]: """ - The coroutine function that generates the coroutines returned by :meth:`__call__` . + The coroutine function that generates the coroutines returned by :meth:`.__call__` . - It is a conversation itself. + It is a :class:`Conversation` itself. """ log.debug(f"Running: {self!r}") return await self.f(_sentry=_sentry, **kwargs) diff --git a/royalnet/engineer/discard.py b/royalnet/engineer/discard.py index 39daaff0..708ad184 100644 --- a/royalnet/engineer/discard.py +++ b/royalnet/engineer/discard.py @@ -1,13 +1,15 @@ class Discard(BaseException): """ - A special exception which should be raised by Metals if a certain object should be discarded from the queue. + A special exception which should be raised by :class:`~royalnet.engineer.wrench.Wrench`\\ es if a certain object + should be discarded from the queue. """ + def __init__(self, obj, message): self.obj = obj self.message = message def __repr__(self): - return f"" + return f"<{self.__class__.__qualname__}>" def __str__(self): return f"Discarded {self.obj}: {self.message}" diff --git a/royalnet/engineer/sentry.py b/royalnet/engineer/sentry.py index 22ddb973..561dba22 100644 --- a/royalnet/engineer/sentry.py +++ b/royalnet/engineer/sentry.py @@ -1,5 +1,5 @@ """ -Sentries are asyncronous receivers for events (usually :class:`bullet.Bullet`) incoming from Dispensers. +Sentries are asynchronous receivers for events (usually :class:`bullet.Bullet`) incoming from Dispensers. They support event filtering through Wrenches and coroutine functions. """ @@ -12,7 +12,6 @@ import logging import asyncio from . import discard -from . import bullet if t.TYPE_CHECKING: from .dispenser import Dispenser diff --git a/royalnet/engineer/teleporter.py b/royalnet/engineer/teleporter.py index 0f905bf2..f85f5b0e 100644 --- a/royalnet/engineer/teleporter.py +++ b/royalnet/engineer/teleporter.py @@ -21,8 +21,19 @@ class Teleporter: validate_input: bool = True, validate_output: bool = True): self.f: t.Callable = f + """ + The function which is having its parameters and return value validated. + """ + self.InputModel: t.Type[pydantic.BaseModel] = self._create_input_model() if validate_input else None + """ + The :mod:`pydantic` model used to validate input parameters. + """ + self.OutputModel: t.Type[pydantic.BaseModel] = self._create_output_model() if validate_output else None + """ + The :mod:`pydantic` model used to validate the return value. + """ def __repr__(self): if self.InputModel and self.OutputModel: