Skip to content

Commit

Permalink
0.6.4
Browse files Browse the repository at this point in the history
  • Loading branch information
loRes228 committed Aug 18, 2024
1 parent fb3b521 commit 3a8e770
Show file tree
Hide file tree
Showing 31 changed files with 119 additions and 171 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ lint:

.PHONY: format
format:
ruff check --fix --unsafe-fixes ${PACKAGE_DIRECTORY}
ruff format ${CODE_DIRECTORIES}
ruff check --fix --unsafe-fixes ${PACKAGE_DIRECTORY}


# =====================================
Expand Down
2 changes: 1 addition & 1 deletion aiogram_broadcaster/__meta__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.6.3"
__version__ = "0.6.4"
11 changes: 6 additions & 5 deletions aiogram_broadcaster/broadcaster.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ async def restore_mailers(self) -> None:
logger.exception("Failed to restore mailer id=%d.", mailer_id)

async def run_mailers(self) -> None:
self.get_mailers(magic=F.status.is_(MailerStatus.STOPPED)).start()
group = self.get_mailers(magic=F.status.is_(MailerStatus.STOPPED))
group.start()

def setup(
self,
Expand All @@ -111,10 +112,10 @@ def setup(
if fetch_dispatcher_context:
self.context.update(dispatcher.workflow_data)
if self.storage:
dispatcher.startup.register(self.storage.startup)
dispatcher.shutdown.register(self.storage.shutdown)
dispatcher.startup.register(callback=self.storage.startup)
dispatcher.shutdown.register(callback=self.storage.shutdown)
if restore_mailers:
dispatcher.startup.register(self.restore_mailers)
dispatcher.startup.register(callback=self.restore_mailers)
if run_mailers:
dispatcher.startup.register(self.run_mailers)
dispatcher.startup.register(callback=self.run_mailers)
return self
2 changes: 1 addition & 1 deletion aiogram_broadcaster/contents/adapters/lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from abc import abstractmethod


class LazyContentAdapter(BaseContent):
class LazyContentAdapter(BaseContent, register=False):
async def as_method(self, **context: Any) -> TelegramMethod[Any]:
content: BaseContent = await self.call(**context)
return await content.as_method(**context)
Expand Down
2 changes: 1 addition & 1 deletion aiogram_broadcaster/contents/adapters/mapped.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from abc import abstractmethod


class MappedContentAdapter(BaseContent):
class MappedContentAdapter(BaseContent, register=False):
default: Optional[SerializeAsAny[BaseContent]] = None
__pydantic_extra__: dict[str, SerializeAsAny[BaseContent]]

Expand Down
4 changes: 2 additions & 2 deletions aiogram_broadcaster/contents/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from aiogram.methods import TelegramMethod
from pydantic import ConfigDict
from pydantic_discriminated_model import DiscriminatedModel

from aiogram_broadcaster.utils.callable_model import CallableModel
from aiogram_broadcaster.utils.discriminated_model import DiscriminatedModel


if TYPE_CHECKING:
Expand All @@ -13,7 +13,7 @@
ContentType = TypeVar("ContentType", bound="BaseContent")


class BaseContent(DiscriminatedModel, CallableModel):
class BaseContent(DiscriminatedModel, CallableModel, register=False):
model_config = ConfigDict(
extra="allow",
validate_assignment=True,
Expand Down
3 changes: 3 additions & 0 deletions aiogram_broadcaster/contents/paid_media.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
class PaidMediaContent(BaseContent):
star_count: int
media: list[Union[InputPaidMediaPhoto, InputPaidMediaVideo]]
business_connection_id: Optional[str] = None
caption: Optional[str] = None
parse_mode: Optional[str] = None
caption_entities: Optional[list[MessageEntity]] = None
Expand All @@ -41,6 +42,7 @@ async def __call__(self, chat_id: int) -> SendPaidMedia:
chat_id=chat_id,
star_count=self.star_count,
media=self.media,
business_connection_id=self.business_connection_id,
caption=self.caption,
parse_mode=self.parse_mode,
caption_entities=self.caption_entities,
Expand All @@ -58,6 +60,7 @@ def __init__(
*,
star_count: int,
media: list[Union[InputPaidMediaPhoto, InputPaidMediaVideo]],
business_connection_id: Optional[str] = ...,
caption: Optional[str] = ...,
parse_mode: Optional[str] = ...,
caption_entities: Optional[list[MessageEntity]] = ...,
Expand Down
6 changes: 3 additions & 3 deletions aiogram_broadcaster/event/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ def __init__(self, name: Optional[str] = None) -> None:
super().__init__(name=name)

self.created = EventObserver()
self.destroyed = EventObserver()
self.deleted = EventObserver()
self.started = EventObserver()
self.stopped = EventObserver()
self.completed = EventObserver()
self.failed_send = EventObserver()
self.success_send = EventObserver()
self.observers = {
self.observers: dict[str, EventObserver] = {
"created": self.created,
"destroyed": self.destroyed,
"deleted": self.deleted,
"started": self.started,
"stopped": self.stopped,
"completed": self.completed,
Expand Down
4 changes: 2 additions & 2 deletions aiogram_broadcaster/event/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ async def emit_event(self, event_name: str, /, **context: Any) -> None:
async def emit_created(self, **context: Any) -> None:
await self.emit_event("created", **context)

async def emit_destroyed(self, **context: Any) -> None:
await self.emit_event("destroyed", **context)
async def emit_deleted(self, **context: Any) -> None:
await self.emit_event("deleted", **context)

async def emit_started(self, **context: Any) -> None:
await self.emit_event("started", **context)
Expand Down
13 changes: 7 additions & 6 deletions aiogram_broadcaster/event/observer.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from typing import Any
from typing import Any, Callable

from aiogram.dispatcher.event.handler import FilterObject, HandlerObject
from aiogram.filters import Filter
from magic_filter import AttrDict, MagicFilter
from typing_extensions import Self

from aiogram_broadcaster.utils.common_types import CallbackType, WrapperType


class MagicContext(Filter):
"""For the magic filters to work properly."""
Expand All @@ -22,14 +20,17 @@ class EventObserver:
def __init__(self) -> None:
self.handlers: list[HandlerObject] = []

def __call__(self, *filters: CallbackType) -> WrapperType:
def wrapper(callback: CallbackType) -> CallbackType:
def __call__(
self,
*filters: Callable[..., Any],
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
def wrapper(callback: Callable[..., Any]) -> Callable[..., Any]:
self.register(callback, *filters)
return callback

return wrapper

def register(self, callback: CallbackType, *filters: CallbackType) -> Self:
def register(self, callback: Callable[..., Any], *filters: Callable[..., Any]) -> Self:
filters_ = [
FilterObject(
callback=(
Expand Down
5 changes: 3 additions & 2 deletions aiogram_broadcaster/intervals/base.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from asyncio import Event
from typing import TYPE_CHECKING, Any

from pydantic_discriminated_model import DiscriminatedModel

from aiogram_broadcaster.utils.callable_model import CallableModel
from aiogram_broadcaster.utils.discriminated_model import DiscriminatedModel
from aiogram_broadcaster.utils.sleep import sleep


if TYPE_CHECKING:
from abc import abstractmethod


class BaseInterval(DiscriminatedModel, CallableModel):
class BaseInterval(DiscriminatedModel, CallableModel, register=False):
async def sleep(self, event: Event, /, **context: Any) -> bool:
if event.is_set():
return False
Expand Down
9 changes: 3 additions & 6 deletions aiogram_broadcaster/mailer/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@


class MailerGroup(MailerContainer[ContentType]):
async def destroy(self) -> dict[Mailer[ContentType], Optional[BaseException]]:
return await self._emit(mailer.destroy() for mailer in self)
async def delete(self) -> dict[Mailer[ContentType], Optional[BaseException]]:
return await self._emit(mailer.delete() for mailer in self)

async def stop(self) -> dict[Mailer[ContentType], Optional[BaseException]]:
return await self._emit(mailer.stop() for mailer in self)
Expand Down Expand Up @@ -52,10 +52,7 @@ async def send(
for mailer in self
)

async def _emit(
self,
targets: Iterable[Awaitable[Any]],
) -> dict[Mailer[ContentType], Any]:
async def _emit(self, targets: Iterable[Awaitable[Any]]) -> dict[Mailer[ContentType], Any]:
if not targets:
return {}
results = await gather(*targets, return_exceptions=True)
Expand Down
61 changes: 30 additions & 31 deletions aiogram_broadcaster/mailer/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
from aiogram_broadcaster.intervals.base import BaseInterval
from aiogram_broadcaster.storages.base import StorageRecord
from aiogram_broadcaster.utils.exceptions import (
MailerDestroyedError,
MailerExtendedError,
MailerDeleteError,
MailerExtendError,
MailerResetError,
MailerStartedError,
MailerStoppedError,
MailerStartError,
MailerStopError,
)
from aiogram_broadcaster.utils.id_generator import generate_id
from aiogram_broadcaster.utils.logger import logger
Expand All @@ -40,7 +40,7 @@ class Mailer(Generic[ContentType]):
context: dict[str, Any]
broadcaster: "Broadcaster"
_stop_event: Event
_destroyed: bool
_deleted: bool

@classmethod
async def create(
Expand Down Expand Up @@ -71,7 +71,7 @@ async def create(
context=context.copy(),
broadcaster=broadcaster,
_stop_event=stop_event,
_destroyed=False,
_deleted=False,
)
mailer.context.update(
broadcaster.context,
Expand Down Expand Up @@ -123,7 +123,7 @@ async def create_from_record(
context=record.context.copy(),
broadcaster=broadcaster,
_stop_event=stop_event,
_destroyed=False,
_deleted=False,
)
mailer.context.update(
broadcaster.context,
Expand All @@ -147,44 +147,44 @@ def __eq__(self, other: object) -> bool:
return hash(self) == hash(other)

@property
def can_destroyed(self) -> bool:
return not self._destroyed
def can_deleted(self) -> bool:
return not self._deleted

@property
def can_stopped(self) -> bool:
return not self._destroyed and self.status is MailerStatus.STARTED
return not self._deleted and self.status is MailerStatus.STARTED

@property
def can_started(self) -> bool:
return not self._destroyed and self.status is MailerStatus.STOPPED
return not self._deleted and self.status is MailerStatus.STOPPED

@property
def can_extended(self) -> bool:
return not self._destroyed
return not self._deleted

@property
def can_reset(self) -> bool:
return (
not self._destroyed
not self._deleted
and self.status is not MailerStatus.STARTED
and self.chats.total != self.chats.pending
)

async def destroy(self) -> None:
if not self.can_destroyed:
raise MailerDestroyedError(mailer_id=self.id)
logger.info("Mailer id=%d was destroyed.", self.id)
async def delete(self) -> None:
if not self.can_deleted:
raise MailerDeleteError(mailer_id=self.id)
logger.info("Mailer id=%d was deleted.", self.id)
self.status = MailerStatus.COMPLETED
self._stop_event.set()
self._destroyed = True
self._deleted = True
del self.broadcaster.mailers[self.id]
if self.broadcaster.storage:
await self.broadcaster.storage.delete_record(mailer_id=self.id)
await self.broadcaster.event.emit_destroyed(**self.context)
await self.broadcaster.event.emit_deleted(**self.context)

async def stop(self) -> None:
if not self.can_stopped:
raise MailerStoppedError(mailer_id=self.id)
raise MailerStopError(mailer_id=self.id)
logger.info("Mailer id=%d was stopped.", self.id)
self.status = MailerStatus.STOPPED
self._stop_event.set()
Expand All @@ -195,7 +195,7 @@ def start(self) -> Task[bool]:

async def _start(self) -> bool:
if not self.can_started:
raise MailerStartedError(mailer_id=self.id)
raise MailerStartError(mailer_id=self.id)
logger.info("Mailer id=%d was started.", self.id)
self.status = MailerStatus.STARTED
self._stop_event.clear()
Expand All @@ -215,14 +215,12 @@ async def _start(self) -> bool:

async def extend(self, chats: Iterable[int]) -> set[int]:
if not self.can_extended:
raise MailerExtendedError(mailer_id=self.id)
raise MailerExtendError(mailer_id=self.id)
difference = set(chats) - self.chats.total.ids
if not difference:
return difference
self.chats.registry[ChatState.PENDING].update(difference)
if self.broadcaster.storage:
async with self.broadcaster.storage.update_record(mailer_id=self.id) as record:
record.chats = self.chats
await self._preserve_chats()
if self.status is MailerStatus.COMPLETED:
self.status = MailerStatus.STOPPED
logger.info(
Expand All @@ -238,9 +236,7 @@ async def reset(self) -> None:
total_chats = self.chats.total.ids
self.chats.registry.clear()
self.chats.registry[ChatState.PENDING].update(total_chats)
if self.broadcaster.storage:
async with self.broadcaster.storage.update_record(mailer_id=self.id) as record:
record.chats = self.chats
await self._preserve_chats()
if self.status is MailerStatus.COMPLETED:
self.status = MailerStatus.STOPPED
logger.info("Mailer id=%d has been reset.")
Expand Down Expand Up @@ -300,11 +296,14 @@ async def _process_chats(self) -> bool:
chat = self.chats.registry[ChatState.PENDING].pop()
success, _ = await self.send(chat_id=chat)
self.chats.registry[ChatState.SUCCESS if success else ChatState.FAILED].add(chat)
if self.broadcaster.storage:
async with self.broadcaster.storage.update_record(mailer_id=self.id) as record:
record.chats = self.chats
await self._preserve_chats()
if not self.chats.registry[ChatState.PENDING]:
return True
if self.interval:
await self.interval.sleep(self._stop_event, **self.context)
return True

async def _preserve_chats(self) -> None:
if self.broadcaster.storage:
async with self.broadcaster.storage.update_record(mailer_id=self.id) as record:
record.chats = self.chats
12 changes: 7 additions & 5 deletions aiogram_broadcaster/placeholder/items/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Callable

from aiogram.dispatcher.event.handler import CallableObject
from typing_extensions import Self

from aiogram_broadcaster.utils.common_types import CallbackType, WrapperType


if TYPE_CHECKING:
from aiogram_broadcaster.placeholder.placeholder import Placeholder
Expand Down Expand Up @@ -39,8 +37,12 @@ class BasePlaceholderDecorator(ABC):
def __init__(self, placeholder: "Placeholder") -> None:
self._placeholder = placeholder

def __call__(self, *args: Any, **kwargs: Any) -> WrapperType:
def wrapper(callback: CallbackType) -> CallbackType:
def __call__(
self,
*args: Any,
**kwargs: Any,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
def wrapper(callback: Callable[..., Any]) -> Callable[..., Any]:
self.register(callback, *args, **kwargs)
return callback

Expand Down
Loading

0 comments on commit 3a8e770

Please sign in to comment.