1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-26 13:04:20 +00:00

Document and improve some parts of Royalnet code

This commit is contained in:
Steffo 2022-02-27 00:42:47 +01:00
parent 81c8fb6fa7
commit bb1f7b0795
11 changed files with 99 additions and 33 deletions

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "royalnet"
version = "6.5.6"
version = "6.6.0"
description = "A multipurpose bot framework"
authors = ["Stefano Pigozzi <me@steffo.eu>"]
license = "AGPL-3.0-or-later"

15
royalnet/__init__.py Normal file
View file

@ -0,0 +1,15 @@
"""
Royalnet is a collection of many Python modules useful to build chat-like applications.
The modules currently are:
- :mod:`.alchemist`, containing utility extensions to :mod:`sqlalchemy`;
- :mod:`.engineer`, containing a framework for building chat bots;
- :mod:`.lazy`, containing utilities to delay the evaluation of values until they are actually used;
- :mod:`.scrolls`, containing configuration utilities;
- :mod:`.sculptor`, containing common :mod:`pydantic` models for serialization and deserialization of data structures;
To prevent the library from breaking if optional dependencies are not installed, this module does not export any object; submodules should be directly imported instead.
All modules use exceptions based on :exc:`.exc.RoyalnetException`, and may subclass it to provide more detail on the errors.
"""

View file

@ -1,3 +1,7 @@
"""
This submodule implements quick alias for some common SQL filtering functions.
"""
import sqlalchemy

View file

@ -1,3 +1,7 @@
"""
This submodule implements the :class:`.Makeable` mixin.
"""
from royalnet.royaltyping import *
import sqlalchemy.orm as o

View file

@ -1,3 +1,8 @@
"""
This submodule implements :func:`repr`\\ esentation mixins.
"""
class ColRepr:
"""
A mixin that can be added to a declared class to display all columns of the table with their values in the

View file

@ -1,3 +1,7 @@
"""
This module implements the :class:`.Updatable` mixin, along with the special class :class:`.DoNotUpdateType` and the singleton :data:`.DoNotUpdate`.
"""
class Updatable:
"""
A mixin that can be added to a declared class to add update methods, allowing attributes to be set from

View file

