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:
parent
81c8fb6fa7
commit
bb1f7b0795
11 changed files with 99 additions and 33 deletions
|
@ -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
15
royalnet/__init__.py
Normal 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.
|
||||
"""
|
|
@ -1,3 +1,7 @@
|
|||
"""
|
||||
This submodule implements quick alias for some common SQL filtering functions.
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
"""
|
||||
This submodule implements the :class:`.Makeable` mixin.
|
||||
"""
|
||||
|
||||
from royalnet.royaltyping import *
|
||||
import sqlalchemy.orm as o
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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."""
|
||||
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue