mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-26 21:14:19 +00:00
💥 Documentation and error handling
This commit is contained in:
parent
3586bd7493
commit
f21c77a0d7
3 changed files with 79 additions and 21 deletions
|
@ -114,13 +114,20 @@ class FullCommand:
|
||||||
|
|
||||||
def __call__(self, *, _sentry: s.Sentry, **kwargs) -> t.Awaitable[t.Optional[c.ConversationProtocol]]:
|
def __call__(self, *, _sentry: s.Sentry, **kwargs) -> t.Awaitable[t.Optional[c.ConversationProtocol]]:
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
:return: Get the awaitable of the :class:`.FullCommand`.
|
||||||
|
|
||||||
|
.. seealso:: :meth:`.run`
|
||||||
"""
|
"""
|
||||||
return self.run(_sentry=_sentry, **kwargs)
|
return self.run(_sentry=_sentry, **kwargs)
|
||||||
|
|
||||||
async def run(self, *, _sentry: s.Sentry, **kwargs) -> t.Optional[c.ConversationProtocol]:
|
async def run(self, *, _sentry: s.Sentry, **kwargs) -> t.Optional[c.ConversationProtocol]:
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
Run the command.
|
||||||
|
|
||||||
|
:param _sentry: The :class:`~royalnet.engineer.sentry.Sentry` the command should use to receive
|
||||||
|
:class:`~royalnet.engineer.bullet.projectiles.Projectile`\\ s.
|
||||||
|
:param kwargs: Additional kwargs to pass to the :attr:`.teleported_f` .
|
||||||
|
:return: :data:`None` or another :class:`~royalnet.engineer.conversation.Conversation` to switch to.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
log.debug(f"Awaiting a bullet...")
|
log.debug(f"Awaiting a bullet...")
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Dispenser:
|
||||||
A :class:`list` of all the running sentries of this dispenser.
|
A :class:`list` of all the running sentries of this dispenser.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._locked_by: t.List[ConversationProtocol] = []
|
self.locked_by: t.List[ConversationProtocol] = []
|
||||||
"""
|
"""
|
||||||
The conversation that are currently locking this dispenser.
|
The conversation that are currently locking this dispenser.
|
||||||
|
|
||||||
|
@ -91,10 +91,10 @@ class Dispenser:
|
||||||
"""
|
"""
|
||||||
log.debug(f"Trying to run: {conv!r}")
|
log.debug(f"Trying to run: {conv!r}")
|
||||||
|
|
||||||
if self._locked_by:
|
if self.locked_by:
|
||||||
log.debug(f"Dispenser is locked by {self._locked_by!r}, refusing to run {conv!r}")
|
log.debug(f"Dispenser is locked by {self.locked_by!r}, refusing to run {conv!r}")
|
||||||
raise LockedDispenserError(
|
raise LockedDispenserError(
|
||||||
f"The Dispenser is currently locked and cannot start any new Conversation.", self._locked_by)
|
f"The Dispenser is currently locked and cannot start any new Conversation.", self.locked_by)
|
||||||
|
|
||||||
log.debug(f"Running: {conv!r}")
|
log.debug(f"Running: {conv!r}")
|
||||||
with self.sentry() as sentry:
|
with self.sentry() as sentry:
|
||||||
|
@ -114,16 +114,16 @@ class Dispenser:
|
||||||
|
|
||||||
:param conv: The conversation that requested the lock.
|
:param conv: The conversation that requested the lock.
|
||||||
|
|
||||||
.. seealso:: :attr:`._locked_by`
|
.. seealso:: :attr:`.locked_by`
|
||||||
"""
|
"""
|
||||||
log.debug(f"Adding lock: {conv!r}")
|
log.debug(f"Adding lock: {conv!r}")
|
||||||
self._locked_by.append(conv)
|
self.locked_by.append(conv)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
log.debug(f"Clearing lock: {conv!r}")
|
log.debug(f"Clearing lock: {conv!r}")
|
||||||
self._locked_by.remove(conv)
|
self.locked_by.remove(conv)
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
|
|
@ -7,7 +7,7 @@ import abc
|
||||||
import contextlib
|
import contextlib
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from royalnet.engineer.dispenser import Dispenser
|
from royalnet.engineer.dispenser import Dispenser, LockedDispenserError
|
||||||
|
|
||||||
if t.TYPE_CHECKING:
|
if t.TYPE_CHECKING:
|
||||||
from royalnet.engineer.conversation import ConversationProtocol
|
from royalnet.engineer.conversation import ConversationProtocol
|
||||||
|
@ -154,9 +154,9 @@ class ConversationListImplementation(PDAImplementation, metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
def _create_dispenser(self) -> "Dispenser":
|
def _create_dispenser(self) -> "Dispenser":
|
||||||
"""
|
"""
|
||||||
Create a new dispenser.
|
Create a new :class:`~royalnet.engineer.dispenser.Dispenser` .
|
||||||
|
|
||||||
:return: The created dispenser.
|
:return: The created :class:`~royalnet.engineer.dispenser.Dispenser` .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.log.debug(f"Creating new dispenser...")
|
self.log.debug(f"Creating new dispenser...")
|
||||||
|
@ -164,7 +164,11 @@ class ConversationListImplementation(PDAImplementation, metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
def get_or_create_dispenser(self, key: "DispenserKey") -> "Dispenser":
|
def get_or_create_dispenser(self, key: "DispenserKey") -> "Dispenser":
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
Try to :meth:`.get_dispenser` the :class:`~royalnet.engineer.dispenser.Dispenser` with the specified key, or
|
||||||
|
:meth:`._create_dispenser` a new one if it isn't available.
|
||||||
|
|
||||||
|
:param key: The key of the :class:`~royalnet.engineer.dispenser.Dispenser` .
|
||||||
|
:return: The retrieved or created :class:`~royalnet.engineer.dispenser.Dispenser` .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if key not in self.dispensers:
|
if key not in self.dispensers:
|
||||||
|
@ -202,7 +206,12 @@ class ConversationListImplementation(PDAImplementation, metaclass=abc.ABCMeta):
|
||||||
@contextlib.asynccontextmanager
|
@contextlib.asynccontextmanager
|
||||||
async def _kwargs(self, kwargs: t.Kwargs, remaining: list["PDAExtension"]) -> t.Kwargs:
|
async def _kwargs(self, kwargs: t.Kwargs, remaining: list["PDAExtension"]) -> t.Kwargs:
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
:func:`contextlib.asynccontextmanager` factory used internally to recurse the generation and cleanup of
|
||||||
|
:meth:`kwargs` .
|
||||||
|
|
||||||
|
:param kwargs: The current ``kwargs`` .
|
||||||
|
:param remaining: The extensions that haven't been processed yet.
|
||||||
|
:return: The corresponding :func:`contextlib.asynccontextmanager`\\ .
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if len(remaining) == 0:
|
if len(remaining) == 0:
|
||||||
|
@ -277,17 +286,59 @@ class ConversationListImplementation(PDAImplementation, metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
async def _run_conversation(self, dispenser: "Dispenser", conv: "ConversationProtocol") -> None:
|
async def _run_conversation(self, dispenser: "Dispenser", conv: "ConversationProtocol") -> None:
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
Run the passed :class:`~royalnet.engineer.conversation.Conversation` in the passed
|
||||||
|
:class:`~royalnet.engineer.dispenser.Dispenser`\\ , while passing the :meth:`.kwargs` provided by the
|
||||||
|
:class:`.PDA` .
|
||||||
|
|
||||||
|
:param dispenser: The :class:`~royalnet.engineer.dispenser.Dispenser` to run the
|
||||||
|
:class:`~royalnet.engineer.conversation.Conversation` in.
|
||||||
|
:param conv: The :class:`~royalnet.engineer.conversation.Conversation` to run.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
async with self.kwargs(conv=conv) as kwargs:
|
async with self.kwargs(conv=conv) as kwargs:
|
||||||
self.log.debug(f"Running {conv!r} in {dispenser!r}...")
|
self.log.debug(f"Running {conv!r} in {dispenser!r}...")
|
||||||
await dispenser.run(conv=conv, **kwargs)
|
await dispenser.run(conv=conv, **kwargs)
|
||||||
|
except Exception as exception:
|
||||||
|
try:
|
||||||
|
await self._handle_conversation_exc(dispenser=dispenser, conv=conv, exception=exception)
|
||||||
|
except Exception as exception:
|
||||||
|
self.log.error(f"Failed to handle conversation exception: {exception!r}")
|
||||||
|
|
||||||
async def _run_all_conversations(self, dispenser: "Dispenser") -> list[asyncio.Task]:
|
@abc.abstractmethod
|
||||||
|
async def _handle_conversation_exc(
|
||||||
|
self,
|
||||||
|
dispenser: "Dispenser",
|
||||||
|
conv: "ConversationProtocol",
|
||||||
|
exception: Exception
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
.. todo:: Document this.
|
Handle :exc:`Exception`\\ s that were not caught by :class:`~royalnet.engineer.conversation.Conversation`\\ s.
|
||||||
|
|
||||||
|
:param dispenser: The dispenser which hosted the :class:`~royalnet.engineer.conversation.Conversation`\\ .
|
||||||
|
:param conv: The :class:`~royalnet.engineer.conversation.Conversation` which didn't catch the error.
|
||||||
|
:param exception: The :class:`Exception` that was raised.
|
||||||
"""
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
async def _schedule_conversations(self, dispenser: "Dispenser") -> list[asyncio.Task]:
|
||||||
|
"""
|
||||||
|
Schedule the execution of instance of all the :class:`~royalnet.engineer.conversation.Conversation`\\ s listed
|
||||||
|
in :attr:`.conversations` in the specified :class:`~royalnet.engineer.dispenser.Dispenser`\\ .
|
||||||
|
|
||||||
|
:param dispenser: The :class:`~royalnet.engineer.dispenser.Dispenser` to run the
|
||||||
|
:class:`~royalnet.engineer.conversation.Conversation`\\ s in.
|
||||||
|
:return: The :class:`list` of :class:`asyncio.Task`\\ s that were created.
|
||||||
|
|
||||||
|
.. seealso:: :meth:`._run_conversation`
|
||||||
|
"""
|
||||||
|
|
||||||
|
if dispenser.locked_by:
|
||||||
|
self.log.warning("Tried to run a Conversation in a locked Dispenser!")
|
||||||
|
raise LockedDispenserError(
|
||||||
|
f"The Dispenser is currently locked and cannot start any new Conversation.",
|
||||||
|
dispenser.locked_by
|
||||||
|
)
|
||||||
|
|
||||||
self.log.info(f"Running in {dispenser!r} all conversations...")
|
self.log.info(f"Running in {dispenser!r} all conversations...")
|
||||||
|
|
||||||
|
@ -319,7 +370,7 @@ class ConversationListImplementation(PDAImplementation, metaclass=abc.ABCMeta):
|
||||||
dispenser = self.get_or_create_dispenser(key=key)
|
dispenser = self.get_or_create_dispenser(key=key)
|
||||||
|
|
||||||
self.log.debug(f"Running all conversations...")
|
self.log.debug(f"Running all conversations...")
|
||||||
await self._run_all_conversations(dispenser=dispenser)
|
await self._schedule_conversations(dispenser=dispenser)
|
||||||
|
|
||||||
self.log.debug(f"Putting {projectile!r} in {dispenser!r}...")
|
self.log.debug(f"Putting {projectile!r} in {dispenser!r}...")
|
||||||
await dispenser.put(projectile)
|
await dispenser.put(projectile)
|
||||||
|
|
Loading…
Reference in a new issue