@ -4,6 +4,7 @@ This module contains the base :class:`.PDAImplementation` and its basic implemen
"""
import royalnet.royaltyping as t
import royalnet.exc as exc
import abc
import sys
import asyncio
@ -21,28 +22,28 @@ DispenserKey = t.Hashable
class PDAImplementation(metaclass=abc.ABCMeta):
"""
.. todo:: Document this.
An abstract class describing the interface of a PDA implementation.
"""
def __init__(self, name: str):
self.name: str = f"{self.namespace}.{name}"
"""
.. todo:: Document this.
The namespaced name of the PDA implementation.
"""
self.bound_to: t.Optional["PDA"] = None
"""
.. todo:: Document this.
The PDA this implementation is bound to.
"""
self.logger_name: str = f"{__name__}.PDAImplementation.{self.namespace}.{name}"
"""
.. todo:: Document this.
The namespaced name of the :class:`logging.Logger` that is being used by this PDA implementation.
"""
self.log: logging.Logger = logging.getLogger(self.logger_name)
"""
.. todo:: Document this.
The :class:`logging.Logger` that is being used by this PDA implementation.
"""
def __repr__(self):
@ -53,7 +54,11 @@ class PDAImplementation(metaclass=abc.ABCMeta):
def bind(self, pda: "PDA") -> None:
"""
.. todo:: Document this.
Bind this PDA implementation to a specific PDA.
Required for objects of this class to function.
:raises .ImplemetationAlreadyBoundError: if the PDA implementation is already bound to a PDA.
"""
self.log.debug(f"Trying to bind to {pda!r}...")
@ -66,9 +71,9 @@ class PDAImplementation(metaclass=abc.ABCMeta):
@property
@abc.abstractmethod
def namespace(self):
def namespace(self) -> str:
"""
.. todo:: Document this.
The namespace of this PDA implementation.
"""
raise NotImplementedError()
@ -82,15 +87,15 @@ class PDAImplementation(metaclass=abc.ABCMeta):
raise NotImplementedError()
class ImplementationException(Exception):
class ImplementationException(exc.RoyalnetException, metaclass=abc.ABCMeta):
"""
.. todo:: Document this.
Base class for exceptions raised by a PDA implementation.
"""
class ImplementationAlreadyBoundError(ImplementationException):
"""
.. todo:: Document this.
The PDA implementation is already bound to a PDA.
"""

View file

@ -14,21 +14,33 @@ log = logging.getLogger(__name__)
class Router(c.Conversation, metaclass=abc.ABCMeta):
"""
.. todo:: Document this.
A conversation which delegates event handling to other conversations by matching the contents of the first message received to one or multiple regexes.
"""
def __init__(self):
"""
.. todo:: Document this.
"""
self.by_pattern: dict[t.Pattern, t.ConversationProtocol] = {}
self.by_name: dict[str, t.ConversationProtocol] = {}
self.by_command: dict[t.ConversationProtocol, t.List[str]] = {}
def register_conversation(self, conv: t.ConversationProtocol, names: t.List[str], patterns: t.List[t.Pattern]):
"""
.. todo:: Document this.
A :class:`dict` mapping regex patterns to conversations registered with this router.
"""
self.by_name: dict[str, t.ConversationProtocol] = {}
"""
A :class:`dict` mapping command names to conversations registered with this router.
"""
self.by_command: dict[t.ConversationProtocol, t.List[str]] = {}
"""
A :class:`dict` mapping conversations registered with this router to lists of command names.
"""
self.else_convs: list[t.ConversationProtocol] = []
"""
A :class:`list` of conversations to delegate event handling to in case no other pattern is matched.
"""
def register_conversation(self, conv: t.ConversationProtocol, names: t.List[str], patterns: t.List[t.Pattern]) -> None:
"""
Registers a new conversation with the :class:`.Router`, allowing it to run if one of the specified ``patterns`` is matched.
"""
log.debug(f"Registering {conv!r}...")
@ -45,10 +57,6 @@ class Router(c.Conversation, metaclass=abc.ABCMeta):
self.by_pattern[pattern] = conv
async def run(self, _sentry: s.Sentry, _conv: t.ConversationProtocol, **kwargs) -> None:
"""
.. todo:: Document this.
"""
dispenser = _sentry.dispenser()
log.debug(f"Locking {dispenser!r}...")
@ -93,8 +101,16 @@ class Router(c.Conversation, metaclass=abc.ABCMeta):
)
return
else:
log.debug("No matches found")
for conversation in self.else_convs:
log.debug(f"No matches found, running conversation {conversation}")
await conversation(
**kwargs,
_sentry=_sentry,
_conv=conversation,
_msg=msg,
_text=text,
_router=self,
)
__all__ = (
"Router",

View file

@ -1,7 +1,6 @@
"""
This module contains the :class:`.Sentry` class and its descendents :class:`SentryFilter` and :class:`SentrySource`\\ .
They support event filtering through Wrenches and coroutine functions.
"""
@ -113,7 +112,7 @@ class Sentry(metaclass=abc.ABCMeta):
if callable(wrench):
return SentryFilter(previous=self, wrench=wrench)
else:
raise TypeError("wrench must be either a Wrench or a coroutine function")
raise TypeError("wrench parameter must be either a Wrench or a coroutine function")
def __or__(self, other: t.WrenchLike) -> SentryFilter:
"""
@ -130,7 +129,7 @@ class Sentry(metaclass=abc.ABCMeta):
try:
return self.filter(other)
except TypeError:
raise TypeError("Right-side must be either a Wrench or a coroutine function")
raise TypeError("Right-side of bitwise-or operator must be either a Wrench or a coroutine function")
@abc.abstractmethod
def dispenser(self) -> Dispenser:

View file

@ -1,3 +1,8 @@
"""
This module exports the base exceptions used in all :mod:`royalnet` modules.
"""
class RoyalnetException(Exception):
"""An exception raised by a Royalnet module."""

View file

@ -1,9 +1,11 @@
"""
This module adds some new common royaltyping to the default typing package.
This module defines adds some common types to the default :mod:`typing` module present in the standard library.
It should be imported with: ::
It is recommended to import it with *one* of the following statements::
import royalnet.royaltyping as t
from royalnet.royaltyping import *
from royalnet.royaltyping import <used_objects>
"""
@ -45,4 +47,11 @@ class ConversationProtocol(Protocol):
Args = Collection[Any]
"""
Any possible combination of positional arguments.
"""
Kwargs = Mapping[str, Any]
"""
Any possible combination of keyword arguments.
"""