diff --git a/.apiversion b/.apiversion index 899dd4f5..83364075 100644 --- a/.apiversion +++ b/.apiversion @@ -1 +1 @@ -4.9 \ No newline at end of file +5.1 \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 1247ec56..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build docs - -on: - push: - branches: - - dev-3.x - -jobs: - build: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@master - - - name: Set up Python 3.8 - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - - name: Install dependencies - run: | - python -m pip install --upgrade pip poetry==1.1.4 - poetry install - mkdir -p reports - - - name: Bump versions - run: | - make bump - - - name: Lint code - run: | - make flake8-report - make mypy-report - - - name: Run tests - run: | - make test-coverage - - - name: Build docs - run: | - make docs - make docs-copy-reports - - - name: Build package - run: | - poetry build - mkdir -p site/simple - mv dist site/simple/aiogram - - - name: Publish docs - uses: SamKirkland/FTP-Deploy-Action@2.0.0 - env: - FTP_SERVER: 2038.host - FTP_USERNAME: ${{ secrets.DOCS_FTP_USERNAME }} - FTP_PASSWORD: ${{ secrets.DOCS_FTP_PASSWORD }} - LOCAL_DIR: site - REMOTE_DIR: public - ARGS: --delete --parallel=20 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d42ee11e..bdb5d012 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,7 @@ jobs: - name: Install dependencies run: | - python -m pip install --upgrade pip poetry==1.1.4 + python -m pip install --upgrade pip poetry poetry install - name: Lint code diff --git a/aiogram/__init__.py b/aiogram/__init__.py index f83bb4cb..7c756601 100644 --- a/aiogram/__init__.py +++ b/aiogram/__init__.py @@ -1,3 +1,5 @@ +from magic_filter import MagicFilter + from .client import session from .client.bot import Bot from .dispatcher import filters, handler @@ -10,8 +12,9 @@ try: _uvloop.install() except ImportError: # pragma: no cover - _uvloop = None + pass +F = MagicFilter() __all__ = ( "__api_version__", @@ -25,7 +28,8 @@ __all__ = ( "BaseMiddleware", "filters", "handler", + "F", ) __version__ = "3.0.0-alpha.6" -__api_version__ = "4.9" +__api_version__ = "5.1" diff --git a/aiogram/client/bot.py b/aiogram/client/bot.py index 695b7b28..19fe7838 100644 --- a/aiogram/client/bot.py +++ b/aiogram/client/bot.py @@ -30,12 +30,14 @@ from ..methods import ( AnswerShippingQuery, Close, CopyMessage, + CreateChatInviteLink, CreateNewStickerSet, DeleteChatPhoto, DeleteChatStickerSet, DeleteMessage, DeleteStickerFromSet, DeleteWebhook, + EditChatInviteLink, EditMessageCaption, EditMessageLiveLocation, EditMessageMedia, @@ -61,6 +63,7 @@ from ..methods import ( PinChatMessage, PromoteChatMember, RestrictChatMember, + RevokeChatInviteLink, SendAnimation, SendAudio, SendChatAction, @@ -103,6 +106,7 @@ from ..types import ( UNSET, BotCommand, Chat, + ChatInviteLink, ChatMember, ChatPermissions, Downloadable, @@ -279,6 +283,9 @@ class Bot(ContextInstanceMixin["Bot"]): raise TypeError("file can only be of the string or Downloadable type") file_ = await self.get_file(file_id) + + # `file_path` can be None for large files but this files can't be downloaded + # So we need to do type-cast # https://github.com/aiogram/aiogram/pull/282/files#r394110017 file_path = cast(str, file_.file_path) @@ -343,7 +350,7 @@ class Bot(ContextInstanceMixin["Bot"]): :param offset: Identifier of the first update to be returned. Must be greater by one than the highest among the identifiers of previously received updates. By default, updates starting with the earliest unconfirmed update are returned. An update is considered confirmed as soon as :class:`aiogram.methods.get_updates.GetUpdates` is called with an *offset* higher than its *update_id*. The negative offset can be specified to retrieve updates starting from *-offset* update from the end of the updates queue. All previous updates will forgotten. :param limit: Limits the number of updates to be retrieved. Values between 1-100 are accepted. Defaults to 100. :param timeout: Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only. - :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all updates regardless of type (default). If not specified, the previous setting will be used. + :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member* (default). If not specified, the previous setting will be used. :param request_timeout: Request timeout :return: An Array of Update objects is returned. """ @@ -384,7 +391,7 @@ class Bot(ContextInstanceMixin["Bot"]): :param certificate: Upload your public key certificate so that the root certificate in use can be checked. See our `self-signed guide `_ for details. :param ip_address: The fixed IP address which will be used to send webhook requests instead of the IP address resolved through DNS :param max_connections: Maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to *40*. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput. - :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all updates regardless of type (default). If not specified, the previous setting will be used. + :param allowed_updates: A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member* (default). If not specified, the previous setting will be used. :param drop_pending_updates: Pass :code:`True` to drop all pending updates :param request_timeout: Request timeout :return: Returns True on success. @@ -539,7 +546,7 @@ class Bot(ContextInstanceMixin["Bot"]): request_timeout: Optional[int] = None, ) -> Message: """ - Use this method to forward messages of any kind. On success, the sent :class:`aiogram.types.message.Message` is returned. + Use this method to forward messages of any kind. Service messages can't be forwarded. On success, the sent :class:`aiogram.types.message.Message` is returned. Source: https://core.telegram.org/bots/api#forwardmessage @@ -575,7 +582,7 @@ class Bot(ContextInstanceMixin["Bot"]): request_timeout: Optional[int] = None, ) -> MessageId: """ - Use this method to copy messages of any kind. The method is analogous to the method :class:`aiogram.methods.forward_messages.ForwardMessages`, but the copied message doesn't have a link to the original message. Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success. + Use this method to copy messages of any kind. Service messages and invoice messages can't be copied. The method is analogous to the method :class:`aiogram.methods.forward_message.ForwardMessage`, but the copied message doesn't have a link to the original message. Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success. Source: https://core.telegram.org/bots/api#copymessage @@ -1314,7 +1321,7 @@ class Bot(ContextInstanceMixin["Bot"]): Source: https://core.telegram.org/bots/api#senddice :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`) - :param emoji: Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', or '🎰'. Dice can have values 1-6 for '🎲' and '🎯', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲' + :param emoji: Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', '🎳', or '🎰'. Dice can have values 1-6 for '🎲', '🎯' and '🎳', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲' :param disable_notification: Sends the message `silently `_. Users will receive a notification with no sound. :param reply_to_message_id: If the message is a reply, ID of the original message :param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found @@ -1408,6 +1415,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Union[int, str], user_id: int, until_date: Optional[Union[datetime.datetime, datetime.timedelta, int]] = None, + revoke_messages: Optional[bool] = None, request_timeout: Optional[int] = None, ) -> bool: """ @@ -1418,6 +1426,7 @@ class Bot(ContextInstanceMixin["Bot"]): :param chat_id: Unique identifier for the target group or username of the target supergroup or channel (in the format :code:`@channelusername`) :param user_id: Unique identifier of the target user :param until_date: Date when the user will be unbanned, unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Applied for supergroups and channels only. + :param revoke_messages: Pass :code:`True` to delete all messages from the chat for the user that is being removed. If :code:`False`, the user will be able to see messages in the group that were sent before the user was removed. Always :code:`True` for supergroups and channels. :param request_timeout: Request timeout :return: In the case of supergroups and channels, the user will not be able to return to the chat on their own using invite links, etc. Returns True on success. @@ -1426,6 +1435,7 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id=chat_id, user_id=user_id, until_date=until_date, + revoke_messages=revoke_messages, ) return await self(call, request_timeout=request_timeout) @@ -1488,14 +1498,16 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id: Union[int, str], user_id: int, is_anonymous: Optional[bool] = None, - can_change_info: Optional[bool] = None, + can_manage_chat: Optional[bool] = None, can_post_messages: Optional[bool] = None, can_edit_messages: Optional[bool] = None, can_delete_messages: Optional[bool] = None, - can_invite_users: Optional[bool] = None, + can_manage_voice_chats: Optional[bool] = None, can_restrict_members: Optional[bool] = None, - can_pin_messages: Optional[bool] = None, can_promote_members: Optional[bool] = None, + can_change_info: Optional[bool] = None, + can_invite_users: Optional[bool] = None, + can_pin_messages: Optional[bool] = None, request_timeout: Optional[int] = None, ) -> bool: """ @@ -1506,14 +1518,16 @@ class Bot(ContextInstanceMixin["Bot"]): :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`) :param user_id: Unique identifier of the target user :param is_anonymous: Pass :code:`True`, if the administrator's presence in the chat is hidden - :param can_change_info: Pass True, if the administrator can change chat title, photo and other settings + :param can_manage_chat: Pass True, if the administrator can access the chat event log, chat statistics, message statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other administrator privilege :param can_post_messages: Pass True, if the administrator can create channel posts, channels only :param can_edit_messages: Pass True, if the administrator can edit messages of other users and can pin messages, channels only :param can_delete_messages: Pass True, if the administrator can delete messages of other users - :param can_invite_users: Pass True, if the administrator can invite new users to the chat + :param can_manage_voice_chats: Pass True, if the administrator can manage voice chats :param can_restrict_members: Pass True, if the administrator can restrict, ban or unban chat members - :param can_pin_messages: Pass True, if the administrator can pin messages, supergroups only :param can_promote_members: Pass True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed by him) + :param can_change_info: Pass True, if the administrator can change chat title, photo and other settings + :param can_invite_users: Pass True, if the administrator can invite new users to the chat + :param can_pin_messages: Pass True, if the administrator can pin messages, supergroups only :param request_timeout: Request timeout :return: Returns True on success. """ @@ -1521,14 +1535,16 @@ class Bot(ContextInstanceMixin["Bot"]): chat_id=chat_id, user_id=user_id, is_anonymous=is_anonymous, - can_change_info=can_change_info, + can_manage_chat=can_manage_chat, can_post_messages=can_post_messages, can_edit_messages=can_edit_messages, can_delete_messages=can_delete_messages, - can_invite_users=can_invite_users, + can_manage_voice_chats=can_manage_voice_chats, can_restrict_members=can_restrict_members, - can_pin_messages=can_pin_messages, can_promote_members=can_promote_members, + can_change_info=can_change_info, + can_invite_users=can_invite_users, + can_pin_messages=can_pin_messages, ) return await self(call, request_timeout=request_timeout) @@ -1585,9 +1601,9 @@ class Bot(ContextInstanceMixin["Bot"]): request_timeout: Optional[int] = None, ) -> str: """ - Use this method to generate a new invite link for a chat; any previously generated link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the new invite link as *String* on success. + Use this method to generate a new primary invite link for a chat; any previously generated primary link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the new invite link as *String* on success. - Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` — after this the link will become available to the bot via the :class:`aiogram.methods.get_chat.GetChat` method. If your bot needs to generate a new invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again. + Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` or by calling the :class:`aiogram.methods.get_chat.GetChat` method. If your bot needs to generate a new primary invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again. Source: https://core.telegram.org/bots/api#exportchatinvitelink @@ -1600,6 +1616,81 @@ class Bot(ContextInstanceMixin["Bot"]): ) return await self(call, request_timeout=request_timeout) + async def create_chat_invite_link( + self, + chat_id: Union[int, str], + expire_date: Optional[int] = None, + member_limit: Optional[int] = None, + request_timeout: Optional[int] = None, + ) -> ChatInviteLink: + """ + Use this method to create an additional invite link for a chat. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. The link can be revoked using the method :class:`aiogram.methods.revoke_chat_invite_link.RevokeChatInviteLink`. Returns the new invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#createchatinvitelink + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`) + :param expire_date: Point in time (Unix timestamp) when the link will expire + :param member_limit: Maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999 + :param request_timeout: Request timeout + :return: Returns the new invite link as ChatInviteLink object. + """ + call = CreateChatInviteLink( + chat_id=chat_id, + expire_date=expire_date, + member_limit=member_limit, + ) + return await self(call, request_timeout=request_timeout) + + async def edit_chat_invite_link( + self, + chat_id: Union[int, str], + invite_link: str, + expire_date: Optional[int] = None, + member_limit: Optional[int] = None, + request_timeout: Optional[int] = None, + ) -> ChatInviteLink: + """ + Use this method to edit a non-primary invite link created by the bot. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#editchatinvitelink + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`) + :param invite_link: The invite link to edit + :param expire_date: Point in time (Unix timestamp) when the link will expire + :param member_limit: Maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999 + :param request_timeout: Request timeout + :return: Returns the edited invite link as a ChatInviteLink object. + """ + call = EditChatInviteLink( + chat_id=chat_id, + invite_link=invite_link, + expire_date=expire_date, + member_limit=member_limit, + ) + return await self(call, request_timeout=request_timeout) + + async def revoke_chat_invite_link( + self, + chat_id: Union[int, str], + invite_link: str, + request_timeout: Optional[int] = None, + ) -> ChatInviteLink: + """ + Use this method to revoke an invite link created by the bot. If the primary link is revoked, a new link is automatically generated. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the revoked invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#revokechatinvitelink + + :param chat_id: Unique identifier of the target chat or username of the target channel (in the format :code:`@channelusername`) + :param invite_link: The invite link to revoke + :param request_timeout: Request timeout + :return: Returns the revoked invite link as ChatInviteLink object. + """ + call = RevokeChatInviteLink( + chat_id=chat_id, + invite_link=invite_link, + ) + return await self(call, request_timeout=request_timeout) + async def set_chat_photo( self, chat_id: Union[int, str], @@ -2443,14 +2534,16 @@ class Bot(ContextInstanceMixin["Bot"]): async def send_invoice( self, - chat_id: int, + chat_id: Union[int, str], title: str, description: str, payload: str, provider_token: str, - start_parameter: str, currency: str, prices: List[LabeledPrice], + max_tip_amount: Optional[int] = None, + suggested_tip_amounts: Optional[List[int]] = None, + start_parameter: Optional[str] = None, provider_data: Optional[str] = None, photo_url: Optional[str] = None, photo_size: Optional[int] = None, @@ -2474,14 +2567,16 @@ class Bot(ContextInstanceMixin["Bot"]): Source: https://core.telegram.org/bots/api#sendinvoice - :param chat_id: Unique identifier for the target private chat + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`) :param title: Product name, 1-32 characters :param description: Product description, 1-255 characters :param payload: Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. :param provider_token: Payments provider token, obtained via `Botfather `_ - :param start_parameter: Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter :param currency: Three-letter ISO 4217 currency code, see `more on currencies `_ :param prices: Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.) + :param max_tip_amount: The maximum accepted amount for tips in the *smallest units* of the currency (integer, **not** float/double). For example, for a maximum tip of :code:`US$ 1.45` pass :code:`max_tip_amount = 145`. See the *exp* parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0 + :param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the *smallest units* of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed *max_tip_amount*. + :param start_parameter: Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a *Pay* button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a *URL* button with a deep link to the bot (instead of a *Pay* button), with the value used as the start parameter :param provider_data: A JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. :param photo_url: URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. :param photo_size: Photo size @@ -2507,9 +2602,11 @@ class Bot(ContextInstanceMixin["Bot"]): description=description, payload=payload, provider_token=provider_token, - start_parameter=start_parameter, currency=currency, prices=prices, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts, + start_parameter=start_parameter, provider_data=provider_data, photo_url=photo_url, photo_size=photo_size, diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index ff0bf1a7..5f3f48fd 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -13,6 +13,11 @@ from ..types import TelegramObject, Update, User from ..utils.exceptions import TelegramAPIError from .event.bases import UNHANDLED, SkipHandler from .event.telegram import TelegramEventObserver +from .fsm.context import FSMContext +from .fsm.middleware import FSMContextMiddleware +from .fsm.storage.base import BaseStorage +from .fsm.storage.memory import MemoryStorage +from .fsm.strategy import FSMStrategy from .middlewares.error import ErrorsMiddleware from .middlewares.user_context import UserContextMiddleware from .router import Router @@ -23,15 +28,36 @@ class Dispatcher(Router): Root router """ - def __init__(self, **kwargs: Any) -> None: + def __init__( + self, + storage: Optional[BaseStorage] = None, + fsm_strategy: FSMStrategy = FSMStrategy.USER_IN_CHAT, + isolate_events: bool = True, + **kwargs: Any, + ) -> None: super(Dispatcher, self).__init__(**kwargs) - self.update = TelegramEventObserver(router=self, event_name="update") - self.observers["update"] = self.update - + # Telegram API provides originally only one event type - Update + # For making easily interactions with events here is registered handler which helps + # to separate Update to different event types like Message, CallbackQuery and etc. + self.update = self.observers["update"] = TelegramEventObserver( + router=self, event_name="update" + ) self.update.register(self._listen_update) - self.update.outer_middleware(UserContextMiddleware()) + + # Error handlers should works is out of all other functions and be registered before all other middlewares self.update.outer_middleware(ErrorsMiddleware(self)) + # User context middleware makes small optimization for all other builtin + # middlewares via caching the user and chat instances in the event context + self.update.outer_middleware(UserContextMiddleware()) + # FSM middleware should always be registered after User context middleware + # because here is used context from previous step + self.fsm = FSMContextMiddleware( + storage=storage if storage else MemoryStorage(), + strategy=fsm_strategy, + isolate_events=isolate_events, + ) + self.update.outer_middleware(self.fsm) self._running_lock = Lock() @@ -150,6 +176,12 @@ class Dispatcher(Router): elif update.poll_answer: update_type = "poll_answer" event = update.poll_answer + elif update.my_chat_member: + update_type = "my_chat_member" + event = update.my_chat_member + elif update.chat_member: + update_type = "chat_member" + event = update.chat_member else: warnings.warn( "Detected unknown update type.\n" @@ -201,13 +233,11 @@ class Dispatcher(Router): :param kwargs: contextual data for middlewares, filters and handlers :return: status """ - handled = False try: response = await self.feed_update(bot, update, **kwargs) - handled = handled is not UNHANDLED if call_answer and isinstance(response, TelegramMethod): await self._silent_call_request(bot=bot, result=response) - return handled + return response is not UNHANDLED except Exception as e: loggers.dispatcher.exception( @@ -347,3 +377,6 @@ class Dispatcher(Router): except (KeyboardInterrupt, SystemExit): # pragma: no cover # Allow to graceful shutdown pass + + def current_state(self, user_id: int, chat_id: int) -> FSMContext: + return self.fsm.get_context(user_id=user_id, chat_id=chat_id) diff --git a/aiogram/dispatcher/event/handler.py b/aiogram/dispatcher/event/handler.py index bc7ee10d..63f5130b 100644 --- a/aiogram/dispatcher/event/handler.py +++ b/aiogram/dispatcher/event/handler.py @@ -5,13 +5,15 @@ from dataclasses import dataclass, field from functools import partial from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Type, Union +from magic_filter import MagicFilter + from aiogram.dispatcher.filters.base import BaseFilter from aiogram.dispatcher.handler.base import BaseHandler CallbackType = Callable[..., Awaitable[Any]] SyncFilter = Callable[..., Any] AsyncFilter = Callable[..., Awaitable[Any]] -FilterType = Union[SyncFilter, AsyncFilter, BaseFilter] +FilterType = Union[SyncFilter, AsyncFilter, BaseFilter, MagicFilter] HandlerType = Union[FilterType, Type[BaseHandler]] @@ -47,6 +49,14 @@ class CallableMixin: class FilterObject(CallableMixin): callback: FilterType + def __post_init__(self) -> None: + # TODO: Make possibility to extract and explain magic from filter object. + # Current solution is hard for debugging because the MagicFilter instance can't be extracted + if isinstance(self.callback, MagicFilter): + # MagicFilter instance is callable but generates only "CallOperation" instead of applying the filter + self.callback = self.callback.resolve + super().__post_init__() + @dataclass class HandlerObject(CallableMixin): diff --git a/aiogram/dispatcher/filters/__init__.py b/aiogram/dispatcher/filters/__init__.py index 1452d0a3..a0456429 100644 --- a/aiogram/dispatcher/filters/__init__.py +++ b/aiogram/dispatcher/filters/__init__.py @@ -29,5 +29,7 @@ BUILTIN_FILTERS: Dict[str, Tuple[Type[BaseFilter], ...]] = { "pre_checkout_query": (), "poll": (), "poll_answer": (), + "my_chat_member": (), + "chat_member": (), "error": (ExceptionMessageFilter, ExceptionTypeFilter), } diff --git a/aiogram/dispatcher/filters/content_types.py b/aiogram/dispatcher/filters/content_types.py index 640a8b64..177ecdae 100644 --- a/aiogram/dispatcher/filters/content_types.py +++ b/aiogram/dispatcher/filters/content_types.py @@ -22,7 +22,7 @@ class ContentTypesFilter(BaseFilter): cls, value: Optional[Union[Sequence[str], str]] ) -> Optional[Sequence[str]]: if not value: - value = [ContentType.TEXT] + return value if isinstance(value, str): value = [value] allowed_content_types = set(ContentType.all()) diff --git a/aiogram/dispatcher/fsm/__init__.py b/aiogram/dispatcher/fsm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aiogram/dispatcher/fsm/context.py b/aiogram/dispatcher/fsm/context.py new file mode 100644 index 00000000..78ed480b --- /dev/null +++ b/aiogram/dispatcher/fsm/context.py @@ -0,0 +1,35 @@ +from typing import Any, Dict, Optional + +from aiogram.dispatcher.fsm.storage.base import BaseStorage, StateType + + +class FSMContext: + def __init__(self, storage: BaseStorage, chat_id: int, user_id: int) -> None: + self.storage = storage + self.chat_id = chat_id + self.user_id = user_id + + async def set_state(self, state: StateType = None) -> None: + await self.storage.set_state(chat_id=self.chat_id, user_id=self.user_id, state=state) + + async def get_state(self) -> Optional[str]: + return await self.storage.get_state(chat_id=self.chat_id, user_id=self.user_id) + + async def set_data(self, data: Dict[str, Any]) -> None: + await self.storage.set_data(chat_id=self.chat_id, user_id=self.user_id, data=data) + + async def get_data(self) -> Dict[str, Any]: + return await self.storage.get_data(chat_id=self.chat_id, user_id=self.user_id) + + async def update_data( + self, data: Optional[Dict[str, Any]] = None, **kwargs: Any + ) -> Dict[str, Any]: + if data: + kwargs.update(data) + return await self.storage.update_data( + chat_id=self.chat_id, user_id=self.user_id, data=kwargs + ) + + async def clear(self) -> None: + await self.set_state(state=None) + await self.set_data({}) diff --git a/aiogram/dispatcher/fsm/middleware.py b/aiogram/dispatcher/fsm/middleware.py new file mode 100644 index 00000000..0d9bfac0 --- /dev/null +++ b/aiogram/dispatcher/fsm/middleware.py @@ -0,0 +1,53 @@ +from typing import Any, Awaitable, Callable, Dict, Optional + +from aiogram.dispatcher.fsm.context import FSMContext +from aiogram.dispatcher.fsm.storage.base import BaseStorage +from aiogram.dispatcher.fsm.strategy import FSMStrategy, apply_strategy +from aiogram.dispatcher.middlewares.base import BaseMiddleware +from aiogram.types import Update + + +class FSMContextMiddleware(BaseMiddleware[Update]): + def __init__( + self, + storage: BaseStorage, + strategy: FSMStrategy = FSMStrategy.USER_IN_CHAT, + isolate_events: bool = True, + ) -> None: + self.storage = storage + self.strategy = strategy + self.isolate_events = isolate_events + + async def __call__( + self, + handler: Callable[[Update, Dict[str, Any]], Awaitable[Any]], + event: Update, + data: Dict[str, Any], + ) -> Any: + context = self._resolve_context(data) + data["fsm_storage"] = self.storage + if context: + data.update({"state": context, "raw_state": await context.get_state()}) + if self.isolate_events: + async with self.storage.lock(): + return await handler(event, data) + return await handler(event, data) + + def _resolve_context(self, data: Dict[str, Any]) -> Optional[FSMContext]: + user = data.get("event_from_user") + chat = data.get("event_chat") + chat_id = chat.id if chat else None + user_id = user.id if user else None + + if chat_id is None: + chat_id = user_id + + if chat_id is not None and user_id is not None: + chat_id, user_id = apply_strategy( + chat_id=chat_id, user_id=user_id, strategy=self.strategy + ) + return self.get_context(chat_id=chat_id, user_id=user_id) + return None + + def get_context(self, chat_id: int, user_id: int) -> FSMContext: + return FSMContext(storage=self.storage, chat_id=chat_id, user_id=user_id) diff --git a/aiogram/dispatcher/fsm/state.py b/aiogram/dispatcher/fsm/state.py new file mode 100644 index 00000000..d4ea1974 --- /dev/null +++ b/aiogram/dispatcher/fsm/state.py @@ -0,0 +1,134 @@ +import inspect +from typing import Any, Optional, Tuple, Type, no_type_check + +from ...types import TelegramObject + + +class State: + """ + State object + """ + + def __init__(self, state: Optional[str] = None, group_name: Optional[str] = None) -> None: + self._state = state + self._group_name = group_name + self._group: Optional[Type[StatesGroup]] = None + + @property + def group(self) -> "Type[StatesGroup]": + if not self._group: + raise RuntimeError("This state is not in any group.") + return self._group + + @property + def state(self) -> Optional[str]: + if self._state is None or self._state == "*": + return self._state + + if self._group_name is None and self._group: + group = self._group.__full_group_name__ + elif self._group_name: + group = self._group_name + else: + group = "@" + + return f"{group}:{self._state}" + + def set_parent(self, group: "Type[StatesGroup]") -> None: + if not issubclass(group, StatesGroup): + raise ValueError("Group must be subclass of StatesGroup") + self._group = group + + def __set_name__(self, owner: "Type[StatesGroup]", name: str) -> None: + if self._state is None: + self._state = name + self.set_parent(owner) + + def __str__(self) -> str: + return f"" + + __repr__ = __str__ + + def __call__(self, event: TelegramObject, raw_state: Optional[str] = None) -> bool: + if self.state == "*": + return True + return raw_state == self.state + + +class StatesGroupMeta(type): + __parent__: "Optional[Type[StatesGroup]]" + __childs__: "Tuple[Type[StatesGroup], ...]" + __states__: Tuple[State, ...] + __state_names__: Tuple[str, ...] + + @no_type_check + def __new__(mcs, name, bases, namespace, **kwargs): + cls = super(StatesGroupMeta, mcs).__new__(mcs, name, bases, namespace) + + states = [] + childs = [] + + for name, arg in namespace.items(): + if isinstance(arg, State): + states.append(arg) + elif inspect.isclass(arg) and issubclass(arg, StatesGroup): + childs.append(arg) + arg.__parent__ = cls + + cls.__parent__ = None + cls.__childs__ = tuple(childs) + cls.__states__ = tuple(states) + cls.__state_names__ = tuple(state.state for state in states) + + return cls + + @property + def __full_group_name__(cls) -> str: + if cls.__parent__: + return ".".join((cls.__parent__.__full_group_name__, cls.__name__)) + return cls.__name__ + + @property + def __all_childs__(cls) -> Tuple[Type["StatesGroup"], ...]: + result = cls.__childs__ + for child in cls.__childs__: + result += child.__childs__ + return result + + @property + def __all_states__(cls) -> Tuple[State, ...]: + result = cls.__states__ + for group in cls.__childs__: + result += group.__all_states__ + return result + + @property + def __all_states_names__(cls) -> Tuple[str, ...]: + return tuple(state.state for state in cls.__all_states__ if state.state) + + def __contains__(cls, item: Any) -> bool: + if isinstance(item, str): + return item in cls.__all_states_names__ + if isinstance(item, State): + return item in cls.__all_states__ + # if isinstance(item, StatesGroup): + # return item in cls.__all_childs__ + return False + + def __str__(self) -> str: + return f"" + + +class StatesGroup(metaclass=StatesGroupMeta): + @classmethod + def get_root(cls) -> Type["StatesGroup"]: + if cls.__parent__ is None: + return cls + return cls.__parent__.get_root() + + # def __call__(cls, event: TelegramObject, raw_state: Optional[str] = None) -> bool: + # return raw_state in cls.__all_states_names__ + + +default_state = State() +any_state = State(state="*") diff --git a/aiogram/dispatcher/fsm/storage/__init__.py b/aiogram/dispatcher/fsm/storage/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aiogram/dispatcher/fsm/storage/base.py b/aiogram/dispatcher/fsm/storage/base.py new file mode 100644 index 00000000..29cce9ed --- /dev/null +++ b/aiogram/dispatcher/fsm/storage/base.py @@ -0,0 +1,38 @@ +from abc import ABC, abstractmethod +from contextlib import asynccontextmanager +from typing import Any, AsyncGenerator, Dict, Optional, Union + +from aiogram.dispatcher.fsm.state import State + +StateType = Optional[Union[str, State]] + + +class BaseStorage(ABC): + @abstractmethod + @asynccontextmanager + async def lock(self) -> AsyncGenerator[None, None]: + yield None + + @abstractmethod + async def set_state(self, chat_id: int, user_id: int, state: StateType = None) -> None: + pass + + @abstractmethod + async def get_state(self, chat_id: int, user_id: int) -> Optional[str]: + pass + + @abstractmethod + async def set_data(self, chat_id: int, user_id: int, data: Dict[str, Any]) -> None: + pass + + @abstractmethod + async def get_data(self, chat_id: int, user_id: int) -> Dict[str, Any]: + pass + + async def update_data( + self, chat_id: int, user_id: int, data: Dict[str, Any] + ) -> Dict[str, Any]: + current_data = await self.get_data(chat_id=chat_id, user_id=user_id) + current_data.update(data) + await self.set_data(chat_id=chat_id, user_id=user_id, data=current_data) + return current_data.copy() diff --git a/aiogram/dispatcher/fsm/storage/memory.py b/aiogram/dispatcher/fsm/storage/memory.py new file mode 100644 index 00000000..46b6d60b --- /dev/null +++ b/aiogram/dispatcher/fsm/storage/memory.py @@ -0,0 +1,39 @@ +from asyncio import Lock +from collections import defaultdict +from contextlib import asynccontextmanager +from dataclasses import dataclass, field +from typing import Any, AsyncGenerator, DefaultDict, Dict, Optional + +from aiogram.dispatcher.fsm.state import State +from aiogram.dispatcher.fsm.storage.base import BaseStorage, StateType + + +@dataclass +class MemoryStorageRecord: + data: Dict[str, Any] = field(default_factory=dict) + state: Optional[str] = None + + +class MemoryStorage(BaseStorage): + def __init__(self) -> None: + self.storage: DefaultDict[int, DefaultDict[int, MemoryStorageRecord]] = defaultdict( + lambda: defaultdict(MemoryStorageRecord) + ) + self._lock = Lock() + + @asynccontextmanager + async def lock(self) -> AsyncGenerator[None, None]: + async with self._lock: + yield None + + async def set_state(self, chat_id: int, user_id: int, state: StateType = None) -> None: + self.storage[chat_id][user_id].state = state.state if isinstance(state, State) else state + + async def get_state(self, chat_id: int, user_id: int) -> Optional[str]: + return self.storage[chat_id][user_id].state + + async def set_data(self, chat_id: int, user_id: int, data: Dict[str, Any]) -> None: + self.storage[chat_id][user_id].data = data.copy() + + async def get_data(self, chat_id: int, user_id: int) -> Dict[str, Any]: + return self.storage[chat_id][user_id].data.copy() diff --git a/aiogram/dispatcher/fsm/strategy.py b/aiogram/dispatcher/fsm/strategy.py new file mode 100644 index 00000000..4f540a4a --- /dev/null +++ b/aiogram/dispatcher/fsm/strategy.py @@ -0,0 +1,16 @@ +from enum import Enum, auto +from typing import Tuple + + +class FSMStrategy(Enum): + USER_IN_CHAT = auto() + CHAT = auto() + GLOBAL_USER = auto() + + +def apply_strategy(chat_id: int, user_id: int, strategy: FSMStrategy) -> Tuple[int, int]: + if strategy == FSMStrategy.CHAT: + return chat_id, chat_id + if strategy == FSMStrategy.GLOBAL_USER: + return user_id, user_id + return chat_id, user_id diff --git a/aiogram/dispatcher/handler/__init__.py b/aiogram/dispatcher/handler/__init__.py index b2c5c9ef..7388a80c 100644 --- a/aiogram/dispatcher/handler/__init__.py +++ b/aiogram/dispatcher/handler/__init__.py @@ -1,5 +1,6 @@ from .base import BaseHandler, BaseHandlerMixin from .callback_query import CallbackQueryHandler +from .chat_member import ChatMemberUpdated from .chosen_inline_result import ChosenInlineResultHandler from .error import ErrorHandler from .inline_query import InlineQueryHandler @@ -12,6 +13,7 @@ __all__ = ( "BaseHandler", "BaseHandlerMixin", "CallbackQueryHandler", + "ChatMemberUpdated", "ChosenInlineResultHandler", "ErrorHandler", "InlineQueryHandler", diff --git a/aiogram/dispatcher/handler/callback_query.py b/aiogram/dispatcher/handler/callback_query.py index 8f129b21..690cdfea 100644 --- a/aiogram/dispatcher/handler/callback_query.py +++ b/aiogram/dispatcher/handler/callback_query.py @@ -7,17 +7,37 @@ from aiogram.types import CallbackQuery, Message, User class CallbackQueryHandler(BaseHandler[CallbackQuery], ABC): """ - Base class for callback query handlers + There is base class for callback query handlers. + + Example: + .. code-block:: python + + from aiogram.handlers import CallbackQueryHandler + + ... + + @router.callback_query() + class MyHandler(CallbackQueryHandler): + async def handle(self) -> Any: ... """ @property def from_user(self) -> User: + """ + Is alias for `event.from_user` + """ return self.event.from_user @property def message(self) -> Optional[Message]: + """ + Is alias for `event.message` + """ return self.event.message @property def callback_data(self) -> Optional[str]: + """ + Is alias for `event.data` + """ return self.event.data diff --git a/aiogram/dispatcher/handler/chat_member.py b/aiogram/dispatcher/handler/chat_member.py new file mode 100644 index 00000000..92793c98 --- /dev/null +++ b/aiogram/dispatcher/handler/chat_member.py @@ -0,0 +1,14 @@ +from abc import ABC + +from aiogram.dispatcher.handler import BaseHandler +from aiogram.types import ChatMemberUpdated, User + + +class ChatMemberHandler(BaseHandler[ChatMemberUpdated], ABC): + """ + Base class for chat member updated events + """ + + @property + def from_user(self) -> User: + return self.event.from_user diff --git a/aiogram/dispatcher/middlewares/user_context.py b/aiogram/dispatcher/middlewares/user_context.py index 1434eec4..c6e64878 100644 --- a/aiogram/dispatcher/middlewares/user_context.py +++ b/aiogram/dispatcher/middlewares/user_context.py @@ -14,6 +14,10 @@ class UserContextMiddleware(BaseMiddleware[Update]): ) -> Any: chat, user = self.resolve_event_context(event=event) with self.context(chat=chat, user=user): + if user is not None: + data["event_from_user"] = user + if chat is not None: + data["event_chat"] = chat return await handler(event, data) @contextmanager @@ -59,4 +63,8 @@ class UserContextMiddleware(BaseMiddleware[Update]): return None, event.pre_checkout_query.from_user if event.poll_answer: return None, event.poll_answer.user + if event.my_chat_member: + return event.my_chat_member.chat, event.my_chat_member.from_user + if event.chat_member: + return event.chat_member.chat, event.chat_member.from_user return None, None diff --git a/aiogram/dispatcher/router.py b/aiogram/dispatcher/router.py index 3370d3c0..2e659c7e 100644 --- a/aiogram/dispatcher/router.py +++ b/aiogram/dispatcher/router.py @@ -51,6 +51,9 @@ class Router: ) self.poll = TelegramEventObserver(router=self, event_name="poll") self.poll_answer = TelegramEventObserver(router=self, event_name="poll_answer") + self.my_chat_member = TelegramEventObserver(router=self, event_name="my_chat_member") + self.chat_member = TelegramEventObserver(router=self, event_name="chat_member") + self.errors = TelegramEventObserver(router=self, event_name="error") self.startup = EventObserver() @@ -68,6 +71,8 @@ class Router: "pre_checkout_query": self.pre_checkout_query, "poll": self.poll, "poll_answer": self.poll_answer, + "my_chat_member": self.my_chat_member, + "chat_member": self.chat_member, "error": self.errors, } diff --git a/aiogram/methods/__init__.py b/aiogram/methods/__init__.py index 9d498162..df602bef 100644 --- a/aiogram/methods/__init__.py +++ b/aiogram/methods/__init__.py @@ -6,12 +6,14 @@ from .answer_shipping_query import AnswerShippingQuery from .base import Request, Response, TelegramMethod from .close import Close from .copy_message import CopyMessage +from .create_chat_invite_link import CreateChatInviteLink from .create_new_sticker_set import CreateNewStickerSet from .delete_chat_photo import DeleteChatPhoto from .delete_chat_sticker_set import DeleteChatStickerSet from .delete_message import DeleteMessage from .delete_sticker_from_set import DeleteStickerFromSet from .delete_webhook import DeleteWebhook +from .edit_chat_invite_link import EditChatInviteLink from .edit_message_caption import EditMessageCaption from .edit_message_live_location import EditMessageLiveLocation from .edit_message_media import EditMessageMedia @@ -37,6 +39,7 @@ from .log_out import LogOut from .pin_chat_message import PinChatMessage from .promote_chat_member import PromoteChatMember from .restrict_chat_member import RestrictChatMember +from .revoke_chat_invite_link import RevokeChatInviteLink from .send_animation import SendAnimation from .send_audio import SendAudio from .send_chat_action import SendChatAction @@ -113,6 +116,9 @@ __all__ = ( "SetChatAdministratorCustomTitle", "SetChatPermissions", "ExportChatInviteLink", + "CreateChatInviteLink", + "EditChatInviteLink", + "RevokeChatInviteLink", "SetChatPhoto", "DeleteChatPhoto", "SetChatTitle", diff --git a/aiogram/methods/copy_message.py b/aiogram/methods/copy_message.py index dddf2c92..be94e4cc 100644 --- a/aiogram/methods/copy_message.py +++ b/aiogram/methods/copy_message.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: # pragma: no cover class CopyMessage(TelegramMethod[MessageId]): """ - Use this method to copy messages of any kind. The method is analogous to the method :class:`aiogram.methods.forward_messages.ForwardMessages`, but the copied message doesn't have a link to the original message. Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success. + Use this method to copy messages of any kind. Service messages and invoice messages can't be copied. The method is analogous to the method :class:`aiogram.methods.forward_message.ForwardMessage`, but the copied message doesn't have a link to the original message. Returns the :class:`aiogram.types.message_id.MessageId` of the sent message on success. Source: https://core.telegram.org/bots/api#copymessage """ diff --git a/aiogram/methods/create_chat_invite_link.py b/aiogram/methods/create_chat_invite_link.py new file mode 100644 index 00000000..c476df02 --- /dev/null +++ b/aiogram/methods/create_chat_invite_link.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Dict, Optional, Union + +from ..types import ChatInviteLink +from .base import Request, TelegramMethod + +if TYPE_CHECKING: # pragma: no cover + from ..client.bot import Bot + + +class CreateChatInviteLink(TelegramMethod[ChatInviteLink]): + """ + Use this method to create an additional invite link for a chat. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. The link can be revoked using the method :class:`aiogram.methods.revoke_chat_invite_link.RevokeChatInviteLink`. Returns the new invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#createchatinvitelink + """ + + __returning__ = ChatInviteLink + + chat_id: Union[int, str] + """Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)""" + expire_date: Optional[int] = None + """Point in time (Unix timestamp) when the link will expire""" + member_limit: Optional[int] = None + """Maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999""" + + def build_request(self, bot: Bot) -> Request: + data: Dict[str, Any] = self.dict() + + return Request(method="createChatInviteLink", data=data) diff --git a/aiogram/methods/edit_chat_invite_link.py b/aiogram/methods/edit_chat_invite_link.py new file mode 100644 index 00000000..d9380f20 --- /dev/null +++ b/aiogram/methods/edit_chat_invite_link.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Dict, Optional, Union + +from ..types import ChatInviteLink +from .base import Request, TelegramMethod + +if TYPE_CHECKING: # pragma: no cover + from ..client.bot import Bot + + +class EditChatInviteLink(TelegramMethod[ChatInviteLink]): + """ + Use this method to edit a non-primary invite link created by the bot. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the edited invite link as a :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#editchatinvitelink + """ + + __returning__ = ChatInviteLink + + chat_id: Union[int, str] + """Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)""" + invite_link: str + """The invite link to edit""" + expire_date: Optional[int] = None + """Point in time (Unix timestamp) when the link will expire""" + member_limit: Optional[int] = None + """Maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999""" + + def build_request(self, bot: Bot) -> Request: + data: Dict[str, Any] = self.dict() + + return Request(method="editChatInviteLink", data=data) diff --git a/aiogram/methods/export_chat_invite_link.py b/aiogram/methods/export_chat_invite_link.py index 5ee6b6d9..9321b5c6 100644 --- a/aiogram/methods/export_chat_invite_link.py +++ b/aiogram/methods/export_chat_invite_link.py @@ -10,9 +10,9 @@ if TYPE_CHECKING: # pragma: no cover class ExportChatInviteLink(TelegramMethod[str]): """ - Use this method to generate a new invite link for a chat; any previously generated link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the new invite link as *String* on success. + Use this method to generate a new primary invite link for a chat; any previously generated primary link is revoked. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the new invite link as *String* on success. - Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` — after this the link will become available to the bot via the :class:`aiogram.methods.get_chat.GetChat` method. If your bot needs to generate a new invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again. + Note: Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` or by calling the :class:`aiogram.methods.get_chat.GetChat` method. If your bot needs to generate a new primary invite link replacing its previous one, use :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink` again. Source: https://core.telegram.org/bots/api#exportchatinvitelink """ diff --git a/aiogram/methods/forward_message.py b/aiogram/methods/forward_message.py index 24b68919..e18e4cf6 100644 --- a/aiogram/methods/forward_message.py +++ b/aiogram/methods/forward_message.py @@ -11,7 +11,7 @@ if TYPE_CHECKING: # pragma: no cover class ForwardMessage(TelegramMethod[Message]): """ - Use this method to forward messages of any kind. On success, the sent :class:`aiogram.types.message.Message` is returned. + Use this method to forward messages of any kind. Service messages can't be forwarded. On success, the sent :class:`aiogram.types.message.Message` is returned. Source: https://core.telegram.org/bots/api#forwardmessage """ diff --git a/aiogram/methods/get_updates.py b/aiogram/methods/get_updates.py index e47dcbd9..e5c99378 100644 --- a/aiogram/methods/get_updates.py +++ b/aiogram/methods/get_updates.py @@ -31,7 +31,7 @@ class GetUpdates(TelegramMethod[List[Update]]): timeout: Optional[int] = None """Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be positive, short polling should be used for testing purposes only.""" allowed_updates: Optional[List[str]] = None - """A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all updates regardless of type (default). If not specified, the previous setting will be used.""" + """A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member* (default). If not specified, the previous setting will be used.""" def build_request(self, bot: Bot) -> Request: data: Dict[str, Any] = self.dict() diff --git a/aiogram/methods/kick_chat_member.py b/aiogram/methods/kick_chat_member.py index 1c18497e..11ed6bba 100644 --- a/aiogram/methods/kick_chat_member.py +++ b/aiogram/methods/kick_chat_member.py @@ -24,6 +24,8 @@ class KickChatMember(TelegramMethod[bool]): """Unique identifier of the target user""" until_date: Optional[Union[datetime.datetime, datetime.timedelta, int]] = None """Date when the user will be unbanned, unix time. If user is banned for more than 366 days or less than 30 seconds from the current time they are considered to be banned forever. Applied for supergroups and channels only.""" + revoke_messages: Optional[bool] = None + """Pass :code:`True` to delete all messages from the chat for the user that is being removed. If :code:`False`, the user will be able to see messages in the group that were sent before the user was removed. Always :code:`True` for supergroups and channels.""" def build_request(self, bot: Bot) -> Request: data: Dict[str, Any] = self.dict() diff --git a/aiogram/methods/promote_chat_member.py b/aiogram/methods/promote_chat_member.py index 335dd522..22347dcd 100644 --- a/aiogram/methods/promote_chat_member.py +++ b/aiogram/methods/promote_chat_member.py @@ -23,22 +23,26 @@ class PromoteChatMember(TelegramMethod[bool]): """Unique identifier of the target user""" is_anonymous: Optional[bool] = None """Pass :code:`True`, if the administrator's presence in the chat is hidden""" - can_change_info: Optional[bool] = None - """Pass True, if the administrator can change chat title, photo and other settings""" + can_manage_chat: Optional[bool] = None + """Pass True, if the administrator can access the chat event log, chat statistics, message statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other administrator privilege""" can_post_messages: Optional[bool] = None """Pass True, if the administrator can create channel posts, channels only""" can_edit_messages: Optional[bool] = None """Pass True, if the administrator can edit messages of other users and can pin messages, channels only""" can_delete_messages: Optional[bool] = None """Pass True, if the administrator can delete messages of other users""" - can_invite_users: Optional[bool] = None - """Pass True, if the administrator can invite new users to the chat""" + can_manage_voice_chats: Optional[bool] = None + """Pass True, if the administrator can manage voice chats""" can_restrict_members: Optional[bool] = None """Pass True, if the administrator can restrict, ban or unban chat members""" - can_pin_messages: Optional[bool] = None - """Pass True, if the administrator can pin messages, supergroups only""" can_promote_members: Optional[bool] = None """Pass True, if the administrator can add new administrators with a subset of their own privileges or demote administrators that he has promoted, directly or indirectly (promoted by administrators that were appointed by him)""" + can_change_info: Optional[bool] = None + """Pass True, if the administrator can change chat title, photo and other settings""" + can_invite_users: Optional[bool] = None + """Pass True, if the administrator can invite new users to the chat""" + can_pin_messages: Optional[bool] = None + """Pass True, if the administrator can pin messages, supergroups only""" def build_request(self, bot: Bot) -> Request: data: Dict[str, Any] = self.dict() diff --git a/aiogram/methods/revoke_chat_invite_link.py b/aiogram/methods/revoke_chat_invite_link.py new file mode 100644 index 00000000..ee684f6d --- /dev/null +++ b/aiogram/methods/revoke_chat_invite_link.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Dict, Union + +from ..types import ChatInviteLink +from .base import Request, TelegramMethod + +if TYPE_CHECKING: # pragma: no cover + from ..client.bot import Bot + + +class RevokeChatInviteLink(TelegramMethod[ChatInviteLink]): + """ + Use this method to revoke an invite link created by the bot. If the primary link is revoked, a new link is automatically generated. The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. Returns the revoked invite link as :class:`aiogram.types.chat_invite_link.ChatInviteLink` object. + + Source: https://core.telegram.org/bots/api#revokechatinvitelink + """ + + __returning__ = ChatInviteLink + + chat_id: Union[int, str] + """Unique identifier of the target chat or username of the target channel (in the format :code:`@channelusername`)""" + invite_link: str + """The invite link to revoke""" + + def build_request(self, bot: Bot) -> Request: + data: Dict[str, Any] = self.dict() + + return Request(method="revokeChatInviteLink", data=data) diff --git a/aiogram/methods/send_dice.py b/aiogram/methods/send_dice.py index ca8e0c12..65b148cd 100644 --- a/aiogram/methods/send_dice.py +++ b/aiogram/methods/send_dice.py @@ -27,7 +27,7 @@ class SendDice(TelegramMethod[Message]): chat_id: Union[int, str] """Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)""" emoji: Optional[str] = None - """Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', or '🎰'. Dice can have values 1-6 for '🎲' and '🎯', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲'""" + """Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', '🎳', or '🎰'. Dice can have values 1-6 for '🎲', '🎯' and '🎳', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲'""" disable_notification: Optional[bool] = None """Sends the message `silently `_. Users will receive a notification with no sound.""" reply_to_message_id: Optional[int] = None diff --git a/aiogram/methods/send_invoice.py b/aiogram/methods/send_invoice.py index 99bacb6c..97d569ea 100644 --- a/aiogram/methods/send_invoice.py +++ b/aiogram/methods/send_invoice.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Dict, List, Optional +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union from ..types import InlineKeyboardMarkup, LabeledPrice, Message from .base import Request, TelegramMethod @@ -18,8 +18,8 @@ class SendInvoice(TelegramMethod[Message]): __returning__ = Message - chat_id: int - """Unique identifier for the target private chat""" + chat_id: Union[int, str] + """Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)""" title: str """Product name, 1-32 characters""" description: str @@ -28,12 +28,16 @@ class SendInvoice(TelegramMethod[Message]): """Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.""" provider_token: str """Payments provider token, obtained via `Botfather `_""" - start_parameter: str - """Unique deep-linking parameter that can be used to generate this invoice when used as a start parameter""" currency: str """Three-letter ISO 4217 currency code, see `more on currencies `_""" prices: List[LabeledPrice] """Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)""" + max_tip_amount: Optional[int] = None + """The maximum accepted amount for tips in the *smallest units* of the currency (integer, **not** float/double). For example, for a maximum tip of :code:`US$ 1.45` pass :code:`max_tip_amount = 145`. See the *exp* parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0""" + suggested_tip_amounts: Optional[List[int]] = None + """A JSON-serialized array of suggested amounts of tips in the *smallest units* of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed *max_tip_amount*.""" + start_parameter: Optional[str] = None + """Unique deep-linking parameter. If left empty, **forwarded copies** of the sent message will have a *Pay* button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a *URL* button with a deep link to the bot (instead of a *Pay* button), with the value used as the start parameter""" provider_data: Optional[str] = None """A JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider.""" photo_url: Optional[str] = None diff --git a/aiogram/methods/set_webhook.py b/aiogram/methods/set_webhook.py index fc7539c4..1c1ffd13 100644 --- a/aiogram/methods/set_webhook.py +++ b/aiogram/methods/set_webhook.py @@ -37,7 +37,7 @@ class SetWebhook(TelegramMethod[bool]): max_connections: Optional[int] = None """Maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to *40*. Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.""" allowed_updates: Optional[List[str]] = None - """A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all updates regardless of type (default). If not specified, the previous setting will be used.""" + """A JSON-serialized list of the update types you want your bot to receive. For example, specify ['message', 'edited_channel_post', 'callback_query'] to only receive updates of these types. See :class:`aiogram.types.update.Update` for a complete list of available update types. Specify an empty list to receive all update types except *chat_member* (default). If not specified, the previous setting will be used.""" drop_pending_updates: Optional[bool] = None """Pass :code:`True` to drop all pending updates""" diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index 3a6141d9..eb4c2c55 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -5,8 +5,10 @@ from .bot_command import BotCommand from .callback_game import CallbackGame from .callback_query import CallbackQuery from .chat import Chat +from .chat_invite_link import ChatInviteLink from .chat_location import ChatLocation from .chat_member import ChatMember +from .chat_member_updated import ChatMemberUpdated from .chat_permissions import ChatPermissions from .chat_photo import ChatPhoto from .chosen_inline_result import ChosenInlineResult @@ -46,6 +48,7 @@ from .inline_query_result_video import InlineQueryResultVideo from .inline_query_result_voice import InlineQueryResultVoice from .input_contact_message_content import InputContactMessageContent from .input_file import BufferedInputFile, FSInputFile, InputFile, URLInputFile +from .input_invoice_message_content import InputInvoiceMessageContent from .input_location_message_content import InputLocationMessageContent from .input_media import InputMedia from .input_media_animation import InputMediaAnimation @@ -64,6 +67,7 @@ from .location import Location from .login_url import LoginUrl from .mask_position import MaskPosition from .message import ContentType, Message +from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged from .message_entity import MessageEntity from .message_id import MessageId from .order_info import OrderInfo @@ -101,6 +105,10 @@ from .venue import Venue from .video import Video from .video_note import VideoNote from .voice import Voice +from .voice_chat_ended import VoiceChatEnded +from .voice_chat_participants_invited import VoiceChatParticipantsInvited +from .voice_chat_scheduled import VoiceChatScheduled +from .voice_chat_started import VoiceChatStarted from .webhook_info import WebhookInfo __all__ = ( @@ -133,6 +141,11 @@ __all__ = ( "Location", "Venue", "ProximityAlertTriggered", + "MessageAutoDeleteTimerChanged", + "VoiceChatScheduled", + "VoiceChatStarted", + "VoiceChatEnded", + "VoiceChatParticipantsInvited", "UserProfilePhotos", "File", "ReplyKeyboardMarkup", @@ -145,7 +158,9 @@ __all__ = ( "CallbackQuery", "ForceReply", "ChatPhoto", + "ChatInviteLink", "ChatMember", + "ChatMemberUpdated", "ChatPermissions", "ChatLocation", "BotCommand", @@ -187,6 +202,7 @@ __all__ = ( "InputLocationMessageContent", "InputVenueMessageContent", "InputContactMessageContent", + "InputInvoiceMessageContent", "ChosenInlineResult", "LabeledPrice", "Invoice", diff --git a/aiogram/types/chat.py b/aiogram/types/chat.py index 8714ceb8..7d735ac3 100644 --- a/aiogram/types/chat.py +++ b/aiogram/types/chat.py @@ -19,7 +19,7 @@ class Chat(TelegramObject): """ id: int - """Unique identifier for this chat. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.""" + """Unique identifier for this chat. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this identifier.""" type: str """Type of chat, can be either 'private', 'group', 'supergroup' or 'channel'""" title: Optional[str] = None @@ -37,13 +37,15 @@ class Chat(TelegramObject): description: Optional[str] = None """*Optional*. Description, for groups, supergroups and channel chats. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" invite_link: Optional[str] = None - """*Optional*. Chat invite link, for groups, supergroups and channel chats. Each administrator in a chat generates their own invite links, so the bot must first generate the link using :class:`aiogram.methods.export_chat_invite_link.ExportChatInviteLink`. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" + """*Optional*. Primary invite link, for groups, supergroups and channel chats. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" pinned_message: Optional[Message] = None """*Optional*. The most recent pinned message (by sending date). Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" permissions: Optional[ChatPermissions] = None """*Optional*. Default chat member permissions, for groups and supergroups. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" slow_mode_delay: Optional[int] = None """*Optional*. For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" + message_auto_delete_time: Optional[int] = None + """*Optional*. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" sticker_set_name: Optional[str] = None """*Optional*. For supergroups, name of group sticker set. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" can_set_sticker_set: Optional[bool] = None diff --git a/aiogram/types/chat_invite_link.py b/aiogram/types/chat_invite_link.py new file mode 100644 index 00000000..4d39a116 --- /dev/null +++ b/aiogram/types/chat_invite_link.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + from .user import User + + +class ChatInviteLink(TelegramObject): + """ + Represents an invite link for a chat. + + Source: https://core.telegram.org/bots/api#chatinvitelink + """ + + invite_link: str + """The invite link. If the link was created by another chat administrator, then the second part of the link will be replaced with '…'.""" + creator: User + """Creator of the link""" + is_primary: bool + """True, if the link is primary""" + is_revoked: bool + """True, if the link is revoked""" + expire_date: Optional[int] = None + """*Optional*. Point in time (Unix timestamp) when the link will expire or has been expired""" + member_limit: Optional[int] = None + """*Optional*. Maximum number of users that can be members of the chat simultaneously after joining the chat via this invite link; 1-99999""" diff --git a/aiogram/types/chat_member.py b/aiogram/types/chat_member.py index aa1809aa..4a1abc8b 100644 --- a/aiogram/types/chat_member.py +++ b/aiogram/types/chat_member.py @@ -28,12 +28,16 @@ class ChatMember(TelegramObject): """*Optional*. Owner and administrators only. True, if the user's presence in the chat is hidden""" can_be_edited: Optional[bool] = None """*Optional*. Administrators only. True, if the bot is allowed to edit administrator privileges of that user""" + can_manage_chat: Optional[bool] = None + """*Optional*. Administrators only. True, if the administrator can access the chat event log, chat statistics, message statistics in channels, see channel members, see anonymous administrators in supergroups and ignore slow mode. Implied by any other administrator privilege""" can_post_messages: Optional[bool] = None """*Optional*. Administrators only. True, if the administrator can post in the channel; channels only""" can_edit_messages: Optional[bool] = None """*Optional*. Administrators only. True, if the administrator can edit messages of other users and can pin messages; channels only""" can_delete_messages: Optional[bool] = None """*Optional*. Administrators only. True, if the administrator can delete messages of other users""" + can_manage_voice_chats: Optional[bool] = None + """*Optional*. Administrators only. True, if the administrator can manage voice chats""" can_restrict_members: Optional[bool] = None """*Optional*. Administrators only. True, if the administrator can restrict, ban or unban chat members""" can_promote_members: Optional[bool] = None @@ -58,7 +62,6 @@ class ChatMember(TelegramObject): """*Optional*. Restricted only. True, if the user is allowed to add web page previews to their messages""" until_date: Optional[Union[datetime.datetime, datetime.timedelta, int]] = None """*Optional*. Restricted and kicked only. Date when restrictions will be lifted for this user; unix time""" - """Restricted and kicked only. Date when restrictions will be lifted for this user; unix time""" @property def is_chat_admin(self) -> bool: diff --git a/aiogram/types/chat_member_updated.py b/aiogram/types/chat_member_updated.py new file mode 100644 index 00000000..e14a9e88 --- /dev/null +++ b/aiogram/types/chat_member_updated.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import datetime +from typing import TYPE_CHECKING, Optional + +from pydantic import Field + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + from .chat import Chat + from .chat_invite_link import ChatInviteLink + from .chat_member import ChatMember + from .user import User + + +class ChatMemberUpdated(TelegramObject): + """ + This object represents changes in the status of a chat member. + + Source: https://core.telegram.org/bots/api#chatmemberupdated + """ + + chat: Chat + """Chat the user belongs to""" + from_user: User = Field(..., alias="from") + """Performer of the action, which resulted in the change""" + date: datetime.datetime + """Date the change was done in Unix time""" + old_chat_member: ChatMember + """Previous information about the chat member""" + new_chat_member: ChatMember + """New information about the chat member""" + invite_link: Optional[ChatInviteLink] = None + """*Optional*. Chat invite link, which was used by the user to join the chat; for joining by invite link events only.""" diff --git a/aiogram/types/contact.py b/aiogram/types/contact.py index 951a5b8f..732b770d 100644 --- a/aiogram/types/contact.py +++ b/aiogram/types/contact.py @@ -19,6 +19,6 @@ class Contact(TelegramObject): last_name: Optional[str] = None """*Optional*. Contact's last name""" user_id: Optional[int] = None - """*Optional*. Contact's user identifier in Telegram""" + """*Optional*. Contact's user identifier in Telegram. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier.""" vcard: Optional[str] = None """*Optional*. Additional data about the contact in the form of a `vCard `_""" diff --git a/aiogram/types/dice.py b/aiogram/types/dice.py index cc5720d8..00356457 100644 --- a/aiogram/types/dice.py +++ b/aiogram/types/dice.py @@ -13,7 +13,7 @@ class Dice(TelegramObject): emoji: str """Emoji on which the dice throw animation is based""" value: int - """Value of the dice, 1-6 for '🎲' and '🎯' base emoji, 1-5 for '🏀' and '⚽' base emoji, 1-64 for '🎰' base emoji""" + """Value of the dice, 1-6 for '🎲', '🎯' and '🎳' base emoji, 1-5 for '🏀' and '⚽' base emoji, 1-64 for '🎰' base emoji""" class DiceEmoji: @@ -22,3 +22,4 @@ class DiceEmoji: BASKETBALL = "🏀" FOOTBALL = "⚽" SLOT_MACHINE = "🎰" + BOWLING = "🎳" diff --git a/aiogram/types/inline_query.py b/aiogram/types/inline_query.py index 1389181b..60bb67d7 100644 --- a/aiogram/types/inline_query.py +++ b/aiogram/types/inline_query.py @@ -28,6 +28,8 @@ class InlineQuery(TelegramObject): """Text of the query (up to 256 characters)""" offset: str """Offset of the results to be returned, can be controlled by the bot""" + chat_type: Optional[str] = None + """*Optional*. Type of the chat, from which the inline query was sent. Can be either 'sender' for a private chat with the inline query sender, 'private', 'group', 'supergroup', or 'channel'. The chat type should be always known for requests sent from official clients and most third-party clients, unless the request was sent from a secret chat""" location: Optional[Location] = None """*Optional*. Sender location, only for bots that request user location""" diff --git a/aiogram/types/inline_query_result.py b/aiogram/types/inline_query_result.py index a8a66403..b615aa2b 100644 --- a/aiogram/types/inline_query_result.py +++ b/aiogram/types/inline_query_result.py @@ -28,5 +28,7 @@ class InlineQueryResult(MutableTelegramObject): - :class:`aiogram.types.inline_query_result_video.InlineQueryResultVideo` - :class:`aiogram.types.inline_query_result_voice.InlineQueryResultVoice` + **Note:** All URLs passed in inline query results will be available to end users and therefore must be assumed to be **public**. + Source: https://core.telegram.org/bots/api#inlinequeryresult """ diff --git a/aiogram/types/input_invoice_message_content.py b/aiogram/types/input_invoice_message_content.py new file mode 100644 index 00000000..b001bfdf --- /dev/null +++ b/aiogram/types/input_invoice_message_content.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, List, Optional + +from .input_message_content import InputMessageContent + +if TYPE_CHECKING: # pragma: no cover + from .labeled_price import LabeledPrice + + +class InputInvoiceMessageContent(InputMessageContent): + """ + Represents the `content `_ of an invoice message to be sent as the result of an inline query. + + Source: https://core.telegram.org/bots/api#inputinvoicemessagecontent + """ + + title: str + """Product name, 1-32 characters""" + description: str + """Product description, 1-255 characters""" + payload: str + """Bot-defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.""" + provider_token: str + """Payment provider token, obtained via `Botfather `_""" + currency: str + """Three-letter ISO 4217 currency code, see `more on currencies `_""" + prices: List[LabeledPrice] + """Price breakdown, a JSON-serialized list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.)""" + max_tip_amount: Optional[int] = None + """*Optional*. The maximum accepted amount for tips in the *smallest units* of the currency (integer, **not** float/double). For example, for a maximum tip of :code:`US$ 1.45` pass :code:`max_tip_amount = 145`. See the *exp* parameter in `currencies.json `_, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0""" + suggested_tip_amounts: Optional[List[int]] = None + """*Optional*. A JSON-serialized array of suggested amounts of tip in the *smallest units* of the currency (integer, **not** float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed *max_tip_amount*.""" + provider_data: Optional[str] = None + """*Optional*. A JSON-serialized object for data about the invoice, which will be shared with the payment provider. A detailed description of the required fields should be provided by the payment provider.""" + photo_url: Optional[str] = None + """*Optional*. URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for.""" + photo_size: Optional[int] = None + """*Optional*. Photo size""" + photo_width: Optional[int] = None + """*Optional*. Photo width""" + photo_height: Optional[int] = None + """*Optional*. Photo height""" + need_name: Optional[bool] = None + """*Optional*. Pass :code:`True`, if you require the user's full name to complete the order""" + need_phone_number: Optional[bool] = None + """*Optional*. Pass :code:`True`, if you require the user's phone number to complete the order""" + need_email: Optional[bool] = None + """*Optional*. Pass :code:`True`, if you require the user's email address to complete the order""" + need_shipping_address: Optional[bool] = None + """*Optional*. Pass :code:`True`, if you require the user's shipping address to complete the order""" + send_phone_number_to_provider: Optional[bool] = None + """*Optional*. Pass :code:`True`, if user's phone number should be sent to provider""" + send_email_to_provider: Optional[bool] = None + """*Optional*. Pass :code:`True`, if user's email address should be sent to provider""" + is_flexible: Optional[bool] = None + """*Optional*. Pass :code:`True`, if the final price depends on the shipping method""" diff --git a/aiogram/types/input_message_content.py b/aiogram/types/input_message_content.py index b763dd92..4d26d4f0 100644 --- a/aiogram/types/input_message_content.py +++ b/aiogram/types/input_message_content.py @@ -5,12 +5,13 @@ from .base import TelegramObject class InputMessageContent(TelegramObject): """ - This object represents the content of a message to be sent as a result of an inline query. Telegram clients currently support the following 4 types: + This object represents the content of a message to be sent as a result of an inline query. Telegram clients currently support the following 5 types: - :class:`aiogram.types.input_text_message_content.InputTextMessageContent` - :class:`aiogram.types.input_location_message_content.InputLocationMessageContent` - :class:`aiogram.types.input_venue_message_content.InputVenueMessageContent` - :class:`aiogram.types.input_contact_message_content.InputContactMessageContent` + - :class:`aiogram.types.input_invoice_message_content.InputInvoiceMessageContent` Source: https://core.telegram.org/bots/api#inputmessagecontent """ diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 063f0521..d476c099 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -11,6 +11,7 @@ from .base import UNSET, TelegramObject if TYPE_CHECKING: # pragma: no cover from ..methods import ( + CopyMessage, SendAnimation, SendAudio, SendContact, @@ -44,6 +45,7 @@ if TYPE_CHECKING: # pragma: no cover from .invoice import Invoice from .labeled_price import LabeledPrice from .location import Location + from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged from .message_entity import MessageEntity from .passport_data import PassportData from .photo_size import PhotoSize @@ -58,6 +60,10 @@ if TYPE_CHECKING: # pragma: no cover from .video import Video from .video_note import VideoNote from .voice import Voice + from .voice_chat_ended import VoiceChatEnded + from .voice_chat_participants_invited import VoiceChatParticipantsInvited + from .voice_chat_scheduled import VoiceChatScheduled + from .voice_chat_started import VoiceChatStarted class Message(TelegramObject): @@ -151,10 +157,12 @@ class Message(TelegramObject): """*Optional*. Service message: the supergroup has been created. This field can't be received in a message coming through updates, because bot can't be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to a very first message in a directly created supergroup.""" channel_chat_created: Optional[bool] = None """*Optional*. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can't be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel.""" + message_auto_delete_timer_changed: Optional[MessageAutoDeleteTimerChanged] = None + """*Optional*. Service message: auto-delete timer settings changed in the chat""" migrate_to_chat_id: Optional[int] = None - """*Optional*. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.""" + """*Optional*. The group has been migrated to a supergroup with the specified identifier. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this identifier.""" migrate_from_chat_id: Optional[int] = None - """*Optional*. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.""" + """*Optional*. The supergroup has been migrated from a group with the specified identifier. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this identifier.""" pinned_message: Optional[Message] = None """*Optional*. Specified message was pinned. Note that the Message object in this field will not contain further *reply_to_message* fields even if it is itself a reply.""" invoice: Optional[Invoice] = None @@ -167,6 +175,14 @@ class Message(TelegramObject): """*Optional*. Telegram Passport data""" proximity_alert_triggered: Optional[ProximityAlertTriggered] = None """*Optional*. Service message. A user in the chat triggered another user's proximity alert while sharing Live Location.""" + voice_chat_scheduled: Optional[VoiceChatScheduled] = None + """*Optional*. Service message: voice chat scheduled""" + voice_chat_started: Optional[VoiceChatStarted] = None + """*Optional*. Service message: voice chat started""" + voice_chat_ended: Optional[VoiceChatEnded] = None + """*Optional*. Service message: voice chat ended""" + voice_chat_participants_invited: Optional[VoiceChatParticipantsInvited] = None + """*Optional*. Service message: new participants invited to a voice chat""" reply_markup: Optional[InlineKeyboardMarkup] = None """*Optional*. Inline keyboard attached to the message. :code:`login_url` buttons are represented as ordinary :code:`url` buttons.""" @@ -228,6 +244,14 @@ class Message(TelegramObject): return ContentType.POLL if self.dice: return ContentType.DICE + if self.message_auto_delete_timer_changed: + return ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED + if self.voice_chat_started: + return ContentType.VOICE_CHAT_STARTED + if self.voice_chat_ended: + return ContentType.VOICE_CHAT_ENDED + if self.voice_chat_participants_invited: + return ContentType.VOICE_CHAT_PARTICIPANTS_INVITED return ContentType.UNKNOWN @@ -1517,6 +1541,179 @@ class Message(TelegramObject): reply_markup=reply_markup, ) + def send_copy( + self: Message, + chat_id: Union[str, int], + disable_notification: Optional[bool] = None, + reply_to_message_id: Optional[int] = None, + reply_markup: Union[InlineKeyboardMarkup, ReplyKeyboardMarkup, None] = None, + ) -> Union[ + SendAnimation, + SendAudio, + SendContact, + SendDocument, + SendLocation, + SendMessage, + SendPhoto, + SendPoll, + SendDice, + SendSticker, + SendVenue, + SendVideo, + SendVideoNote, + SendVoice, + ]: + """ + Send copy of message. + + Is similar to :meth:`aiogram.client.bot.Bot.copy_message` + but returning the sent message instead of :class:`aiogram.types.message_id.MessageId` + + .. note:: + + This method don't use the API method named `copyMessage` and + historically implemented before the similar method is added to API + + :param chat_id: + :param disable_notification: + :param reply_to_message_id: + :param reply_markup: + :return: + """ + from ..methods import ( + SendAnimation, + SendAudio, + SendContact, + SendDice, + SendDocument, + SendLocation, + SendMessage, + SendPhoto, + SendPoll, + SendSticker, + SendVenue, + SendVideo, + SendVideoNote, + SendVoice, + ) + + kwargs = { + "chat_id": chat_id, + "reply_markup": reply_markup or self.reply_markup, + "disable_notification": disable_notification, + "reply_to_message_id": reply_to_message_id, + } + text = self.text or self.caption + entities = self.entities or self.caption_entities + + if self.text: + return SendMessage(text=text, entities=entities, **kwargs) + elif self.audio: + return SendAudio( + audio=self.audio.file_id, + caption=text, + title=self.audio.title, + performer=self.audio.performer, + duration=self.audio.duration, + caption_entities=entities, + **kwargs, + ) + elif self.animation: + return SendAnimation( + animation=self.animation.file_id, caption=text, caption_entities=entities, **kwargs + ) + elif self.document: + return SendDocument( + document=self.document.file_id, caption=text, caption_entities=entities, **kwargs + ) + elif self.photo: + return SendPhoto( + photo=self.photo[-1].file_id, caption=text, caption_entities=entities, **kwargs + ) + elif self.sticker: + return SendSticker(sticker=self.sticker.file_id, **kwargs) + elif self.video: + return SendVideo( + video=self.video.file_id, caption=text, caption_entities=entities, **kwargs + ) + elif self.video_note: + return SendVideoNote(video_note=self.video_note.file_id, **kwargs) + elif self.voice: + return SendVoice(voice=self.voice.file_id, **kwargs) + elif self.contact: + return SendContact( + phone_number=self.contact.phone_number, + first_name=self.contact.first_name, + last_name=self.contact.last_name, + vcard=self.contact.vcard, + **kwargs, + ) + elif self.venue: + return SendVenue( + latitude=self.venue.location.latitude, + longitude=self.venue.location.longitude, + title=self.venue.title, + address=self.venue.address, + foursquare_id=self.venue.foursquare_id, + foursquare_type=self.venue.foursquare_type, + **kwargs, + ) + elif self.location: + return SendLocation( + latitude=self.location.latitude, longitude=self.location.longitude, **kwargs + ) + elif self.poll: + return SendPoll( + question=self.poll.question, + options=[option.text for option in self.poll.options], + **kwargs, + ) + elif self.dice: # Dice value can't be controlled + return SendDice(**kwargs) + else: + raise TypeError("This type of message can't be copied.") + + def copy_to( + self, + chat_id: Union[int, str], + caption: Optional[str] = None, + parse_mode: Optional[str] = None, + caption_entities: Optional[List[MessageEntity]] = None, + disable_notification: Optional[bool] = None, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: Optional[bool] = None, + reply_markup: Optional[ + Union[InlineKeyboardMarkup, ReplyKeyboardMarkup, ReplyKeyboardRemove, ForceReply] + ] = None, + ) -> CopyMessage: + """ + Copy message + + :param chat_id: + :param caption: + :param parse_mode: + :param caption_entities: + :param disable_notification: + :param reply_to_message_id: + :param allow_sending_without_reply: + :param reply_markup: + :return: + """ + from ..methods import CopyMessage + + return CopyMessage( + chat_id=chat_id, + from_chat_id=self.chat.id, + message_id=self.message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + ) + class ContentType(helper.Helper): mode = helper.HelperMode.snake_case @@ -1549,6 +1746,10 @@ class ContentType(helper.Helper): PASSPORT_DATA = helper.Item() # passport_data POLL = helper.Item() # poll DICE = helper.Item() # dice + MESSAGE_AUTO_DELETE_TIMER_CHANGED = helper.Item() # message_auto_delete_timer_changed + VOICE_CHAT_STARTED = helper.Item() # voice_chat_started + VOICE_CHAT_ENDED = helper.Item() # voice_chat_ended + VOICE_CHAT_PARTICIPANTS_INVITED = helper.Item() # voice_chat_participants_invited UNKNOWN = helper.Item() # unknown ANY = helper.Item() # any diff --git a/aiogram/types/message_auto_delete_timer_changed.py b/aiogram/types/message_auto_delete_timer_changed.py new file mode 100644 index 00000000..ab62baab --- /dev/null +++ b/aiogram/types/message_auto_delete_timer_changed.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + pass + + +class MessageAutoDeleteTimerChanged(TelegramObject): + """ + This object represents a service message about a change in auto-delete timer settings. + + Source: https://core.telegram.org/bots/api#messageautodeletetimerchanged + """ + + message_auto_delete_time: int + """New auto-delete time for messages in the chat""" diff --git a/aiogram/types/message_entity.py b/aiogram/types/message_entity.py index c0324656..2fb6623a 100644 --- a/aiogram/types/message_entity.py +++ b/aiogram/types/message_entity.py @@ -1,7 +1,9 @@ from __future__ import annotations +import warnings from typing import TYPE_CHECKING, Optional +from ..utils.text_decorations import add_surrogates, remove_surrogates from .base import MutableTelegramObject if TYPE_CHECKING: # pragma: no cover @@ -27,3 +29,16 @@ class MessageEntity(MutableTelegramObject): """*Optional*. For 'text_mention' only, the mentioned user""" language: Optional[str] = None """*Optional*. For 'pre' only, the programming language of the entity text""" + + def extract(self, text: str) -> str: + return remove_surrogates( + add_surrogates(text)[self.offset * 2 : (self.offset + self.length) * 2] + ) + + def get_text(self, text: str) -> str: + warnings.warn( + "Method `MessageEntity.get_text(...)` deprecated and will be removed in 3.2.\n" + " Use `MessageEntity.extract(...)` instead.", + DeprecationWarning, + ) + return self.extract(text=text) diff --git a/aiogram/types/response_parameters.py b/aiogram/types/response_parameters.py index 8bfb3cf5..5c722c9e 100644 --- a/aiogram/types/response_parameters.py +++ b/aiogram/types/response_parameters.py @@ -13,6 +13,6 @@ class ResponseParameters(TelegramObject): """ migrate_to_chat_id: Optional[int] = None - """*Optional*. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.""" + """*Optional*. The group has been migrated to a supergroup with the specified identifier. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this identifier.""" retry_after: Optional[int] = None """*Optional*. In case of exceeding flood control, the number of seconds left to wait before the request can be repeated""" diff --git a/aiogram/types/update.py b/aiogram/types/update.py index 625fce4a..3e43a316 100644 --- a/aiogram/types/update.py +++ b/aiogram/types/update.py @@ -6,6 +6,7 @@ from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover from .callback_query import CallbackQuery + from .chat_member_updated import ChatMemberUpdated from .chosen_inline_result import ChosenInlineResult from .inline_query import InlineQuery from .message import Message @@ -48,3 +49,7 @@ class Update(TelegramObject): """*Optional*. New poll state. Bots receive only updates about stopped polls and polls, which are sent by the bot""" poll_answer: Optional[PollAnswer] = None """*Optional*. A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls that were sent by the bot itself.""" + my_chat_member: Optional[ChatMemberUpdated] = None + """*Optional*. The bot's chat member status was updated in a chat. For private chats, this update is received only when the bot is blocked or unblocked by the user.""" + chat_member: Optional[ChatMemberUpdated] = None + """*Optional*. A chat member's status was updated in a chat. The bot must be an administrator in the chat and must explicitly specify 'chat_member' in the list of *allowed_updates* to receive these updates.""" diff --git a/aiogram/types/user.py b/aiogram/types/user.py index 7f687e17..4d65ce71 100644 --- a/aiogram/types/user.py +++ b/aiogram/types/user.py @@ -13,7 +13,7 @@ class User(TelegramObject): """ id: int - """Unique identifier for this user or bot""" + """Unique identifier for this user or bot. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier.""" is_bot: bool """True, if this user is a bot""" first_name: str diff --git a/aiogram/types/voice_chat_ended.py b/aiogram/types/voice_chat_ended.py new file mode 100644 index 00000000..cd8290d8 --- /dev/null +++ b/aiogram/types/voice_chat_ended.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + pass + + +class VoiceChatEnded(TelegramObject): + """ + This object represents a service message about a voice chat ended in the chat. + + Source: https://core.telegram.org/bots/api#voicechatended + """ + + duration: int + """Voice chat duration; in seconds""" diff --git a/aiogram/types/voice_chat_participants_invited.py b/aiogram/types/voice_chat_participants_invited.py new file mode 100644 index 00000000..191b414f --- /dev/null +++ b/aiogram/types/voice_chat_participants_invited.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, List, Optional + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + from .user import User + + +class VoiceChatParticipantsInvited(TelegramObject): + """ + This object represents a service message about new members invited to a voice chat. + + Source: https://core.telegram.org/bots/api#voicechatparticipantsinvited + """ + + users: Optional[List[User]] = None + """*Optional*. New members that were invited to the voice chat""" diff --git a/aiogram/types/voice_chat_scheduled.py b/aiogram/types/voice_chat_scheduled.py new file mode 100644 index 00000000..8aa8eb97 --- /dev/null +++ b/aiogram/types/voice_chat_scheduled.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + pass + + +class VoiceChatScheduled(TelegramObject): + """ + This object represents a service message about a voice chat scheduled in the chat. + + Source: https://core.telegram.org/bots/api#voicechatscheduled + """ + + start_date: int + """Point in time (Unix timestamp) when the voice chat is supposed to be started by a chat administrator""" diff --git a/aiogram/types/voice_chat_started.py b/aiogram/types/voice_chat_started.py new file mode 100644 index 00000000..68b72cf3 --- /dev/null +++ b/aiogram/types/voice_chat_started.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + pass + + +class VoiceChatStarted(TelegramObject): + """ + This object represents a service message about a voice chat started in the chat. Currently holds no information. + + Source: https://core.telegram.org/bots/api#voicechatstarted + """ diff --git a/aiogram/types/webhook_info.py b/aiogram/types/webhook_info.py index 24a9844e..b6f4747d 100644 --- a/aiogram/types/webhook_info.py +++ b/aiogram/types/webhook_info.py @@ -27,4 +27,4 @@ class WebhookInfo(TelegramObject): max_connections: Optional[int] = None """*Optional*. Maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery""" allowed_updates: Optional[List[str]] = None - """*Optional*. A list of update types the bot is subscribed to. Defaults to all update types""" + """*Optional*. A list of update types the bot is subscribed to. Defaults to all update types except *chat_member*""" diff --git a/aiogram/utils/help/__init__.py b/aiogram/utils/help/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aiogram/utils/help/engine.py b/aiogram/utils/help/engine.py new file mode 100644 index 00000000..c91c8899 --- /dev/null +++ b/aiogram/utils/help/engine.py @@ -0,0 +1,48 @@ +from abc import ABC, abstractmethod +from collections import Generator +from typing import Dict, List + +from aiogram.utils.help.record import CommandRecord + + +class BaseHelpBackend(ABC): + @abstractmethod + def add(self, record: CommandRecord) -> None: + pass + + @abstractmethod + def search(self, value: str) -> CommandRecord: + pass + + @abstractmethod + def all(self) -> Generator[CommandRecord, None, None]: + pass + + def __getitem__(self, item: str) -> CommandRecord: + return self.search(item) + + def __iter__(self) -> Generator[CommandRecord, None, None]: + return self.all() + + +class MappingBackend(BaseHelpBackend): + def __init__(self, search_empty_prefix: bool = True) -> None: + self._records: List[CommandRecord] = [] + self._mapping: Dict[str, CommandRecord] = {} + self.search_empty_prefix = search_empty_prefix + + def search(self, value: str) -> CommandRecord: + return self._mapping[value] + + def add(self, record: CommandRecord) -> None: + new_records = {} + for key in record.as_keys(with_empty_prefix=self.search_empty_prefix): + if key in self._mapping: + raise ValueError(f"Key '{key}' is already indexed") + new_records[key] = record + self._mapping.update(new_records) + self._records.append(record) + self._records.sort(key=lambda rec: (rec.priority, rec.commands[0])) + + def all(self) -> Generator[CommandRecord, None, None]: + yield from self._records diff --git a/aiogram/utils/help/manager.py b/aiogram/utils/help/manager.py new file mode 100644 index 00000000..b9aefb0e --- /dev/null +++ b/aiogram/utils/help/manager.py @@ -0,0 +1,113 @@ +from typing import Any, Optional, Tuple + +from aiogram import Bot, Router +from aiogram.dispatcher.filters import Command, CommandObject +from aiogram.types import BotCommand, Message +from aiogram.utils.help.engine import BaseHelpBackend, MappingBackend +from aiogram.utils.help.record import DEFAULT_PREFIXES, CommandRecord +from aiogram.utils.help.render import BaseHelpRenderer, SimpleRenderer + + +class HelpManager: + def __init__( + self, + backend: Optional[BaseHelpBackend] = None, + renderer: Optional[BaseHelpRenderer] = None, + ) -> None: + if backend is None: + backend = MappingBackend() + if renderer is None: + renderer = SimpleRenderer() + self._backend = backend + self._renderer = renderer + + def add( + self, + *commands: str, + help: str, + description: Optional[str] = None, + prefix: str = DEFAULT_PREFIXES, + ignore_case: bool = False, + ignore_mention: bool = False, + priority: int = 0, + ) -> CommandRecord: + record = CommandRecord( + commands=commands, + help=help, + description=description, + prefix=prefix, + ignore_case=ignore_case, + ignore_mention=ignore_mention, + priority=priority, + ) + self._backend.add(record) + return record + + def command( + self, + *commands: str, + help: str, + description: Optional[str] = None, + prefix: str = DEFAULT_PREFIXES, + ignore_case: bool = False, + ignore_mention: bool = False, + priority: int = 0, + ) -> Command: + record = self.add( + *commands, + help=help, + description=description, + prefix=prefix, + ignore_case=ignore_case, + ignore_mention=ignore_mention, + priority=priority, + ) + return record.as_filter() + + def mount_help( + self, + router: Router, + *commands: str, + prefix: str = "/", + help: str = "Help", + description: str = "Show help for the commands\n" + "Also you can use '/help command' for get help for specific command", + as_reply: bool = True, + filters: Tuple[Any, ...] = (), + **kw_filters: Any, + ) -> Any: + if not commands: + commands = ("help",) + help_filter = self.command(*commands, prefix=prefix, help=help, description=description) + + async def handle(message: Message, command: CommandObject, **kwargs: Any) -> Any: + return await self._handle_help( + message=message, command=command, as_reply=as_reply, **kwargs + ) + + return router.message.register(handle, help_filter, *filters, **kw_filters) + + async def _handle_help( + self, + message: Message, + bot: Bot, + command: CommandObject, + as_reply: bool = True, + **kwargs: Any, + ) -> Any: + lines = self._renderer.render(backend=self._backend, command=command, **kwargs) + text = "\n".join(line or "" for line in lines) + return await bot.send_message( + chat_id=message.chat.id, + text=text, + reply_to_message_id=message.message_id if as_reply else None, + ) + + async def set_bot_commands(self, bot: Bot) -> bool: + return await bot.set_my_commands( + commands=[ + BotCommand(command=record.commands[0], description=record.help) + for record in self._backend + if "/" in record.prefix + ] + ) diff --git a/aiogram/utils/help/record.py b/aiogram/utils/help/record.py new file mode 100644 index 00000000..beb00468 --- /dev/null +++ b/aiogram/utils/help/record.py @@ -0,0 +1,33 @@ +from dataclasses import dataclass +from itertools import product +from typing import Generator, Optional, Sequence + +from aiogram.dispatcher.filters import Command + +DEFAULT_PREFIXES = "/" + + +@dataclass +class CommandRecord: + commands: Sequence[str] + help: str + description: Optional[str] = None + prefix: str = DEFAULT_PREFIXES + ignore_case: bool = False + ignore_mention: bool = False + priority: int = 0 + + def as_filter(self) -> Command: + return Command(commands=self.commands, commands_prefix=self.prefix) + + def as_keys(self, with_empty_prefix: bool = False) -> Generator[str, None, None]: + for command in self.commands: + yield command + for prefix in self.prefix: + yield f"{prefix}{command}" + + def as_command(self) -> str: + return f"{self.prefix[0]}{self.commands[0]}" + + def as_aliases(self) -> str: + return ", ".join(f"{p}{c}" for c, p in product(self.commands, self.prefix)) diff --git a/aiogram/utils/help/render.py b/aiogram/utils/help/render.py new file mode 100644 index 00000000..8b15d0af --- /dev/null +++ b/aiogram/utils/help/render.py @@ -0,0 +1,64 @@ +from abc import ABC, abstractmethod +from typing import Any, Generator, Optional + +from aiogram.dispatcher.filters import CommandObject +from aiogram.utils.help.engine import BaseHelpBackend + + +class BaseHelpRenderer(ABC): + @abstractmethod + def render( + self, backend: BaseHelpBackend, command: CommandObject, **kwargs: Any + ) -> Generator[Optional[str], None, None]: + pass + + +class SimpleRenderer(BaseHelpRenderer): + def __init__( + self, + help_title: str = "Commands list:", + help_footer: str = "", + aliases_line: str = "Aliases", + command_title: str = "Help for command:", + unknown_command: str = "Command not found", + ): + self.help_title = help_title + self.help_footer = help_footer + self.aliases_line = aliases_line + self.command_title = command_title + self.unknown_command = unknown_command + + def render_help(self, backend: BaseHelpBackend) -> Generator[Optional[str], None, None]: + yield self.help_title + + for command in backend: + yield f"{command.prefix[0]}{command.commands[0]} - {command.help}" + + if self.help_footer: + yield None + yield self.help_footer + + def render_command_help( + self, backend: BaseHelpBackend, target: str + ) -> Generator[Optional[str], None, None]: + try: + record = backend[target] + except KeyError: + yield f"{self.command_title} {target}" + yield self.unknown_command + return + + yield f"{self.command_title} {record.as_command()}" + if len(record.commands) > 1 or len(record.prefix) > 1: + yield f"{self.aliases_line}: {record.as_aliases()}" + yield record.help + yield None + yield record.description + + def render( + self, backend: BaseHelpBackend, command: CommandObject, **kwargs: Any + ) -> Generator[Optional[str], None, None]: + if command.args: + yield from self.render_command_help(backend=backend, target=command.args) + else: + yield from self.render_help(backend=backend) diff --git a/aiogram/utils/markup.py b/aiogram/utils/markup.py new file mode 100644 index 00000000..32169104 --- /dev/null +++ b/aiogram/utils/markup.py @@ -0,0 +1,224 @@ +from itertools import chain +from itertools import cycle as repeat_all +from typing import Any, Generator, Generic, Iterable, List, Optional, Type, TypeVar + +from aiogram.types import InlineKeyboardButton, KeyboardButton + +ButtonType = TypeVar("ButtonType", InlineKeyboardButton, KeyboardButton) +T = TypeVar("T") +MAX_WIDTH = 8 +MIN_WIDTH = 1 +MAX_BUTTONS = 100 + + +class MarkupConstructor(Generic[ButtonType]): + def __init__( + self, button_type: Type[ButtonType], markup: Optional[List[List[ButtonType]]] = None + ) -> None: + if not issubclass(button_type, (InlineKeyboardButton, KeyboardButton)): + raise ValueError(f"Button type {button_type} are not allowed here") + self._button_type: Type[ButtonType] = button_type + if markup: + self._validate_markup(markup) + else: + markup = [] + self._markup: List[List[ButtonType]] = markup + + @property + def buttons(self) -> Generator[ButtonType, None, None]: + """ + Get flatten set of all buttons + + :return: + """ + yield from chain.from_iterable(self.export()) + + def _validate_button(self, button: ButtonType) -> bool: + """ + Check that button item has correct type + + :param button: + :return: + """ + allowed = self._button_type + if not isinstance(button, allowed): + raise ValueError( + f"{button!r} should be type {allowed.__name__!r} not {type(button).__name__!r}" + ) + return True + + def _validate_buttons(self, *buttons: ButtonType) -> bool: + """ + Check that all passed button has correct type + + :param buttons: + :return: + """ + return all(map(self._validate_button, buttons)) + + def _validate_row(self, row: List[ButtonType]) -> bool: + """ + Check that row of buttons are correct + Row can be only list of allowed button types and has length 0 <= n <= 8 + + :param row: + :return: + """ + if not isinstance(row, list): + raise ValueError( + f"Row {row!r} should be type 'List[{self._button_type.__name__}]' not type {type(row).__name__}" + ) + if len(row) > MAX_WIDTH: + raise ValueError(f"Row {row!r} is too long (MAX_WIDTH={MAX_WIDTH})") + self._validate_buttons(*row) + return True + + def _validate_markup(self, markup: List[List[ButtonType]]) -> bool: + """ + Check that passed markup has correct data structure + Markup is list of lists of buttons + + :param markup: + :return: + """ + count = 0 + if not isinstance(markup, list): + raise ValueError( + f"Markup should be type 'List[List[{self._button_type.__name__}]]' not type {type(markup).__name__!r}" + ) + for row in markup: + self._validate_row(row) + count += len(row) + if count > MAX_BUTTONS: + raise ValueError(f"Too much buttons detected Max allowed count - {MAX_BUTTONS}") + return True + + def _validate_size(self, size: Any) -> int: + """ + Validate that passed size is legit + + :param size: + :return: + """ + if not isinstance(size, int): + raise ValueError("Only int sizes are allowed") + if size not in range(MIN_WIDTH, MAX_WIDTH + 1): + raise ValueError(f"Row size {size} are not allowed") + return size + + def copy(self: "MarkupConstructor[ButtonType]") -> "MarkupConstructor[ButtonType]": + """ + Make full copy of current constructor with markup + + :return: + """ + return self.__class__(self._button_type, markup=self.export()) + + def export(self) -> List[List[ButtonType]]: + """ + Export configured markup as list of lists of buttons + + .. code-block:: python + + >>> constructor = MarkupConstructor(button_type=InlineKeyboardButton) + >>> ... # Add buttons to constructor + >>> markup = InlineKeyboardMarkup(inline_keyboard=constructor.export()) + + :return: + """ + return self._markup.copy() + + def add(self, *buttons: ButtonType) -> "MarkupConstructor[ButtonType]": + """ + Add one or many buttons to markup. + + :param buttons: + :return: + """ + self._validate_buttons(*buttons) + markup = self.export() + + # Try to add new buttons to the end of last row if it possible + if markup and len(markup[-1]) < MAX_WIDTH: + last_row = markup[-1] + pos = MAX_WIDTH - len(last_row) + head, buttons = buttons[:pos], buttons[pos:] + last_row.extend(head) + + # Separate buttons to exclusive rows with max possible row width + while buttons: + row, buttons = buttons[:MAX_WIDTH], buttons[MAX_WIDTH:] + markup.append(list(row)) + + self._markup = markup + return self + + def row(self, *buttons: ButtonType, width: int = MAX_WIDTH) -> "MarkupConstructor[ButtonType]": + """ + Add row to markup + + When too much buttons is passed it will be separated to many rows + + :param buttons: + :param width: + :return: + """ + self._validate_size(width) + self._validate_buttons(*buttons) + self._markup.extend( + list(buttons[pos : pos + width]) for pos in range(0, len(buttons), width) + ) + return self + + def adjust(self, *sizes: int, repeat: bool = False) -> "MarkupConstructor[ButtonType]": + """ + Adjust previously added buttons to specific row sizes. + + By default when the sum of passed sizes is lower than buttons count the last + one size will be used for tail of the markup. + If repeat=True is passed - all sizes will be cycled when available more buttons count than all sizes + + :param sizes: + :param repeat: + :return: + """ + if not sizes: + sizes = (MAX_WIDTH,) + + validated_sizes = map(self._validate_size, sizes) + sizes_iter = repeat_all(validated_sizes) if repeat else repeat_last(validated_sizes) + size = next(sizes_iter) + + markup = [] + row: List[ButtonType] = [] + for button in self.buttons: + if len(row) >= size: + markup.append(row) + size = next(sizes_iter) + row = [] + row.append(button) + if row: + markup.append(row) + self._markup = markup + return self + + def button(self, **kwargs: Any) -> "MarkupConstructor[ButtonType]": + button = self._button_type(**kwargs) + return self.add(button) + + +def repeat_last(items: Iterable[T]) -> Generator[T, None, None]: + items_iter = iter(items) + try: + value = next(items_iter) + except StopIteration: + return + yield value + finished = False + while True: + if not finished: + try: + value = next(items_iter) + except StopIteration: + finished = True + yield value diff --git a/aiogram/utils/text_decorations.py b/aiogram/utils/text_decorations.py index 6377223b..a41e481f 100644 --- a/aiogram/utils/text_decorations.py +++ b/aiogram/utils/text_decorations.py @@ -17,6 +17,14 @@ __all__ = ( ) +def add_surrogates(text: str) -> bytes: + return text.encode("utf-16-le") + + +def remove_surrogates(text: bytes) -> str: + return text.decode("utf-16-le") + + class TextDecoration(ABC): def apply_entity(self, entity: MessageEntity, text: str) -> str: """ @@ -57,7 +65,7 @@ class TextDecoration(ABC): """ result = "".join( self._unparse_entities( - self._add_surrogates(text), + add_surrogates(text), sorted(entities, key=lambda item: item.offset) if entities else [], ) ) @@ -78,7 +86,7 @@ class TextDecoration(ABC): if entity.offset * 2 < offset: continue if entity.offset * 2 > offset: - yield self.quote(self._remove_surrogates(text[offset : entity.offset * 2])) + yield self.quote(remove_surrogates(text[offset : entity.offset * 2])) start = entity.offset * 2 offset = entity.offset * 2 + entity.length * 2 @@ -91,15 +99,7 @@ class TextDecoration(ABC): ) if offset < length: - yield self.quote(self._remove_surrogates(text[offset:length])) - - @staticmethod - def _add_surrogates(text: str) -> bytes: - return text.encode("utf-16-le") - - @staticmethod - def _remove_surrogates(text: bytes) -> str: - return text.decode("utf-16-le") + yield self.quote(remove_surrogates(text[offset:length])) @abstractmethod def link(self, value: str, link: str) -> str: # pragma: no cover diff --git a/docs/_api_version.md b/docs/_api_version.md index 86a9588a..a75b92f1 100644 --- a/docs/_api_version.md +++ b/docs/_api_version.md @@ -1 +1 @@ -4.9 +5.1 diff --git a/docs/_package_version.md b/docs/_package_version.md index d8cad509..d2cc0e7f 100644 --- a/docs/_package_version.md +++ b/docs/_package_version.md @@ -1 +1 @@ -3.0.0a6 +3.0.0a7 diff --git a/docs2/api/methods/add_sticker_to_set.rst b/docs2/api/methods/add_sticker_to_set.rst index 32cec35c..68d1cbc6 100644 --- a/docs2/api/methods/add_sticker_to_set.rst +++ b/docs2/api/methods/add_sticker_to_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return AddStickerToSet(...) \ No newline at end of file + return AddStickerToSet(...) diff --git a/docs2/api/methods/answer_callback_query.rst b/docs2/api/methods/answer_callback_query.rst index f0afd844..1ffad5f5 100644 --- a/docs2/api/methods/answer_callback_query.rst +++ b/docs2/api/methods/answer_callback_query.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return AnswerCallbackQuery(...) \ No newline at end of file + return AnswerCallbackQuery(...) diff --git a/docs2/api/methods/answer_inline_query.rst b/docs2/api/methods/answer_inline_query.rst index 8998eb53..a2231c5b 100644 --- a/docs2/api/methods/answer_inline_query.rst +++ b/docs2/api/methods/answer_inline_query.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return AnswerInlineQuery(...) \ No newline at end of file + return AnswerInlineQuery(...) diff --git a/docs2/api/methods/answer_pre_checkout_query.rst b/docs2/api/methods/answer_pre_checkout_query.rst index d3e3c6f0..c332f6e6 100644 --- a/docs2/api/methods/answer_pre_checkout_query.rst +++ b/docs2/api/methods/answer_pre_checkout_query.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return AnswerPreCheckoutQuery(...) \ No newline at end of file + return AnswerPreCheckoutQuery(...) diff --git a/docs2/api/methods/answer_shipping_query.rst b/docs2/api/methods/answer_shipping_query.rst index 14689178..2b3f5212 100644 --- a/docs2/api/methods/answer_shipping_query.rst +++ b/docs2/api/methods/answer_shipping_query.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return AnswerShippingQuery(...) \ No newline at end of file + return AnswerShippingQuery(...) diff --git a/docs2/api/methods/close.rst b/docs2/api/methods/close.rst index 8daec78d..2ae15875 100644 --- a/docs2/api/methods/close.rst +++ b/docs2/api/methods/close.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return Close(...) \ No newline at end of file + return Close(...) diff --git a/docs2/api/methods/copy_message.rst b/docs2/api/methods/copy_message.rst index 44406c3a..a4f5c9b9 100644 --- a/docs2/api/methods/copy_message.rst +++ b/docs2/api/methods/copy_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return CopyMessage(...) \ No newline at end of file + return CopyMessage(...) diff --git a/docs2/api/methods/create_chat_invite_link.rst b/docs2/api/methods/create_chat_invite_link.rst new file mode 100644 index 00000000..787eded8 --- /dev/null +++ b/docs2/api/methods/create_chat_invite_link.rst @@ -0,0 +1,51 @@ +#################### +createChatInviteLink +#################### + +Returns: :obj:`ChatInviteLink` + +.. automodule:: aiogram.methods.create_chat_invite_link + :members: + :member-order: bysource + :undoc-members: True + + +Usage +===== + +As bot method +------------- + +.. code-block:: + + result: ChatInviteLink = await bot.create_chat_invite_link(...) + + +Method as object +---------------- + +Imports: + +- :code:`from aiogram.methods.create_chat_invite_link import CreateChatInviteLink` +- alias: :code:`from aiogram.methods import CreateChatInviteLink` + +In handlers with current bot +---------------------------- + +.. code-block:: python + + result: ChatInviteLink = await CreateChatInviteLink(...) + +With specific bot +~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + result: ChatInviteLink = await bot(CreateChatInviteLink(...)) + +As reply into Webhook in handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + return CreateChatInviteLink(...) diff --git a/docs2/api/methods/create_new_sticker_set.rst b/docs2/api/methods/create_new_sticker_set.rst index 230f49fe..475c1c01 100644 --- a/docs2/api/methods/create_new_sticker_set.rst +++ b/docs2/api/methods/create_new_sticker_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return CreateNewStickerSet(...) \ No newline at end of file + return CreateNewStickerSet(...) diff --git a/docs2/api/methods/delete_chat_photo.rst b/docs2/api/methods/delete_chat_photo.rst index 01280b60..637cef64 100644 --- a/docs2/api/methods/delete_chat_photo.rst +++ b/docs2/api/methods/delete_chat_photo.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return DeleteChatPhoto(...) \ No newline at end of file + return DeleteChatPhoto(...) diff --git a/docs2/api/methods/delete_chat_sticker_set.rst b/docs2/api/methods/delete_chat_sticker_set.rst index 67a9eef0..a06cc894 100644 --- a/docs2/api/methods/delete_chat_sticker_set.rst +++ b/docs2/api/methods/delete_chat_sticker_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return DeleteChatStickerSet(...) \ No newline at end of file + return DeleteChatStickerSet(...) diff --git a/docs2/api/methods/delete_message.rst b/docs2/api/methods/delete_message.rst index b97f5c41..96b721e9 100644 --- a/docs2/api/methods/delete_message.rst +++ b/docs2/api/methods/delete_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return DeleteMessage(...) \ No newline at end of file + return DeleteMessage(...) diff --git a/docs2/api/methods/delete_sticker_from_set.rst b/docs2/api/methods/delete_sticker_from_set.rst index dfb57a0a..ac491710 100644 --- a/docs2/api/methods/delete_sticker_from_set.rst +++ b/docs2/api/methods/delete_sticker_from_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return DeleteStickerFromSet(...) \ No newline at end of file + return DeleteStickerFromSet(...) diff --git a/docs2/api/methods/delete_webhook.rst b/docs2/api/methods/delete_webhook.rst index 1c7e7d6e..b1f4d02c 100644 --- a/docs2/api/methods/delete_webhook.rst +++ b/docs2/api/methods/delete_webhook.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return DeleteWebhook(...) \ No newline at end of file + return DeleteWebhook(...) diff --git a/docs2/api/methods/edit_chat_invite_link.rst b/docs2/api/methods/edit_chat_invite_link.rst new file mode 100644 index 00000000..a9702e84 --- /dev/null +++ b/docs2/api/methods/edit_chat_invite_link.rst @@ -0,0 +1,51 @@ +################## +editChatInviteLink +################## + +Returns: :obj:`ChatInviteLink` + +.. automodule:: aiogram.methods.edit_chat_invite_link + :members: + :member-order: bysource + :undoc-members: True + + +Usage +===== + +As bot method +------------- + +.. code-block:: + + result: ChatInviteLink = await bot.edit_chat_invite_link(...) + + +Method as object +---------------- + +Imports: + +- :code:`from aiogram.methods.edit_chat_invite_link import EditChatInviteLink` +- alias: :code:`from aiogram.methods import EditChatInviteLink` + +In handlers with current bot +---------------------------- + +.. code-block:: python + + result: ChatInviteLink = await EditChatInviteLink(...) + +With specific bot +~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + result: ChatInviteLink = await bot(EditChatInviteLink(...)) + +As reply into Webhook in handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + return EditChatInviteLink(...) diff --git a/docs2/api/methods/edit_message_caption.rst b/docs2/api/methods/edit_message_caption.rst index d05a83b8..fb8a001a 100644 --- a/docs2/api/methods/edit_message_caption.rst +++ b/docs2/api/methods/edit_message_caption.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return EditMessageCaption(...) \ No newline at end of file + return EditMessageCaption(...) diff --git a/docs2/api/methods/edit_message_live_location.rst b/docs2/api/methods/edit_message_live_location.rst index 5516727c..85022f03 100644 --- a/docs2/api/methods/edit_message_live_location.rst +++ b/docs2/api/methods/edit_message_live_location.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return EditMessageLiveLocation(...) \ No newline at end of file + return EditMessageLiveLocation(...) diff --git a/docs2/api/methods/edit_message_media.rst b/docs2/api/methods/edit_message_media.rst index 057d1d5c..5e77467f 100644 --- a/docs2/api/methods/edit_message_media.rst +++ b/docs2/api/methods/edit_message_media.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return EditMessageMedia(...) \ No newline at end of file + return EditMessageMedia(...) diff --git a/docs2/api/methods/edit_message_reply_markup.rst b/docs2/api/methods/edit_message_reply_markup.rst index d37d9400..34916d42 100644 --- a/docs2/api/methods/edit_message_reply_markup.rst +++ b/docs2/api/methods/edit_message_reply_markup.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return EditMessageReplyMarkup(...) \ No newline at end of file + return EditMessageReplyMarkup(...) diff --git a/docs2/api/methods/edit_message_text.rst b/docs2/api/methods/edit_message_text.rst index 55cd428c..32645b94 100644 --- a/docs2/api/methods/edit_message_text.rst +++ b/docs2/api/methods/edit_message_text.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return EditMessageText(...) \ No newline at end of file + return EditMessageText(...) diff --git a/docs2/api/methods/export_chat_invite_link.rst b/docs2/api/methods/export_chat_invite_link.rst index c2cb9c40..ea8c6fcd 100644 --- a/docs2/api/methods/export_chat_invite_link.rst +++ b/docs2/api/methods/export_chat_invite_link.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return ExportChatInviteLink(...) \ No newline at end of file + return ExportChatInviteLink(...) diff --git a/docs2/api/methods/forward_message.rst b/docs2/api/methods/forward_message.rst index b8eace3c..fcf8fd59 100644 --- a/docs2/api/methods/forward_message.rst +++ b/docs2/api/methods/forward_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return ForwardMessage(...) \ No newline at end of file + return ForwardMessage(...) diff --git a/docs2/api/methods/get_chat.rst b/docs2/api/methods/get_chat.rst index 9953c616..79124ed2 100644 --- a/docs2/api/methods/get_chat.rst +++ b/docs2/api/methods/get_chat.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: Chat = await bot(GetChat(...)) - diff --git a/docs2/api/methods/get_chat_administrators.rst b/docs2/api/methods/get_chat_administrators.rst index f5690d73..39bc46ee 100644 --- a/docs2/api/methods/get_chat_administrators.rst +++ b/docs2/api/methods/get_chat_administrators.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: List[ChatMember] = await bot(GetChatAdministrators(...)) - diff --git a/docs2/api/methods/get_chat_member.rst b/docs2/api/methods/get_chat_member.rst index 53f20f64..0fcf67d3 100644 --- a/docs2/api/methods/get_chat_member.rst +++ b/docs2/api/methods/get_chat_member.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: ChatMember = await bot(GetChatMember(...)) - diff --git a/docs2/api/methods/get_chat_members_count.rst b/docs2/api/methods/get_chat_members_count.rst index 95030cb7..6286e845 100644 --- a/docs2/api/methods/get_chat_members_count.rst +++ b/docs2/api/methods/get_chat_members_count.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: int = await bot(GetChatMembersCount(...)) - diff --git a/docs2/api/methods/get_file.rst b/docs2/api/methods/get_file.rst index dfdf4411..ee96326b 100644 --- a/docs2/api/methods/get_file.rst +++ b/docs2/api/methods/get_file.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: File = await bot(GetFile(...)) - diff --git a/docs2/api/methods/get_game_high_scores.rst b/docs2/api/methods/get_game_high_scores.rst index cb9dc562..4fb1f06e 100644 --- a/docs2/api/methods/get_game_high_scores.rst +++ b/docs2/api/methods/get_game_high_scores.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: List[GameHighScore] = await bot(GetGameHighScores(...)) - diff --git a/docs2/api/methods/get_me.rst b/docs2/api/methods/get_me.rst index b29e64db..7ae9d580 100644 --- a/docs2/api/methods/get_me.rst +++ b/docs2/api/methods/get_me.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: User = await bot(GetMe(...)) - diff --git a/docs2/api/methods/get_my_commands.rst b/docs2/api/methods/get_my_commands.rst index 13add8e9..9dba9fe6 100644 --- a/docs2/api/methods/get_my_commands.rst +++ b/docs2/api/methods/get_my_commands.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: List[BotCommand] = await bot(GetMyCommands(...)) - diff --git a/docs2/api/methods/get_sticker_set.rst b/docs2/api/methods/get_sticker_set.rst index bc3faa93..a1feb38c 100644 --- a/docs2/api/methods/get_sticker_set.rst +++ b/docs2/api/methods/get_sticker_set.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: StickerSet = await bot(GetStickerSet(...)) - diff --git a/docs2/api/methods/get_updates.rst b/docs2/api/methods/get_updates.rst index 15cae582..6ff33d31 100644 --- a/docs2/api/methods/get_updates.rst +++ b/docs2/api/methods/get_updates.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: List[Update] = await bot(GetUpdates(...)) - diff --git a/docs2/api/methods/get_user_profile_photos.rst b/docs2/api/methods/get_user_profile_photos.rst index 3b76b9c4..dab76989 100644 --- a/docs2/api/methods/get_user_profile_photos.rst +++ b/docs2/api/methods/get_user_profile_photos.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: UserProfilePhotos = await bot(GetUserProfilePhotos(...)) - diff --git a/docs2/api/methods/get_webhook_info.rst b/docs2/api/methods/get_webhook_info.rst index 88bc2a46..519e1207 100644 --- a/docs2/api/methods/get_webhook_info.rst +++ b/docs2/api/methods/get_webhook_info.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: WebhookInfo = await bot(GetWebhookInfo(...)) - diff --git a/docs2/api/methods/index.rst b/docs2/api/methods/index.rst index 728008f4..94c08366 100644 --- a/docs2/api/methods/index.rst +++ b/docs2/api/methods/index.rst @@ -55,6 +55,9 @@ Available methods set_chat_administrator_custom_title set_chat_permissions export_chat_invite_link + create_chat_invite_link + edit_chat_invite_link + revoke_chat_invite_link set_chat_photo delete_chat_photo set_chat_title @@ -136,4 +139,3 @@ Games send_game set_game_score get_game_high_scores - diff --git a/docs2/api/methods/kick_chat_member.rst b/docs2/api/methods/kick_chat_member.rst index 7cf3d70d..da73a535 100644 --- a/docs2/api/methods/kick_chat_member.rst +++ b/docs2/api/methods/kick_chat_member.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return KickChatMember(...) \ No newline at end of file + return KickChatMember(...) diff --git a/docs2/api/methods/leave_chat.rst b/docs2/api/methods/leave_chat.rst index edb603f7..a78dce7e 100644 --- a/docs2/api/methods/leave_chat.rst +++ b/docs2/api/methods/leave_chat.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return LeaveChat(...) \ No newline at end of file + return LeaveChat(...) diff --git a/docs2/api/methods/log_out.rst b/docs2/api/methods/log_out.rst index 46cc92c9..0049c3f2 100644 --- a/docs2/api/methods/log_out.rst +++ b/docs2/api/methods/log_out.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return LogOut(...) \ No newline at end of file + return LogOut(...) diff --git a/docs2/api/methods/pin_chat_message.rst b/docs2/api/methods/pin_chat_message.rst index 1c3dc9ee..717f86a1 100644 --- a/docs2/api/methods/pin_chat_message.rst +++ b/docs2/api/methods/pin_chat_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return PinChatMessage(...) \ No newline at end of file + return PinChatMessage(...) diff --git a/docs2/api/methods/promote_chat_member.rst b/docs2/api/methods/promote_chat_member.rst index ec883f59..67bf3671 100644 --- a/docs2/api/methods/promote_chat_member.rst +++ b/docs2/api/methods/promote_chat_member.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return PromoteChatMember(...) \ No newline at end of file + return PromoteChatMember(...) diff --git a/docs2/api/methods/restrict_chat_member.rst b/docs2/api/methods/restrict_chat_member.rst index 47cadd01..a93c4c92 100644 --- a/docs2/api/methods/restrict_chat_member.rst +++ b/docs2/api/methods/restrict_chat_member.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return RestrictChatMember(...) \ No newline at end of file + return RestrictChatMember(...) diff --git a/docs2/api/methods/revoke_chat_invite_link.rst b/docs2/api/methods/revoke_chat_invite_link.rst new file mode 100644 index 00000000..530133f8 --- /dev/null +++ b/docs2/api/methods/revoke_chat_invite_link.rst @@ -0,0 +1,51 @@ +#################### +revokeChatInviteLink +#################### + +Returns: :obj:`ChatInviteLink` + +.. automodule:: aiogram.methods.revoke_chat_invite_link + :members: + :member-order: bysource + :undoc-members: True + + +Usage +===== + +As bot method +------------- + +.. code-block:: + + result: ChatInviteLink = await bot.revoke_chat_invite_link(...) + + +Method as object +---------------- + +Imports: + +- :code:`from aiogram.methods.revoke_chat_invite_link import RevokeChatInviteLink` +- alias: :code:`from aiogram.methods import RevokeChatInviteLink` + +In handlers with current bot +---------------------------- + +.. code-block:: python + + result: ChatInviteLink = await RevokeChatInviteLink(...) + +With specific bot +~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + result: ChatInviteLink = await bot(RevokeChatInviteLink(...)) + +As reply into Webhook in handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + return RevokeChatInviteLink(...) diff --git a/docs2/api/methods/send_animation.rst b/docs2/api/methods/send_animation.rst index 8c2515a7..2e6284b5 100644 --- a/docs2/api/methods/send_animation.rst +++ b/docs2/api/methods/send_animation.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendAnimation(...) \ No newline at end of file + return SendAnimation(...) diff --git a/docs2/api/methods/send_audio.rst b/docs2/api/methods/send_audio.rst index 9da55ded..ce023e84 100644 --- a/docs2/api/methods/send_audio.rst +++ b/docs2/api/methods/send_audio.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendAudio(...) \ No newline at end of file + return SendAudio(...) diff --git a/docs2/api/methods/send_chat_action.rst b/docs2/api/methods/send_chat_action.rst index 156915f8..97d3bd22 100644 --- a/docs2/api/methods/send_chat_action.rst +++ b/docs2/api/methods/send_chat_action.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendChatAction(...) \ No newline at end of file + return SendChatAction(...) diff --git a/docs2/api/methods/send_contact.rst b/docs2/api/methods/send_contact.rst index 6560a367..48cae668 100644 --- a/docs2/api/methods/send_contact.rst +++ b/docs2/api/methods/send_contact.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendContact(...) \ No newline at end of file + return SendContact(...) diff --git a/docs2/api/methods/send_dice.rst b/docs2/api/methods/send_dice.rst index 9348d2b5..2774fd6d 100644 --- a/docs2/api/methods/send_dice.rst +++ b/docs2/api/methods/send_dice.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendDice(...) \ No newline at end of file + return SendDice(...) diff --git a/docs2/api/methods/send_document.rst b/docs2/api/methods/send_document.rst index 2996da0d..5134bcde 100644 --- a/docs2/api/methods/send_document.rst +++ b/docs2/api/methods/send_document.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendDocument(...) \ No newline at end of file + return SendDocument(...) diff --git a/docs2/api/methods/send_game.rst b/docs2/api/methods/send_game.rst index 0526baaa..149e3131 100644 --- a/docs2/api/methods/send_game.rst +++ b/docs2/api/methods/send_game.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendGame(...) \ No newline at end of file + return SendGame(...) diff --git a/docs2/api/methods/send_invoice.rst b/docs2/api/methods/send_invoice.rst index f7d88111..90132a46 100644 --- a/docs2/api/methods/send_invoice.rst +++ b/docs2/api/methods/send_invoice.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendInvoice(...) \ No newline at end of file + return SendInvoice(...) diff --git a/docs2/api/methods/send_location.rst b/docs2/api/methods/send_location.rst index 3694f8a6..769d6724 100644 --- a/docs2/api/methods/send_location.rst +++ b/docs2/api/methods/send_location.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendLocation(...) \ No newline at end of file + return SendLocation(...) diff --git a/docs2/api/methods/send_media_group.rst b/docs2/api/methods/send_media_group.rst index 7f0dfe75..c962e049 100644 --- a/docs2/api/methods/send_media_group.rst +++ b/docs2/api/methods/send_media_group.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendMediaGroup(...) \ No newline at end of file + return SendMediaGroup(...) diff --git a/docs2/api/methods/send_message.rst b/docs2/api/methods/send_message.rst index 318684bf..c054b382 100644 --- a/docs2/api/methods/send_message.rst +++ b/docs2/api/methods/send_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendMessage(...) \ No newline at end of file + return SendMessage(...) diff --git a/docs2/api/methods/send_photo.rst b/docs2/api/methods/send_photo.rst index 313b815e..f6dfd0f5 100644 --- a/docs2/api/methods/send_photo.rst +++ b/docs2/api/methods/send_photo.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendPhoto(...) \ No newline at end of file + return SendPhoto(...) diff --git a/docs2/api/methods/send_poll.rst b/docs2/api/methods/send_poll.rst index e83d3240..7261399b 100644 --- a/docs2/api/methods/send_poll.rst +++ b/docs2/api/methods/send_poll.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendPoll(...) \ No newline at end of file + return SendPoll(...) diff --git a/docs2/api/methods/send_sticker.rst b/docs2/api/methods/send_sticker.rst index ca77bd92..9c27417b 100644 --- a/docs2/api/methods/send_sticker.rst +++ b/docs2/api/methods/send_sticker.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendSticker(...) \ No newline at end of file + return SendSticker(...) diff --git a/docs2/api/methods/send_venue.rst b/docs2/api/methods/send_venue.rst index 6c19d76e..f87100de 100644 --- a/docs2/api/methods/send_venue.rst +++ b/docs2/api/methods/send_venue.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendVenue(...) \ No newline at end of file + return SendVenue(...) diff --git a/docs2/api/methods/send_video.rst b/docs2/api/methods/send_video.rst index 4328017a..8fe6ed40 100644 --- a/docs2/api/methods/send_video.rst +++ b/docs2/api/methods/send_video.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendVideo(...) \ No newline at end of file + return SendVideo(...) diff --git a/docs2/api/methods/send_video_note.rst b/docs2/api/methods/send_video_note.rst index f661a9e0..f10f534e 100644 --- a/docs2/api/methods/send_video_note.rst +++ b/docs2/api/methods/send_video_note.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendVideoNote(...) \ No newline at end of file + return SendVideoNote(...) diff --git a/docs2/api/methods/send_voice.rst b/docs2/api/methods/send_voice.rst index 82159641..b3583bb1 100644 --- a/docs2/api/methods/send_voice.rst +++ b/docs2/api/methods/send_voice.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SendVoice(...) \ No newline at end of file + return SendVoice(...) diff --git a/docs2/api/methods/set_chat_administrator_custom_title.rst b/docs2/api/methods/set_chat_administrator_custom_title.rst index 3e942918..ca73df29 100644 --- a/docs2/api/methods/set_chat_administrator_custom_title.rst +++ b/docs2/api/methods/set_chat_administrator_custom_title.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetChatAdministratorCustomTitle(...) \ No newline at end of file + return SetChatAdministratorCustomTitle(...) diff --git a/docs2/api/methods/set_chat_description.rst b/docs2/api/methods/set_chat_description.rst index af1ba8c5..0625516c 100644 --- a/docs2/api/methods/set_chat_description.rst +++ b/docs2/api/methods/set_chat_description.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetChatDescription(...) \ No newline at end of file + return SetChatDescription(...) diff --git a/docs2/api/methods/set_chat_permissions.rst b/docs2/api/methods/set_chat_permissions.rst index 87f8fa84..b287a7e2 100644 --- a/docs2/api/methods/set_chat_permissions.rst +++ b/docs2/api/methods/set_chat_permissions.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetChatPermissions(...) \ No newline at end of file + return SetChatPermissions(...) diff --git a/docs2/api/methods/set_chat_photo.rst b/docs2/api/methods/set_chat_photo.rst index a2133a14..536696e8 100644 --- a/docs2/api/methods/set_chat_photo.rst +++ b/docs2/api/methods/set_chat_photo.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: bool = await bot(SetChatPhoto(...)) - diff --git a/docs2/api/methods/set_chat_sticker_set.rst b/docs2/api/methods/set_chat_sticker_set.rst index f0a76edb..71e447b2 100644 --- a/docs2/api/methods/set_chat_sticker_set.rst +++ b/docs2/api/methods/set_chat_sticker_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetChatStickerSet(...) \ No newline at end of file + return SetChatStickerSet(...) diff --git a/docs2/api/methods/set_chat_title.rst b/docs2/api/methods/set_chat_title.rst index efba5e20..b9473be9 100644 --- a/docs2/api/methods/set_chat_title.rst +++ b/docs2/api/methods/set_chat_title.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetChatTitle(...) \ No newline at end of file + return SetChatTitle(...) diff --git a/docs2/api/methods/set_game_score.rst b/docs2/api/methods/set_game_score.rst index e631c07b..de9dd9b3 100644 --- a/docs2/api/methods/set_game_score.rst +++ b/docs2/api/methods/set_game_score.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetGameScore(...) \ No newline at end of file + return SetGameScore(...) diff --git a/docs2/api/methods/set_my_commands.rst b/docs2/api/methods/set_my_commands.rst index 5f6db367..456bf270 100644 --- a/docs2/api/methods/set_my_commands.rst +++ b/docs2/api/methods/set_my_commands.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetMyCommands(...) \ No newline at end of file + return SetMyCommands(...) diff --git a/docs2/api/methods/set_passport_data_errors.rst b/docs2/api/methods/set_passport_data_errors.rst index 14c00b44..8db5be3c 100644 --- a/docs2/api/methods/set_passport_data_errors.rst +++ b/docs2/api/methods/set_passport_data_errors.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetPassportDataErrors(...) \ No newline at end of file + return SetPassportDataErrors(...) diff --git a/docs2/api/methods/set_sticker_position_in_set.rst b/docs2/api/methods/set_sticker_position_in_set.rst index a9efce31..f0b4771b 100644 --- a/docs2/api/methods/set_sticker_position_in_set.rst +++ b/docs2/api/methods/set_sticker_position_in_set.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetStickerPositionInSet(...) \ No newline at end of file + return SetStickerPositionInSet(...) diff --git a/docs2/api/methods/set_sticker_set_thumb.rst b/docs2/api/methods/set_sticker_set_thumb.rst index d2959f03..fb4a85e6 100644 --- a/docs2/api/methods/set_sticker_set_thumb.rst +++ b/docs2/api/methods/set_sticker_set_thumb.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetStickerSetThumb(...) \ No newline at end of file + return SetStickerSetThumb(...) diff --git a/docs2/api/methods/set_webhook.rst b/docs2/api/methods/set_webhook.rst index c5188243..5e0a6e20 100644 --- a/docs2/api/methods/set_webhook.rst +++ b/docs2/api/methods/set_webhook.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return SetWebhook(...) \ No newline at end of file + return SetWebhook(...) diff --git a/docs2/api/methods/stop_message_live_location.rst b/docs2/api/methods/stop_message_live_location.rst index bc997f43..f7519860 100644 --- a/docs2/api/methods/stop_message_live_location.rst +++ b/docs2/api/methods/stop_message_live_location.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return StopMessageLiveLocation(...) \ No newline at end of file + return StopMessageLiveLocation(...) diff --git a/docs2/api/methods/stop_poll.rst b/docs2/api/methods/stop_poll.rst index e0ad1046..2e14c094 100644 --- a/docs2/api/methods/stop_poll.rst +++ b/docs2/api/methods/stop_poll.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return StopPoll(...) \ No newline at end of file + return StopPoll(...) diff --git a/docs2/api/methods/unban_chat_member.rst b/docs2/api/methods/unban_chat_member.rst index c49779e4..6aae1669 100644 --- a/docs2/api/methods/unban_chat_member.rst +++ b/docs2/api/methods/unban_chat_member.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return UnbanChatMember(...) \ No newline at end of file + return UnbanChatMember(...) diff --git a/docs2/api/methods/unpin_all_chat_messages.rst b/docs2/api/methods/unpin_all_chat_messages.rst index c4c9b930..90c2ca9e 100644 --- a/docs2/api/methods/unpin_all_chat_messages.rst +++ b/docs2/api/methods/unpin_all_chat_messages.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return UnpinAllChatMessages(...) \ No newline at end of file + return UnpinAllChatMessages(...) diff --git a/docs2/api/methods/unpin_chat_message.rst b/docs2/api/methods/unpin_chat_message.rst index c1d1d68d..02c6e816 100644 --- a/docs2/api/methods/unpin_chat_message.rst +++ b/docs2/api/methods/unpin_chat_message.rst @@ -48,4 +48,4 @@ As reply into Webhook in handler .. code-block:: python - return UnpinChatMessage(...) \ No newline at end of file + return UnpinChatMessage(...) diff --git a/docs2/api/methods/upload_sticker_file.rst b/docs2/api/methods/upload_sticker_file.rst index 4d763556..210c9784 100644 --- a/docs2/api/methods/upload_sticker_file.rst +++ b/docs2/api/methods/upload_sticker_file.rst @@ -42,4 +42,3 @@ With specific bot .. code-block:: python result: File = await bot(UploadStickerFile(...)) - diff --git a/docs2/api/types/animation.rst b/docs2/api/types/animation.rst index 4d48b1e1..1d111c20 100644 --- a/docs2/api/types/animation.rst +++ b/docs2/api/types/animation.rst @@ -6,4 +6,4 @@ Animation .. automodule:: aiogram.types.animation :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/audio.rst b/docs2/api/types/audio.rst index 9eba9027..e29b246c 100644 --- a/docs2/api/types/audio.rst +++ b/docs2/api/types/audio.rst @@ -6,4 +6,4 @@ Audio .. automodule:: aiogram.types.audio :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/bot_command.rst b/docs2/api/types/bot_command.rst index a8364c68..4b8c60ab 100644 --- a/docs2/api/types/bot_command.rst +++ b/docs2/api/types/bot_command.rst @@ -6,4 +6,4 @@ BotCommand .. automodule:: aiogram.types.bot_command :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/callback_game.rst b/docs2/api/types/callback_game.rst index 89f2c91e..789519f3 100644 --- a/docs2/api/types/callback_game.rst +++ b/docs2/api/types/callback_game.rst @@ -6,4 +6,4 @@ CallbackGame .. automodule:: aiogram.types.callback_game :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/callback_query.rst b/docs2/api/types/callback_query.rst index f8d34ddd..22ddc99b 100644 --- a/docs2/api/types/callback_query.rst +++ b/docs2/api/types/callback_query.rst @@ -6,4 +6,4 @@ CallbackQuery .. automodule:: aiogram.types.callback_query :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chat.rst b/docs2/api/types/chat.rst index 800dead4..5b506b1b 100644 --- a/docs2/api/types/chat.rst +++ b/docs2/api/types/chat.rst @@ -6,4 +6,4 @@ Chat .. automodule:: aiogram.types.chat :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chat_invite_link.rst b/docs2/api/types/chat_invite_link.rst new file mode 100644 index 00000000..d64e28ae --- /dev/null +++ b/docs2/api/types/chat_invite_link.rst @@ -0,0 +1,9 @@ +############## +ChatInviteLink +############## + + +.. automodule:: aiogram.types.chat_invite_link + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/chat_location.rst b/docs2/api/types/chat_location.rst index 84f4bef9..5d528095 100644 --- a/docs2/api/types/chat_location.rst +++ b/docs2/api/types/chat_location.rst @@ -6,4 +6,4 @@ ChatLocation .. automodule:: aiogram.types.chat_location :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chat_member.rst b/docs2/api/types/chat_member.rst index 4fff69f9..bd357f7c 100644 --- a/docs2/api/types/chat_member.rst +++ b/docs2/api/types/chat_member.rst @@ -6,4 +6,4 @@ ChatMember .. automodule:: aiogram.types.chat_member :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chat_member_updated.rst b/docs2/api/types/chat_member_updated.rst new file mode 100644 index 00000000..e02ddd8b --- /dev/null +++ b/docs2/api/types/chat_member_updated.rst @@ -0,0 +1,9 @@ +################# +ChatMemberUpdated +################# + + +.. automodule:: aiogram.types.chat_member_updated + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/chat_permissions.rst b/docs2/api/types/chat_permissions.rst index b3020a19..6eedb23b 100644 --- a/docs2/api/types/chat_permissions.rst +++ b/docs2/api/types/chat_permissions.rst @@ -6,4 +6,4 @@ ChatPermissions .. automodule:: aiogram.types.chat_permissions :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chat_photo.rst b/docs2/api/types/chat_photo.rst index bc7c8a5e..7821d5ba 100644 --- a/docs2/api/types/chat_photo.rst +++ b/docs2/api/types/chat_photo.rst @@ -6,4 +6,4 @@ ChatPhoto .. automodule:: aiogram.types.chat_photo :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/chosen_inline_result.rst b/docs2/api/types/chosen_inline_result.rst index fe4d7c11..3f86a983 100644 --- a/docs2/api/types/chosen_inline_result.rst +++ b/docs2/api/types/chosen_inline_result.rst @@ -6,4 +6,4 @@ ChosenInlineResult .. automodule:: aiogram.types.chosen_inline_result :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/contact.rst b/docs2/api/types/contact.rst index aa75232e..f99e1d27 100644 --- a/docs2/api/types/contact.rst +++ b/docs2/api/types/contact.rst @@ -6,4 +6,4 @@ Contact .. automodule:: aiogram.types.contact :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/dice.rst b/docs2/api/types/dice.rst index 15dbab13..41ddf6c4 100644 --- a/docs2/api/types/dice.rst +++ b/docs2/api/types/dice.rst @@ -6,4 +6,4 @@ Dice .. automodule:: aiogram.types.dice :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/document.rst b/docs2/api/types/document.rst index 8138cf2c..48799778 100644 --- a/docs2/api/types/document.rst +++ b/docs2/api/types/document.rst @@ -6,4 +6,4 @@ Document .. automodule:: aiogram.types.document :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/encrypted_credentials.rst b/docs2/api/types/encrypted_credentials.rst index 185e7881..41425c95 100644 --- a/docs2/api/types/encrypted_credentials.rst +++ b/docs2/api/types/encrypted_credentials.rst @@ -6,4 +6,4 @@ EncryptedCredentials .. automodule:: aiogram.types.encrypted_credentials :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/encrypted_passport_element.rst b/docs2/api/types/encrypted_passport_element.rst index 78a5c223..0acf7a8e 100644 --- a/docs2/api/types/encrypted_passport_element.rst +++ b/docs2/api/types/encrypted_passport_element.rst @@ -6,4 +6,4 @@ EncryptedPassportElement .. automodule:: aiogram.types.encrypted_passport_element :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/file.rst b/docs2/api/types/file.rst index 4089e6c8..5a9d920e 100644 --- a/docs2/api/types/file.rst +++ b/docs2/api/types/file.rst @@ -6,4 +6,4 @@ File .. automodule:: aiogram.types.file :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/force_reply.rst b/docs2/api/types/force_reply.rst index e15d8b18..326cd91f 100644 --- a/docs2/api/types/force_reply.rst +++ b/docs2/api/types/force_reply.rst @@ -6,4 +6,4 @@ ForceReply .. automodule:: aiogram.types.force_reply :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/game.rst b/docs2/api/types/game.rst index 706206fc..62a7f390 100644 --- a/docs2/api/types/game.rst +++ b/docs2/api/types/game.rst @@ -6,4 +6,4 @@ Game .. automodule:: aiogram.types.game :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/game_high_score.rst b/docs2/api/types/game_high_score.rst index 044c70ed..6f8d8194 100644 --- a/docs2/api/types/game_high_score.rst +++ b/docs2/api/types/game_high_score.rst @@ -6,4 +6,4 @@ GameHighScore .. automodule:: aiogram.types.game_high_score :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/index.rst b/docs2/api/types/index.rst index 07f8be47..2e3b3812 100644 --- a/docs2/api/types/index.rst +++ b/docs2/api/types/index.rst @@ -41,6 +41,11 @@ Available types location venue proximity_alert_triggered + message_auto_delete_timer_changed + voice_chat_scheduled + voice_chat_started + voice_chat_ended + voice_chat_participants_invited user_profile_photos file reply_keyboard_markup @@ -53,7 +58,9 @@ Available types callback_query force_reply chat_photo + chat_invite_link chat_member + chat_member_updated chat_permissions chat_location bot_command @@ -111,6 +118,7 @@ Inline mode input_location_message_content input_venue_message_content input_contact_message_content + input_invoice_message_content chosen_inline_result Payments @@ -158,4 +166,3 @@ Games game callback_game game_high_score - diff --git a/docs2/api/types/inline_keyboard_button.rst b/docs2/api/types/inline_keyboard_button.rst index 3689b038..1075ad01 100644 --- a/docs2/api/types/inline_keyboard_button.rst +++ b/docs2/api/types/inline_keyboard_button.rst @@ -6,4 +6,4 @@ InlineKeyboardButton .. automodule:: aiogram.types.inline_keyboard_button :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_keyboard_markup.rst b/docs2/api/types/inline_keyboard_markup.rst index bdb03b8e..b7c5108f 100644 --- a/docs2/api/types/inline_keyboard_markup.rst +++ b/docs2/api/types/inline_keyboard_markup.rst @@ -6,4 +6,4 @@ InlineKeyboardMarkup .. automodule:: aiogram.types.inline_keyboard_markup :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query.rst b/docs2/api/types/inline_query.rst index ab1b08e5..7577b29c 100644 --- a/docs2/api/types/inline_query.rst +++ b/docs2/api/types/inline_query.rst @@ -6,4 +6,4 @@ InlineQuery .. automodule:: aiogram.types.inline_query :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result.rst b/docs2/api/types/inline_query_result.rst index 8f65bd92..ba3e265f 100644 --- a/docs2/api/types/inline_query_result.rst +++ b/docs2/api/types/inline_query_result.rst @@ -6,4 +6,4 @@ InlineQueryResult .. automodule:: aiogram.types.inline_query_result :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_article.rst b/docs2/api/types/inline_query_result_article.rst index a633ba41..8ffb1db9 100644 --- a/docs2/api/types/inline_query_result_article.rst +++ b/docs2/api/types/inline_query_result_article.rst @@ -6,4 +6,4 @@ InlineQueryResultArticle .. automodule:: aiogram.types.inline_query_result_article :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_audio.rst b/docs2/api/types/inline_query_result_audio.rst index 584ee611..50858460 100644 --- a/docs2/api/types/inline_query_result_audio.rst +++ b/docs2/api/types/inline_query_result_audio.rst @@ -6,4 +6,4 @@ InlineQueryResultAudio .. automodule:: aiogram.types.inline_query_result_audio :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_audio.rst b/docs2/api/types/inline_query_result_cached_audio.rst index af64c31a..bcce043d 100644 --- a/docs2/api/types/inline_query_result_cached_audio.rst +++ b/docs2/api/types/inline_query_result_cached_audio.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedAudio .. automodule:: aiogram.types.inline_query_result_cached_audio :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_document.rst b/docs2/api/types/inline_query_result_cached_document.rst index 39ebaf3c..0813734d 100644 --- a/docs2/api/types/inline_query_result_cached_document.rst +++ b/docs2/api/types/inline_query_result_cached_document.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedDocument .. automodule:: aiogram.types.inline_query_result_cached_document :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_gif.rst b/docs2/api/types/inline_query_result_cached_gif.rst index 7d88ab69..d1103a55 100644 --- a/docs2/api/types/inline_query_result_cached_gif.rst +++ b/docs2/api/types/inline_query_result_cached_gif.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedGif .. automodule:: aiogram.types.inline_query_result_cached_gif :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_mpeg4_gif.rst b/docs2/api/types/inline_query_result_cached_mpeg4_gif.rst index 23e06635..022ce1ca 100644 --- a/docs2/api/types/inline_query_result_cached_mpeg4_gif.rst +++ b/docs2/api/types/inline_query_result_cached_mpeg4_gif.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedMpeg4Gif .. automodule:: aiogram.types.inline_query_result_cached_mpeg4_gif :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_photo.rst b/docs2/api/types/inline_query_result_cached_photo.rst index 3ebcc6be..3fcd27bc 100644 --- a/docs2/api/types/inline_query_result_cached_photo.rst +++ b/docs2/api/types/inline_query_result_cached_photo.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedPhoto .. automodule:: aiogram.types.inline_query_result_cached_photo :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_sticker.rst b/docs2/api/types/inline_query_result_cached_sticker.rst index 3156775a..30a5d5b3 100644 --- a/docs2/api/types/inline_query_result_cached_sticker.rst +++ b/docs2/api/types/inline_query_result_cached_sticker.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedSticker .. automodule:: aiogram.types.inline_query_result_cached_sticker :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_video.rst b/docs2/api/types/inline_query_result_cached_video.rst index 51b95a05..0c5acbe9 100644 --- a/docs2/api/types/inline_query_result_cached_video.rst +++ b/docs2/api/types/inline_query_result_cached_video.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedVideo .. automodule:: aiogram.types.inline_query_result_cached_video :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_cached_voice.rst b/docs2/api/types/inline_query_result_cached_voice.rst index b2c70d60..5b4f0d8e 100644 --- a/docs2/api/types/inline_query_result_cached_voice.rst +++ b/docs2/api/types/inline_query_result_cached_voice.rst @@ -6,4 +6,4 @@ InlineQueryResultCachedVoice .. automodule:: aiogram.types.inline_query_result_cached_voice :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_contact.rst b/docs2/api/types/inline_query_result_contact.rst index e2ae2f9c..123b4d61 100644 --- a/docs2/api/types/inline_query_result_contact.rst +++ b/docs2/api/types/inline_query_result_contact.rst @@ -6,4 +6,4 @@ InlineQueryResultContact .. automodule:: aiogram.types.inline_query_result_contact :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_document.rst b/docs2/api/types/inline_query_result_document.rst index 931b8938..6352c6c3 100644 --- a/docs2/api/types/inline_query_result_document.rst +++ b/docs2/api/types/inline_query_result_document.rst @@ -6,4 +6,4 @@ InlineQueryResultDocument .. automodule:: aiogram.types.inline_query_result_document :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_game.rst b/docs2/api/types/inline_query_result_game.rst index bbe99fcd..562c1974 100644 --- a/docs2/api/types/inline_query_result_game.rst +++ b/docs2/api/types/inline_query_result_game.rst @@ -6,4 +6,4 @@ InlineQueryResultGame .. automodule:: aiogram.types.inline_query_result_game :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_gif.rst b/docs2/api/types/inline_query_result_gif.rst index fbdf91dd..552252de 100644 --- a/docs2/api/types/inline_query_result_gif.rst +++ b/docs2/api/types/inline_query_result_gif.rst @@ -6,4 +6,4 @@ InlineQueryResultGif .. automodule:: aiogram.types.inline_query_result_gif :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_location.rst b/docs2/api/types/inline_query_result_location.rst index 5edd684f..fcde9fb2 100644 --- a/docs2/api/types/inline_query_result_location.rst +++ b/docs2/api/types/inline_query_result_location.rst @@ -6,4 +6,4 @@ InlineQueryResultLocation .. automodule:: aiogram.types.inline_query_result_location :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_mpeg4_gif.rst b/docs2/api/types/inline_query_result_mpeg4_gif.rst index 6fc64d7d..ccdfb06f 100644 --- a/docs2/api/types/inline_query_result_mpeg4_gif.rst +++ b/docs2/api/types/inline_query_result_mpeg4_gif.rst @@ -6,4 +6,4 @@ InlineQueryResultMpeg4Gif .. automodule:: aiogram.types.inline_query_result_mpeg4_gif :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_photo.rst b/docs2/api/types/inline_query_result_photo.rst index 1b171e93..4af41c8e 100644 --- a/docs2/api/types/inline_query_result_photo.rst +++ b/docs2/api/types/inline_query_result_photo.rst @@ -6,4 +6,4 @@ InlineQueryResultPhoto .. automodule:: aiogram.types.inline_query_result_photo :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_venue.rst b/docs2/api/types/inline_query_result_venue.rst index 20e9289f..b3c40c01 100644 --- a/docs2/api/types/inline_query_result_venue.rst +++ b/docs2/api/types/inline_query_result_venue.rst @@ -6,4 +6,4 @@ InlineQueryResultVenue .. automodule:: aiogram.types.inline_query_result_venue :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_video.rst b/docs2/api/types/inline_query_result_video.rst index 374dcf17..e27f6be3 100644 --- a/docs2/api/types/inline_query_result_video.rst +++ b/docs2/api/types/inline_query_result_video.rst @@ -6,4 +6,4 @@ InlineQueryResultVideo .. automodule:: aiogram.types.inline_query_result_video :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/inline_query_result_voice.rst b/docs2/api/types/inline_query_result_voice.rst index 23717afa..4496c4fe 100644 --- a/docs2/api/types/inline_query_result_voice.rst +++ b/docs2/api/types/inline_query_result_voice.rst @@ -6,4 +6,4 @@ InlineQueryResultVoice .. automodule:: aiogram.types.inline_query_result_voice :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_contact_message_content.rst b/docs2/api/types/input_contact_message_content.rst index 51c8cc58..a3100b83 100644 --- a/docs2/api/types/input_contact_message_content.rst +++ b/docs2/api/types/input_contact_message_content.rst @@ -6,4 +6,4 @@ InputContactMessageContent .. automodule:: aiogram.types.input_contact_message_content :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_file.rst b/docs2/api/types/input_file.rst index d295de5f..4197e6cd 100644 --- a/docs2/api/types/input_file.rst +++ b/docs2/api/types/input_file.rst @@ -6,4 +6,4 @@ InputFile .. automodule:: aiogram.types.input_file :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_invoice_message_content.rst b/docs2/api/types/input_invoice_message_content.rst new file mode 100644 index 00000000..f5d7a0ab --- /dev/null +++ b/docs2/api/types/input_invoice_message_content.rst @@ -0,0 +1,9 @@ +########################## +InputInvoiceMessageContent +########################## + + +.. automodule:: aiogram.types.input_invoice_message_content + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/input_location_message_content.rst b/docs2/api/types/input_location_message_content.rst index 9f33b5cc..6ca59b0b 100644 --- a/docs2/api/types/input_location_message_content.rst +++ b/docs2/api/types/input_location_message_content.rst @@ -6,4 +6,4 @@ InputLocationMessageContent .. automodule:: aiogram.types.input_location_message_content :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media.rst b/docs2/api/types/input_media.rst index 3c4f8e0c..9b3f386b 100644 --- a/docs2/api/types/input_media.rst +++ b/docs2/api/types/input_media.rst @@ -6,4 +6,4 @@ InputMedia .. automodule:: aiogram.types.input_media :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media_animation.rst b/docs2/api/types/input_media_animation.rst index 9f16d9de..9c00494b 100644 --- a/docs2/api/types/input_media_animation.rst +++ b/docs2/api/types/input_media_animation.rst @@ -6,4 +6,4 @@ InputMediaAnimation .. automodule:: aiogram.types.input_media_animation :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media_audio.rst b/docs2/api/types/input_media_audio.rst index a312af6f..c12d307c 100644 --- a/docs2/api/types/input_media_audio.rst +++ b/docs2/api/types/input_media_audio.rst @@ -6,4 +6,4 @@ InputMediaAudio .. automodule:: aiogram.types.input_media_audio :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media_document.rst b/docs2/api/types/input_media_document.rst index b5f6c196..645b78e7 100644 --- a/docs2/api/types/input_media_document.rst +++ b/docs2/api/types/input_media_document.rst @@ -6,4 +6,4 @@ InputMediaDocument .. automodule:: aiogram.types.input_media_document :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media_photo.rst b/docs2/api/types/input_media_photo.rst index 59ddb8f5..32656e29 100644 --- a/docs2/api/types/input_media_photo.rst +++ b/docs2/api/types/input_media_photo.rst @@ -6,4 +6,4 @@ InputMediaPhoto .. automodule:: aiogram.types.input_media_photo :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_media_video.rst b/docs2/api/types/input_media_video.rst index ef2ded4d..57099c51 100644 --- a/docs2/api/types/input_media_video.rst +++ b/docs2/api/types/input_media_video.rst @@ -6,4 +6,4 @@ InputMediaVideo .. automodule:: aiogram.types.input_media_video :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_message_content.rst b/docs2/api/types/input_message_content.rst index 945f4ee1..84040fb7 100644 --- a/docs2/api/types/input_message_content.rst +++ b/docs2/api/types/input_message_content.rst @@ -6,4 +6,4 @@ InputMessageContent .. automodule:: aiogram.types.input_message_content :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_text_message_content.rst b/docs2/api/types/input_text_message_content.rst index 48ca93a1..1eb83e54 100644 --- a/docs2/api/types/input_text_message_content.rst +++ b/docs2/api/types/input_text_message_content.rst @@ -6,4 +6,4 @@ InputTextMessageContent .. automodule:: aiogram.types.input_text_message_content :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/input_venue_message_content.rst b/docs2/api/types/input_venue_message_content.rst index ed0f5792..479a99a0 100644 --- a/docs2/api/types/input_venue_message_content.rst +++ b/docs2/api/types/input_venue_message_content.rst @@ -6,4 +6,4 @@ InputVenueMessageContent .. automodule:: aiogram.types.input_venue_message_content :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/invoice.rst b/docs2/api/types/invoice.rst index b8c51922..24ecc961 100644 --- a/docs2/api/types/invoice.rst +++ b/docs2/api/types/invoice.rst @@ -6,4 +6,4 @@ Invoice .. automodule:: aiogram.types.invoice :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/keyboard_button.rst b/docs2/api/types/keyboard_button.rst index 7321914d..9faca06d 100644 --- a/docs2/api/types/keyboard_button.rst +++ b/docs2/api/types/keyboard_button.rst @@ -6,4 +6,4 @@ KeyboardButton .. automodule:: aiogram.types.keyboard_button :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/keyboard_button_poll_type.rst b/docs2/api/types/keyboard_button_poll_type.rst index e24d92da..9a4974a5 100644 --- a/docs2/api/types/keyboard_button_poll_type.rst +++ b/docs2/api/types/keyboard_button_poll_type.rst @@ -6,4 +6,4 @@ KeyboardButtonPollType .. automodule:: aiogram.types.keyboard_button_poll_type :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/labeled_price.rst b/docs2/api/types/labeled_price.rst index 69512ab2..a76b28f3 100644 --- a/docs2/api/types/labeled_price.rst +++ b/docs2/api/types/labeled_price.rst @@ -6,4 +6,4 @@ LabeledPrice .. automodule:: aiogram.types.labeled_price :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/location.rst b/docs2/api/types/location.rst index 244331c8..2957683a 100644 --- a/docs2/api/types/location.rst +++ b/docs2/api/types/location.rst @@ -6,4 +6,4 @@ Location .. automodule:: aiogram.types.location :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/login_url.rst b/docs2/api/types/login_url.rst index 7122fe50..f72b28b6 100644 --- a/docs2/api/types/login_url.rst +++ b/docs2/api/types/login_url.rst @@ -6,4 +6,4 @@ LoginUrl .. automodule:: aiogram.types.login_url :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/mask_position.rst b/docs2/api/types/mask_position.rst index d7dd7bbb..74c28494 100644 --- a/docs2/api/types/mask_position.rst +++ b/docs2/api/types/mask_position.rst @@ -6,4 +6,4 @@ MaskPosition .. automodule:: aiogram.types.mask_position :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/message.rst b/docs2/api/types/message.rst index ea9ebcdd..5e1be4f7 100644 --- a/docs2/api/types/message.rst +++ b/docs2/api/types/message.rst @@ -6,4 +6,4 @@ Message .. automodule:: aiogram.types.message :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/message_auto_delete_timer_changed.rst b/docs2/api/types/message_auto_delete_timer_changed.rst new file mode 100644 index 00000000..102caacc --- /dev/null +++ b/docs2/api/types/message_auto_delete_timer_changed.rst @@ -0,0 +1,9 @@ +############################# +MessageAutoDeleteTimerChanged +############################# + + +.. automodule:: aiogram.types.message_auto_delete_timer_changed + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/message_entity.rst b/docs2/api/types/message_entity.rst index fb4ccb0c..38ee737d 100644 --- a/docs2/api/types/message_entity.rst +++ b/docs2/api/types/message_entity.rst @@ -6,4 +6,4 @@ MessageEntity .. automodule:: aiogram.types.message_entity :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/message_id.rst b/docs2/api/types/message_id.rst index 35ee56fa..2ed2adc6 100644 --- a/docs2/api/types/message_id.rst +++ b/docs2/api/types/message_id.rst @@ -6,4 +6,4 @@ MessageId .. automodule:: aiogram.types.message_id :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/order_info.rst b/docs2/api/types/order_info.rst index b32b433c..6180f709 100644 --- a/docs2/api/types/order_info.rst +++ b/docs2/api/types/order_info.rst @@ -6,4 +6,4 @@ OrderInfo .. automodule:: aiogram.types.order_info :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_data.rst b/docs2/api/types/passport_data.rst index 6918a40c..9a3de684 100644 --- a/docs2/api/types/passport_data.rst +++ b/docs2/api/types/passport_data.rst @@ -6,4 +6,4 @@ PassportData .. automodule:: aiogram.types.passport_data :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error.rst b/docs2/api/types/passport_element_error.rst index eb8de72b..8fc30e86 100644 --- a/docs2/api/types/passport_element_error.rst +++ b/docs2/api/types/passport_element_error.rst @@ -6,4 +6,4 @@ PassportElementError .. automodule:: aiogram.types.passport_element_error :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_data_field.rst b/docs2/api/types/passport_element_error_data_field.rst index 4887f585..b9382471 100644 --- a/docs2/api/types/passport_element_error_data_field.rst +++ b/docs2/api/types/passport_element_error_data_field.rst @@ -6,4 +6,4 @@ PassportElementErrorDataField .. automodule:: aiogram.types.passport_element_error_data_field :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_file.rst b/docs2/api/types/passport_element_error_file.rst index 849d2904..877def6a 100644 --- a/docs2/api/types/passport_element_error_file.rst +++ b/docs2/api/types/passport_element_error_file.rst @@ -6,4 +6,4 @@ PassportElementErrorFile .. automodule:: aiogram.types.passport_element_error_file :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_files.rst b/docs2/api/types/passport_element_error_files.rst index 36a3aa94..922b4ffb 100644 --- a/docs2/api/types/passport_element_error_files.rst +++ b/docs2/api/types/passport_element_error_files.rst @@ -6,4 +6,4 @@ PassportElementErrorFiles .. automodule:: aiogram.types.passport_element_error_files :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_front_side.rst b/docs2/api/types/passport_element_error_front_side.rst index 1e6cb1a4..3f7dfe81 100644 --- a/docs2/api/types/passport_element_error_front_side.rst +++ b/docs2/api/types/passport_element_error_front_side.rst @@ -6,4 +6,4 @@ PassportElementErrorFrontSide .. automodule:: aiogram.types.passport_element_error_front_side :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_reverse_side.rst b/docs2/api/types/passport_element_error_reverse_side.rst index 56f2291d..dd61c9a1 100644 --- a/docs2/api/types/passport_element_error_reverse_side.rst +++ b/docs2/api/types/passport_element_error_reverse_side.rst @@ -6,4 +6,4 @@ PassportElementErrorReverseSide .. automodule:: aiogram.types.passport_element_error_reverse_side :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_selfie.rst b/docs2/api/types/passport_element_error_selfie.rst index 082ee422..d3463191 100644 --- a/docs2/api/types/passport_element_error_selfie.rst +++ b/docs2/api/types/passport_element_error_selfie.rst @@ -6,4 +6,4 @@ PassportElementErrorSelfie .. automodule:: aiogram.types.passport_element_error_selfie :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_translation_file.rst b/docs2/api/types/passport_element_error_translation_file.rst index d30fa6bc..3a0e16aa 100644 --- a/docs2/api/types/passport_element_error_translation_file.rst +++ b/docs2/api/types/passport_element_error_translation_file.rst @@ -6,4 +6,4 @@ PassportElementErrorTranslationFile .. automodule:: aiogram.types.passport_element_error_translation_file :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_translation_files.rst b/docs2/api/types/passport_element_error_translation_files.rst index 79b0ef79..9ac03422 100644 --- a/docs2/api/types/passport_element_error_translation_files.rst +++ b/docs2/api/types/passport_element_error_translation_files.rst @@ -6,4 +6,4 @@ PassportElementErrorTranslationFiles .. automodule:: aiogram.types.passport_element_error_translation_files :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_element_error_unspecified.rst b/docs2/api/types/passport_element_error_unspecified.rst index d59a985e..ec90bed9 100644 --- a/docs2/api/types/passport_element_error_unspecified.rst +++ b/docs2/api/types/passport_element_error_unspecified.rst @@ -6,4 +6,4 @@ PassportElementErrorUnspecified .. automodule:: aiogram.types.passport_element_error_unspecified :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/passport_file.rst b/docs2/api/types/passport_file.rst index 944cc7e7..4c737fff 100644 --- a/docs2/api/types/passport_file.rst +++ b/docs2/api/types/passport_file.rst @@ -6,4 +6,4 @@ PassportFile .. automodule:: aiogram.types.passport_file :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/photo_size.rst b/docs2/api/types/photo_size.rst index fbd32f33..1086588c 100644 --- a/docs2/api/types/photo_size.rst +++ b/docs2/api/types/photo_size.rst @@ -6,4 +6,4 @@ PhotoSize .. automodule:: aiogram.types.photo_size :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/poll.rst b/docs2/api/types/poll.rst index 3b278712..fd11bc88 100644 --- a/docs2/api/types/poll.rst +++ b/docs2/api/types/poll.rst @@ -6,4 +6,4 @@ Poll .. automodule:: aiogram.types.poll :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/poll_answer.rst b/docs2/api/types/poll_answer.rst index adce5f72..fe92fb6a 100644 --- a/docs2/api/types/poll_answer.rst +++ b/docs2/api/types/poll_answer.rst @@ -6,4 +6,4 @@ PollAnswer .. automodule:: aiogram.types.poll_answer :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/poll_option.rst b/docs2/api/types/poll_option.rst index 5b7bbefb..72ebfbd2 100644 --- a/docs2/api/types/poll_option.rst +++ b/docs2/api/types/poll_option.rst @@ -6,4 +6,4 @@ PollOption .. automodule:: aiogram.types.poll_option :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/pre_checkout_query.rst b/docs2/api/types/pre_checkout_query.rst index 2d9367ef..418c11b9 100644 --- a/docs2/api/types/pre_checkout_query.rst +++ b/docs2/api/types/pre_checkout_query.rst @@ -6,4 +6,4 @@ PreCheckoutQuery .. automodule:: aiogram.types.pre_checkout_query :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/proximity_alert_triggered.rst b/docs2/api/types/proximity_alert_triggered.rst index 1d0ba461..98ac7d2f 100644 --- a/docs2/api/types/proximity_alert_triggered.rst +++ b/docs2/api/types/proximity_alert_triggered.rst @@ -6,4 +6,4 @@ ProximityAlertTriggered .. automodule:: aiogram.types.proximity_alert_triggered :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/reply_keyboard_markup.rst b/docs2/api/types/reply_keyboard_markup.rst index 2f32bdff..a5c5ae85 100644 --- a/docs2/api/types/reply_keyboard_markup.rst +++ b/docs2/api/types/reply_keyboard_markup.rst @@ -6,4 +6,4 @@ ReplyKeyboardMarkup .. automodule:: aiogram.types.reply_keyboard_markup :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/reply_keyboard_remove.rst b/docs2/api/types/reply_keyboard_remove.rst index acc212ee..799ad3a9 100644 --- a/docs2/api/types/reply_keyboard_remove.rst +++ b/docs2/api/types/reply_keyboard_remove.rst @@ -6,4 +6,4 @@ ReplyKeyboardRemove .. automodule:: aiogram.types.reply_keyboard_remove :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/response_parameters.rst b/docs2/api/types/response_parameters.rst index 42a1a4d6..5b7056b8 100644 --- a/docs2/api/types/response_parameters.rst +++ b/docs2/api/types/response_parameters.rst @@ -6,4 +6,4 @@ ResponseParameters .. automodule:: aiogram.types.response_parameters :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/shipping_address.rst b/docs2/api/types/shipping_address.rst index d2b72bde..0421c58e 100644 --- a/docs2/api/types/shipping_address.rst +++ b/docs2/api/types/shipping_address.rst @@ -6,4 +6,4 @@ ShippingAddress .. automodule:: aiogram.types.shipping_address :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/shipping_option.rst b/docs2/api/types/shipping_option.rst index e3976d5f..28e13897 100644 --- a/docs2/api/types/shipping_option.rst +++ b/docs2/api/types/shipping_option.rst @@ -6,4 +6,4 @@ ShippingOption .. automodule:: aiogram.types.shipping_option :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/shipping_query.rst b/docs2/api/types/shipping_query.rst index 9117bbd5..c4ccdf70 100644 --- a/docs2/api/types/shipping_query.rst +++ b/docs2/api/types/shipping_query.rst @@ -6,4 +6,4 @@ ShippingQuery .. automodule:: aiogram.types.shipping_query :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/sticker.rst b/docs2/api/types/sticker.rst index 643e4122..f15dd9ef 100644 --- a/docs2/api/types/sticker.rst +++ b/docs2/api/types/sticker.rst @@ -6,4 +6,4 @@ Sticker .. automodule:: aiogram.types.sticker :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/sticker_set.rst b/docs2/api/types/sticker_set.rst index 19e2ae99..a25e064f 100644 --- a/docs2/api/types/sticker_set.rst +++ b/docs2/api/types/sticker_set.rst @@ -6,4 +6,4 @@ StickerSet .. automodule:: aiogram.types.sticker_set :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/successful_payment.rst b/docs2/api/types/successful_payment.rst index 10ec78b1..f21f860b 100644 --- a/docs2/api/types/successful_payment.rst +++ b/docs2/api/types/successful_payment.rst @@ -6,4 +6,4 @@ SuccessfulPayment .. automodule:: aiogram.types.successful_payment :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/update.rst b/docs2/api/types/update.rst index c8338f19..5419da6e 100644 --- a/docs2/api/types/update.rst +++ b/docs2/api/types/update.rst @@ -6,4 +6,4 @@ Update .. automodule:: aiogram.types.update :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/user.rst b/docs2/api/types/user.rst index 5c58898d..b13f8808 100644 --- a/docs2/api/types/user.rst +++ b/docs2/api/types/user.rst @@ -6,4 +6,4 @@ User .. automodule:: aiogram.types.user :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/user_profile_photos.rst b/docs2/api/types/user_profile_photos.rst index 7a6876b4..b6cce934 100644 --- a/docs2/api/types/user_profile_photos.rst +++ b/docs2/api/types/user_profile_photos.rst @@ -6,4 +6,4 @@ UserProfilePhotos .. automodule:: aiogram.types.user_profile_photos :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/venue.rst b/docs2/api/types/venue.rst index 2621755b..75a71fff 100644 --- a/docs2/api/types/venue.rst +++ b/docs2/api/types/venue.rst @@ -6,4 +6,4 @@ Venue .. automodule:: aiogram.types.venue :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/video.rst b/docs2/api/types/video.rst index 30d29917..0478b3f7 100644 --- a/docs2/api/types/video.rst +++ b/docs2/api/types/video.rst @@ -6,4 +6,4 @@ Video .. automodule:: aiogram.types.video :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/video_note.rst b/docs2/api/types/video_note.rst index a436faa8..b9d308e5 100644 --- a/docs2/api/types/video_note.rst +++ b/docs2/api/types/video_note.rst @@ -6,4 +6,4 @@ VideoNote .. automodule:: aiogram.types.video_note :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/voice.rst b/docs2/api/types/voice.rst index 29c44ea6..7d58722d 100644 --- a/docs2/api/types/voice.rst +++ b/docs2/api/types/voice.rst @@ -6,4 +6,4 @@ Voice .. automodule:: aiogram.types.voice :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/api/types/voice_chat_ended.rst b/docs2/api/types/voice_chat_ended.rst new file mode 100644 index 00000000..cce70b7c --- /dev/null +++ b/docs2/api/types/voice_chat_ended.rst @@ -0,0 +1,9 @@ +############## +VoiceChatEnded +############## + + +.. automodule:: aiogram.types.voice_chat_ended + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/voice_chat_participants_invited.rst b/docs2/api/types/voice_chat_participants_invited.rst new file mode 100644 index 00000000..89a94fa9 --- /dev/null +++ b/docs2/api/types/voice_chat_participants_invited.rst @@ -0,0 +1,9 @@ +############################ +VoiceChatParticipantsInvited +############################ + + +.. automodule:: aiogram.types.voice_chat_participants_invited + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/voice_chat_scheduled.rst b/docs2/api/types/voice_chat_scheduled.rst new file mode 100644 index 00000000..e63936e2 --- /dev/null +++ b/docs2/api/types/voice_chat_scheduled.rst @@ -0,0 +1,9 @@ +################## +VoiceChatScheduled +################## + + +.. automodule:: aiogram.types.voice_chat_scheduled + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/voice_chat_started.rst b/docs2/api/types/voice_chat_started.rst new file mode 100644 index 00000000..c1a1964b --- /dev/null +++ b/docs2/api/types/voice_chat_started.rst @@ -0,0 +1,9 @@ +################ +VoiceChatStarted +################ + + +.. automodule:: aiogram.types.voice_chat_started + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/api/types/webhook_info.rst b/docs2/api/types/webhook_info.rst index 0491c68d..259a01bc 100644 --- a/docs2/api/types/webhook_info.rst +++ b/docs2/api/types/webhook_info.rst @@ -6,4 +6,4 @@ WebhookInfo .. automodule:: aiogram.types.webhook_info :members: :member-order: bysource - :undoc-members: True \ No newline at end of file + :undoc-members: True diff --git a/docs2/dispatcher/class_based_handlers/base.rst b/docs2/dispatcher/class_based_handlers/base.rst index 3c3e910d..0d478224 100644 --- a/docs2/dispatcher/class_based_handlers/base.rst +++ b/docs2/dispatcher/class_based_handlers/base.rst @@ -6,7 +6,7 @@ BaseHandler Base handler is generic abstract class and should be used in all other class-based handlers. -Import: :code:`from aiogram.hanler import BaseHandler` +Import: :code:`from aiogram.handler import BaseHandler` By default you will need to override only method :code:`async def handle(self) -> Any: ...` diff --git a/docs2/dispatcher/class_based_handlers/callback_query.rst b/docs2/dispatcher/class_based_handlers/callback_query.rst index 292f111d..a8cdf152 100644 --- a/docs2/dispatcher/class_based_handlers/callback_query.rst +++ b/docs2/dispatcher/class_based_handlers/callback_query.rst @@ -1,27 +1,9 @@ -==================== +#################### CallbackQueryHandler -==================== - -There is base class for callback query handlers. - -Simple usage -============ -.. code-block:: python - - from aiogram.handlers import CallbackQueryHandler - - ... - - @router.callback_query() - class MyHandler(CallbackQueryHandler): - async def handle(self) -> Any: ... +#################### -Extension -========= - -This base handler is subclass of :ref:`BaseHandler ` with some extensions: - -- :code:`self.from_user` is alias for :code:`self.event.from_user` -- :code:`self.message` is alias for :code:`self.event.message` -- :code:`self.callback_data` is alias for :code:`self.event.data` +.. automodule:: aiogram.dispatcher.handler.callback_query + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs2/dispatcher/class_based_handlers/chat_member.rst b/docs2/dispatcher/class_based_handlers/chat_member.rst new file mode 100644 index 00000000..9df18a0c --- /dev/null +++ b/docs2/dispatcher/class_based_handlers/chat_member.rst @@ -0,0 +1,28 @@ +================= +ChatMemberHandler +================= + +There is base class for chat member updated events. + +Simple usage +============ + +.. code-block:: python + + from aiogram.handlers import ChatMemberHandler + + ... + + @router.chat_member() + @router.my_chat_member() + class MyHandler(ChatMemberHandler): + async def handle(self) -> Any: ... + + +Extension +========= + +This base handler is subclass of :ref:`BaseHandler ` with some extensions: + +- :code:`self.chat` is alias for :code:`self.event.chat` + diff --git a/docs2/dispatcher/class_based_handlers/index.rst b/docs2/dispatcher/class_based_handlers/index.rst index 094b127f..4de831ed 100644 --- a/docs2/dispatcher/class_based_handlers/index.rst +++ b/docs2/dispatcher/class_based_handlers/index.rst @@ -20,3 +20,4 @@ There are some base class based handlers what you need to use in your own handle poll pre_checkout_query shipping_query + chat_member diff --git a/poetry.lock b/poetry.lock index d91a7a5f..86a831d1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,7 +8,7 @@ python-versions = "*" [[package]] name = "aiohttp" -version = "3.7.3" +version = "3.7.4.post0" description = "Async http client/server framework (asyncio)" category = "main" optional = false @@ -17,7 +17,7 @@ python-versions = ">=3.6" [package.dependencies] async-timeout = ">=3.0,<4.0" attrs = ">=17.3.0" -chardet = ">=2.0,<4.0" +chardet = ">=2.0,<5.0" multidict = ">=4.5,<7.0" typing-extensions = ">=3.6.5" yarl = ">=1.0,<2.0" @@ -122,7 +122,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (> [[package]] name = "babel" -version = "2.9.0" +version = "2.9.1" description = "Internationalization utilities" category = "main" optional = false @@ -156,33 +156,26 @@ lxml = ["lxml"] [[package]] name = "black" -version = "20.8b1" +version = "21.4b2" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.2" [package.dependencies] appdirs = "*" click = ">=7.1.2" mypy-extensions = ">=0.4.3" -pathspec = ">=0.6,<1" +pathspec = ">=0.8.1,<1" regex = ">=2020.1.8" toml = ">=0.10.1" -typed-ast = ">=1.4.0" -typing-extensions = ">=3.7.4" +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] - -[[package]] -name = "certifi" -version = "2020.12.5" -description = "Python package for providing Mozilla's CA Bundle." -category = "main" -optional = false -python-versions = "*" +python2 = ["typed-ast (>=1.4.2)"] [[package]] name = "cfgv" @@ -194,11 +187,11 @@ python-versions = ">=3.6.1" [[package]] name = "chardet" -version = "3.0.4" +version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" category = "main" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "click" @@ -218,7 +211,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "5.3.1" +version = "5.5" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -229,11 +222,11 @@ toml = ["toml"] [[package]] name = "decorator" -version = "4.4.2" +version = "5.0.7" description = "Decorators for Humans" category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" +python-versions = ">=3.5" [[package]] name = "distlib" @@ -245,7 +238,7 @@ python-versions = "*" [[package]] name = "docutils" -version = "0.16" +version = "0.17.1" description = "Docutils -- Python Documentation Utilities" category = "main" optional = false @@ -261,17 +254,17 @@ python-versions = "*" [[package]] name = "flake8" -version = "3.8.4" +version = "3.9.1" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.6.0a1,<2.7.0" -pyflakes = ">=2.2.0,<2.3.0" +pycodestyle = ">=2.7.0,<2.8.0" +pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "flake8-html" @@ -303,32 +296,24 @@ sphinx = ">=3.0,<4.0" doc = ["myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"] test = ["pytest", "pytest-cov", "pytest-xdist"] -[[package]] -name = "future" -version = "0.18.2" -description = "Clean single-source support for Python 3 and 2" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - [[package]] name = "identify" -version = "1.5.13" +version = "2.2.3" description = "File identification library for Python" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = ">=3.6.1" [package.extras] -license = ["editdistance"] +license = ["editdistance-s"] [[package]] name = "idna" -version = "2.10" +version = "3.1" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.4" [[package]] name = "imagesize" @@ -340,7 +325,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "3.4.0" +version = "4.0.0" description = "Read metadata from Python packages" category = "dev" optional = false @@ -352,7 +337,7 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -364,7 +349,7 @@ python-versions = "*" [[package]] name = "ipython" -version = "7.19.0" +version = "7.22.0" description = "IPython: Productive Interactive Computing" category = "dev" optional = false @@ -375,7 +360,7 @@ appnope = {version = "*", markers = "sys_platform == \"darwin\""} backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" -jedi = ">=0.10" +jedi = ">=0.16" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} pickleshare = "*" prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" @@ -383,7 +368,7 @@ pygments = "*" traitlets = ">=4.2" [package.extras] -all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.14)", "pygments", "qtconsole", "requests", "testpath"] +all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.16)", "pygments", "qtconsole", "requests", "testpath"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -391,7 +376,7 @@ nbformat = ["nbformat"] notebook = ["notebook", "ipywidgets"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.14)"] +test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.16)"] [[package]] name = "ipython-genutils" @@ -403,7 +388,7 @@ python-versions = "*" [[package]] name = "isort" -version = "5.7.0" +version = "5.8.0" description = "A Python utility / library to sort Python imports." category = "dev" optional = false @@ -431,7 +416,7 @@ testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] [[package]] name = "jinja2" -version = "2.11.2" +version = "2.11.3" description = "A very fast and expressive template engine." category = "main" optional = false @@ -443,14 +428,6 @@ MarkupSafe = ">=0.23" [package.extras] i18n = ["Babel (>=0.8)"] -[[package]] -name = "joblib" -version = "1.0.0" -description = "Lightweight pipelining with Python functions" -category = "dev" -optional = false -python-versions = ">=3.6" - [[package]] name = "livereload" version = "2.6.3" @@ -463,47 +440,17 @@ python-versions = "*" six = "*" tornado = {version = "*", markers = "python_version > \"2.7\""} -[[package]] -name = "lunr" -version = "0.5.8" -description = "A Python implementation of Lunr.js" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -future = ">=0.16.0" -nltk = {version = ">=3.2.5", optional = true, markers = "python_version > \"2.7\" and extra == \"languages\""} -six = ">=1.11.0" - -[package.extras] -languages = ["nltk (>=3.2.5,<3.5)", "nltk (>=3.2.5)"] - -[[package]] -name = "lxml" -version = "4.6.2" -description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" - -[package.extras] -cssselect = ["cssselect (>=0.7)"] -html5 = ["html5lib"] -htmlsoup = ["beautifulsoup4"] -source = ["Cython (>=0.29.7)"] - [[package]] name = "magic-filter" -version = "0.1.2" +version = "1.0.0a1" description = "This package provides magic filter based on dynamic attribute getter" category = "main" optional = false -python-versions = ">=3.6.1,<4.0.0" +python-versions = ">=3.6.2,<4.0.0" [[package]] name = "markdown" -version = "3.3.3" +version = "3.3.4" description = "Python implementation of Markdown." category = "dev" optional = false @@ -542,57 +489,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "mkautodoc" -version = "0.1.0" -description = "AutoDoc for MarkDown" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mkdocs" -version = "1.1.2" -description = "Project documentation with Markdown." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -click = ">=3.3" -Jinja2 = ">=2.10.1" -livereload = ">=2.5.1" -lunr = {version = "0.5.8", extras = ["languages"]} -Markdown = ">=3.2.1" -PyYAML = ">=3.10" -tornado = ">=5.0" - -[[package]] -name = "mkdocs-material" -version = "6.2.5" -description = "A Material Design theme for MkDocs" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -markdown = ">=3.2" -mkdocs = ">=1.1" -mkdocs-material-extensions = ">=1.0" -Pygments = ">=2.4" -pymdown-extensions = ">=7.0" - -[[package]] -name = "mkdocs-material-extensions" -version = "1.0.1" -description = "Extension pack for Python Markdown." -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -mkdocs-material = ">=5.0.0" - [[package]] name = "multidict" version = "5.1.0" @@ -603,7 +499,7 @@ python-versions = ">=3.6" [[package]] name = "mypy" -version = "0.800" +version = "0.812" description = "Optional static typing for Python" category = "dev" optional = false @@ -625,31 +521,9 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "nltk" -version = "3.5" -description = "Natural Language Toolkit" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -click = "*" -joblib = "*" -regex = "*" -tqdm = "*" - -[package.extras] -all = ["requests", "numpy", "python-crfsuite", "scikit-learn", "twython", "pyparsing", "scipy", "matplotlib", "gensim"] -corenlp = ["requests"] -machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"] -plot = ["matplotlib"] -tgrep = ["pyparsing"] -twitter = ["twython"] - [[package]] name = "nodeenv" -version = "1.5.0" +version = "1.6.0" description = "Node.js virtual environment builder" category = "dev" optional = false @@ -657,7 +531,7 @@ python-versions = "*" [[package]] name = "packaging" -version = "20.8" +version = "20.9" description = "Core utilities for Python packages" category = "main" optional = false @@ -668,7 +542,7 @@ pyparsing = ">=2.0.2" [[package]] name = "parso" -version = "0.8.1" +version = "0.8.2" description = "A Python Parser" category = "dev" optional = false @@ -721,7 +595,7 @@ dev = ["pre-commit", "tox"] [[package]] name = "pre-commit" -version = "2.9.3" +version = "2.12.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false @@ -738,7 +612,7 @@ virtualenv = ">=20.0.8" [[package]] name = "prompt-toolkit" -version = "3.0.14" +version = "3.0.18" description = "Library for building powerful interactive command lines in Python" category = "dev" optional = false @@ -765,7 +639,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pycodestyle" -version = "2.6.0" +version = "2.7.0" description = "Python style guide checker" category = "dev" optional = false @@ -773,20 +647,22 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pydantic" -version = "1.7.3" +version = "1.8.1" description = "Data validation and settings management using python 3.6 type hinting" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -typing_extensions = ["typing-extensions (>=3.7.2)"] [[package]] name = "pyflakes" -version = "2.2.0" +version = "2.3.1" description = "passive checker of Python programs" category = "dev" optional = false @@ -794,7 +670,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.7.4" +version = "2.8.1" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false @@ -802,7 +678,7 @@ python-versions = ">=3.5" [[package]] name = "pymdown-extensions" -version = "8.1" +version = "8.1.1" description = "Extension pack for Python Markdown." category = "dev" optional = false @@ -821,7 +697,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "pytest" -version = "6.2.1" +version = "6.2.3" description = "pytest: simple powerful testing with Python" category = "dev" optional = false @@ -843,17 +719,17 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-asyncio" -version = "0.14.0" +version = "0.15.1" description = "Pytest support for asyncio." category = "dev" optional = false -python-versions = ">= 3.5" +python-versions = ">= 3.6" [package.dependencies] pytest = ">=5.4.0" [package.extras] -testing = ["async-generator (>=1.3)", "coverage", "hypothesis (>=5.7.1)"] +testing = ["coverage", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" @@ -895,11 +771,11 @@ pytest = ">=2.9.0" [[package]] name = "pytest-mock" -version = "3.5.1" +version = "3.6.0" description = "Thin-wrapper around the mock package for easier use with pytest" category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [package.dependencies] pytest = ">=5.0" @@ -909,7 +785,7 @@ dev = ["pre-commit", "tox", "pytest-asyncio"] [[package]] name = "pytest-mypy" -version = "0.8.0" +version = "0.8.1" description = "Mypy static type checker plugin for Pytest" category = "dev" optional = false @@ -927,7 +803,7 @@ pytest = ">=3.5" [[package]] name = "python-socks" -version = "1.2.0" +version = "1.2.4" description = "Core proxy (SOCKS4, SOCKS5, HTTP tunneling) functionality for Python" category = "main" optional = false @@ -943,7 +819,7 @@ trio = ["trio (>=0.16.0)"] [[package]] name = "pytz" -version = "2020.5" +version = "2021.1" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -959,7 +835,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "regex" -version = "2020.11.13" +version = "2021.4.4" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -967,20 +843,14 @@ python-versions = "*" [[package]] name = "requests" -version = "2.25.1" +version = "2.15.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.dependencies] -certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.27" +python-versions = "*" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +security = ["cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] @@ -1001,15 +871,15 @@ python-versions = "*" [[package]] name = "soupsieve" -version = "2.1" +version = "2.2.1" description = "A modern CSS selector implementation for Beautiful Soup." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "sphinx" -version = "3.4.3" +version = "3.5.3" description = "Python documentation generator" category = "main" optional = false @@ -1035,7 +905,7 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.790)", "docutils-stubs"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.800)", "docutils-stubs"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] @@ -1086,7 +956,7 @@ transifex = ["transifex_client (>=0.11)"] [[package]] name = "sphinx-prompt" -version = "1.3.0" +version = "1.4.0" description = "Sphinx directive to add unselectable prompt" category = "main" optional = false @@ -1199,18 +1069,6 @@ category = "main" optional = false python-versions = ">= 3.5" -[[package]] -name = "tqdm" -version = "4.56.0" -description = "Fast, Extensible Progress Meter" -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" - -[package.extras] -dev = ["py-make (>=0.1.0)", "twine", "wheel"] -telegram = ["requests"] - [[package]] name = "traitlets" version = "5.0.5" @@ -1227,7 +1085,7 @@ test = ["pytest"] [[package]] name = "typed-ast" -version = "1.4.2" +version = "1.4.3" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false @@ -1242,29 +1100,21 @@ optional = false python-versions = "*" [[package]] -name = "urllib3" -version = "1.26.2" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" +name = "uvloop" +version = "0.15.2" +description = "Fast implementation of asyncio event loop on top of libuv" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=3.7" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "uvloop" -version = "0.14.0" -description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" -optional = false -python-versions = "*" +dev = ["Cython (>=0.29.20,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)", "aiohttp", "flake8 (>=3.8.4,<3.9.0)", "psutil", "pycodestyle (>=2.6.0,<2.7.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] +docs = ["Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)"] +test = ["aiohttp", "flake8 (>=3.8.4,<3.9.0)", "psutil", "pycodestyle (>=2.6.0,<2.7.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] [[package]] name = "virtualenv" -version = "20.4.0" +version = "20.4.3" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -1304,25 +1154,25 @@ typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} [[package]] name = "zipp" -version = "3.4.0" +version = "3.4.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [extras] docs = ["sphinx", "sphinx-intl", "sphinx-autobuild", "sphinx-copybutton", "furo", "sphinx-prompt", "Sphinx-Substitution-Extensions"] -fast = ["uvloop"] +fast = [] proxy = ["aiohttp-socks"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "ee4cbf4fb0a62ec777bec179dad21e7cea1ced466ab2a5424f54f8764f2955d3" +content-hash = "9a787135a6d8ed2a395c07246db424e9961281cf7e0dc00fc08507da3081143e" [metadata.files] aiofiles = [ @@ -1330,43 +1180,43 @@ aiofiles = [ {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, ] aiohttp = [ - {file = "aiohttp-3.7.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:328b552513d4f95b0a2eea4c8573e112866107227661834652a8984766aa7656"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c733ef3bdcfe52a1a75564389bad4064352274036e7e234730526d155f04d914"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:2858b2504c8697beb9357be01dc47ef86438cc1cb36ecb6991796d19475faa3e"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d2cfac21e31e841d60dc28c0ec7d4ec47a35c608cb8906435d47ef83ffb22150"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:3228b7a51e3ed533f5472f54f70fd0b0a64c48dc1649a0f0e809bec312934d7a"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:dcc119db14757b0c7bce64042158307b9b1c76471e655751a61b57f5a0e4d78e"}, - {file = "aiohttp-3.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:7d9b42127a6c0bdcc25c3dcf252bb3ddc70454fac593b1b6933ae091396deb13"}, - {file = "aiohttp-3.7.3-cp36-cp36m-win32.whl", hash = "sha256:df48a623c58180874d7407b4d9ec06a19b84ed47f60a3884345b1a5099c1818b"}, - {file = "aiohttp-3.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:0b795072bb1bf87b8620120a6373a3c61bfcb8da7e5c2377f4bb23ff4f0b62c9"}, - {file = "aiohttp-3.7.3-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:0d438c8ca703b1b714e82ed5b7a4412c82577040dadff479c08405e2a715564f"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8389d6044ee4e2037dca83e3f6994738550f6ee8cfb746762283fad9b932868f"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3ea8c252d8df5e9166bcf3d9edced2af132f4ead8ac422eac723c5781063709a"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:78e2f18a82b88cbc37d22365cf8d2b879a492faedb3f2975adb4ed8dfe994d3a"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:df3a7b258cc230a65245167a202dd07320a5af05f3d41da1488ba0fa05bc9347"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:f326b3c1bbfda5b9308252ee0dcb30b612ee92b0e105d4abec70335fab5b1245"}, - {file = "aiohttp-3.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:5e479df4b2d0f8f02133b7e4430098699450e1b2a826438af6bec9a400530957"}, - {file = "aiohttp-3.7.3-cp37-cp37m-win32.whl", hash = "sha256:6d42debaf55450643146fabe4b6817bb2a55b23698b0434107e892a43117285e"}, - {file = "aiohttp-3.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9c58b0b84055d8bc27b7df5a9d141df4ee6ff59821f922dd73155861282f6a3"}, - {file = "aiohttp-3.7.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:f411cb22115cb15452d099fec0ee636b06cf81bfb40ed9c02d30c8dc2bc2e3d1"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1e0920909d916d3375c7a1fdb0b1c78e46170e8bb42792312b6eb6676b2f87f"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:59d11674964b74a81b149d4ceaff2b674b3b0e4d0f10f0be1533e49c4a28408b"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:41608c0acbe0899c852281978492f9ce2c6fbfaf60aff0cefc54a7c4516b822c"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:16a3cb5df5c56f696234ea9e65e227d1ebe9c18aa774d36ff42f532139066a5f"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:6ccc43d68b81c424e46192a778f97da94ee0630337c9bbe5b2ecc9b0c1c59001"}, - {file = "aiohttp-3.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:d03abec50df423b026a5aa09656bd9d37f1e6a49271f123f31f9b8aed5dc3ea3"}, - {file = "aiohttp-3.7.3-cp38-cp38-win32.whl", hash = "sha256:39f4b0a6ae22a1c567cb0630c30dd082481f95c13ca528dc501a7766b9c718c0"}, - {file = "aiohttp-3.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:c68fdf21c6f3573ae19c7ee65f9ff185649a060c9a06535e9c3a0ee0bbac9235"}, - {file = "aiohttp-3.7.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:710376bf67d8ff4500a31d0c207b8941ff4fba5de6890a701d71680474fe2a60"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2406dc1dda01c7f6060ab586e4601f18affb7a6b965c50a8c90ff07569cf782a"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2a7b7640167ab536c3cb90cfc3977c7094f1c5890d7eeede8b273c175c3910fd"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:684850fb1e3e55c9220aad007f8386d8e3e477c4ec9211ae54d968ecdca8c6f9"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:1edfd82a98c5161497bbb111b2b70c0813102ad7e0aa81cbeb34e64c93863005"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:77149002d9386fae303a4a162e6bce75cc2161347ad2ba06c2f0182561875d45"}, - {file = "aiohttp-3.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:756ae7efddd68d4ea7d89c636b703e14a0c686688d42f588b90778a3c2fc0564"}, - {file = "aiohttp-3.7.3-cp39-cp39-win32.whl", hash = "sha256:3b0036c978cbcc4a4512278e98e3e6d9e6b834dc973206162eddf98b586ef1c6"}, - {file = "aiohttp-3.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:e1b95972a0ae3f248a899cdbac92ba2e01d731225f566569311043ce2226f5e7"}, - {file = "aiohttp-3.7.3.tar.gz", hash = "sha256:9c1a81af067e72261c9cbe33ea792893e83bc6aa987bfbd6fdc1e5e7b22777c4"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-win32.whl", hash = "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-win32.whl", hash = "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-win32.whl", hash = "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-win_amd64.whl", hash = "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-win32.whl", hash = "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-win_amd64.whl", hash = "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe"}, + {file = "aiohttp-3.7.4.post0.tar.gz", hash = "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf"}, ] aiohttp-socks = [ {file = "aiohttp_socks-0.5.5-py3-none-any.whl", hash = "sha256:faaa25ed4dc34440ca888d23e089420f3b1918dc4ecf062c3fd9474827ad6a39"}, @@ -1408,8 +1258,8 @@ attrs = [ {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, ] babel = [ - {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"}, - {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"}, + {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, + {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] backcall = [ {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, @@ -1421,19 +1271,16 @@ beautifulsoup4 = [ {file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"}, ] black = [ - {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, -] -certifi = [ - {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, - {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, + {file = "black-21.4b2-py3-none-any.whl", hash = "sha256:bff7067d8bc25eb21dcfdbc8c72f2baafd9ec6de4663241a52fb904b304d391f"}, + {file = "black-21.4b2.tar.gz", hash = "sha256:fc9bcf3b482b05c1f35f6a882c079dc01b9c7795827532f4cc43c0ec88067bbc"}, ] cfgv = [ {file = "cfgv-3.2.0-py2.py3-none-any.whl", hash = "sha256:32e43d604bbe7896fe7c248a9c2276447dbef840feb28fe20494f62af110211d"}, {file = "cfgv-3.2.0.tar.gz", hash = "sha256:cf22deb93d4bcf92f345a5c3cd39d3d41d6340adc60c78bbbd6588c384fda6a1"}, ] chardet = [ - {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, - {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, @@ -1444,75 +1291,78 @@ colorama = [ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-5.3.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fabeeb121735d47d8eab8671b6b031ce08514c86b7ad8f7d5490a7b6dcd6267d"}, - {file = "coverage-5.3.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7e4d159021c2029b958b2363abec4a11db0ce8cd43abb0d9ce44284cb97217e7"}, - {file = "coverage-5.3.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:378ac77af41350a8c6b8801a66021b52da8a05fd77e578b7380e876c0ce4f528"}, - {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e448f56cfeae7b1b3b5bcd99bb377cde7c4eb1970a525c770720a352bc4c8044"}, - {file = "coverage-5.3.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:cc44e3545d908ecf3e5773266c487ad1877be718d9dc65fc7eb6e7d14960985b"}, - {file = "coverage-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:08b3ba72bd981531fd557f67beee376d6700fba183b167857038997ba30dd297"}, - {file = "coverage-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:8dacc4073c359f40fcf73aede8428c35f84639baad7e1b46fce5ab7a8a7be4bb"}, - {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ee2f1d1c223c3d2c24e3afbb2dd38be3f03b1a8d6a83ee3d9eb8c36a52bee899"}, - {file = "coverage-5.3.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9a9d4ff06804920388aab69c5ea8a77525cf165356db70131616acd269e19b36"}, - {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:782a5c7df9f91979a7a21792e09b34a658058896628217ae6362088b123c8500"}, - {file = "coverage-5.3.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:fda29412a66099af6d6de0baa6bd7c52674de177ec2ad2630ca264142d69c6c7"}, - {file = "coverage-5.3.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:f2c6888eada180814b8583c3e793f3f343a692fc802546eed45f40a001b1169f"}, - {file = "coverage-5.3.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:8f33d1156241c43755137288dea619105477961cfa7e47f48dbf96bc2c30720b"}, - {file = "coverage-5.3.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b239711e774c8eb910e9b1ac719f02f5ae4bf35fa0420f438cdc3a7e4e7dd6ec"}, - {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:f54de00baf200b4539a5a092a759f000b5f45fd226d6d25a76b0dff71177a714"}, - {file = "coverage-5.3.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:be0416074d7f253865bb67630cf7210cbc14eb05f4099cc0f82430135aaa7a3b"}, - {file = "coverage-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:c46643970dff9f5c976c6512fd35768c4a3819f01f61169d8cdac3f9290903b7"}, - {file = "coverage-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9a4f66259bdd6964d8cf26142733c81fb562252db74ea367d9beb4f815478e72"}, - {file = "coverage-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c6e5174f8ca585755988bc278c8bb5d02d9dc2e971591ef4a1baabdf2d99589b"}, - {file = "coverage-5.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3911c2ef96e5ddc748a3c8b4702c61986628bb719b8378bf1e4a6184bbd48fe4"}, - {file = "coverage-5.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c5ec71fd4a43b6d84ddb88c1df94572479d9a26ef3f150cef3dacefecf888105"}, - {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f51dbba78d68a44e99d484ca8c8f604f17e957c1ca09c3ebc2c7e3bbd9ba0448"}, - {file = "coverage-5.3.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:a2070c5affdb3a5e751f24208c5c4f3d5f008fa04d28731416e023c93b275277"}, - {file = "coverage-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:535dc1e6e68fad5355f9984d5637c33badbdc987b0c0d303ee95a6c979c9516f"}, - {file = "coverage-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a4857f7e2bc6921dbd487c5c88b84f5633de3e7d416c4dc0bb70256775551a6c"}, - {file = "coverage-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fac3c432851038b3e6afe086f777732bcf7f6ebbfd90951fa04ee53db6d0bcdd"}, - {file = "coverage-5.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cd556c79ad665faeae28020a0ab3bda6cd47d94bec48e36970719b0b86e4dcf4"}, - {file = "coverage-5.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a66ca3bdf21c653e47f726ca57f46ba7fc1f260ad99ba783acc3e58e3ebdb9ff"}, - {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ab110c48bc3d97b4d19af41865e14531f300b482da21783fdaacd159251890e8"}, - {file = "coverage-5.3.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e52d3d95df81c8f6b2a1685aabffadf2d2d9ad97203a40f8d61e51b70f191e4e"}, - {file = "coverage-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:fa10fee7e32213f5c7b0d6428ea92e3a3fdd6d725590238a3f92c0de1c78b9d2"}, - {file = "coverage-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ce6f3a147b4b1a8b09aae48517ae91139b1b010c5f36423fa2b866a8b23df879"}, - {file = "coverage-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:93a280c9eb736a0dcca19296f3c30c720cb41a71b1f9e617f341f0a8e791a69b"}, - {file = "coverage-5.3.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3102bb2c206700a7d28181dbe04d66b30780cde1d1c02c5f3c165cf3d2489497"}, - {file = "coverage-5.3.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8ffd4b204d7de77b5dd558cdff986a8274796a1e57813ed005b33fd97e29f059"}, - {file = "coverage-5.3.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a607ae05b6c96057ba86c811d9c43423f35e03874ffb03fbdcd45e0637e8b631"}, - {file = "coverage-5.3.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:3a3c3f8863255f3c31db3889f8055989527173ef6192a283eb6f4db3c579d830"}, - {file = "coverage-5.3.1-cp38-cp38-win32.whl", hash = "sha256:ff1330e8bc996570221b450e2d539134baa9465f5cb98aff0e0f73f34172e0ae"}, - {file = "coverage-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:3498b27d8236057def41de3585f317abae235dd3a11d33e01736ffedb2ef8606"}, - {file = "coverage-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ceb499d2b3d1d7b7ba23abe8bf26df5f06ba8c71127f188333dddcf356b4b63f"}, - {file = "coverage-5.3.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3b14b1da110ea50c8bcbadc3b82c3933974dbeea1832e814aab93ca1163cd4c1"}, - {file = "coverage-5.3.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:76b2775dda7e78680d688daabcb485dc87cf5e3184a0b3e012e1d40e38527cc8"}, - {file = "coverage-5.3.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:cef06fb382557f66d81d804230c11ab292d94b840b3cb7bf4450778377b592f4"}, - {file = "coverage-5.3.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f61319e33222591f885c598e3e24f6a4be3533c1d70c19e0dc59e83a71ce27d"}, - {file = "coverage-5.3.1-cp39-cp39-win32.whl", hash = "sha256:cc6f8246e74dd210d7e2b56c76ceaba1cc52b025cd75dbe96eb48791e0250e98"}, - {file = "coverage-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:2757fa64e11ec12220968f65d086b7a29b6583d16e9a544c889b22ba98555ef1"}, - {file = "coverage-5.3.1-pp36-none-any.whl", hash = "sha256:723d22d324e7997a651478e9c5a3120a0ecbc9a7e94071f7e1954562a8806cf3"}, - {file = "coverage-5.3.1-pp37-none-any.whl", hash = "sha256:c89b558f8a9a5a6f2cfc923c304d49f0ce629c3bd85cb442ca258ec20366394c"}, - {file = "coverage-5.3.1.tar.gz", hash = "sha256:38f16b1317b8dd82df67ed5daa5f5e7c959e46579840d77a67a4ceb9cef0a50b"}, + {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"}, + {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"}, + {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"}, + {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"}, + {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"}, + {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"}, + {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"}, + {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"}, + {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"}, + {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"}, + {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"}, + {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"}, + {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"}, + {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"}, + {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"}, + {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"}, + {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"}, + {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"}, + {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"}, + {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"}, + {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"}, + {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"}, + {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"}, + {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"}, + {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"}, + {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"}, + {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"}, + {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"}, + {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"}, + {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"}, + {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"}, + {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"}, + {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"}, + {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"}, + {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"}, + {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, + {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] decorator = [ - {file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"}, - {file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"}, + {file = "decorator-5.0.7-py3-none-any.whl", hash = "sha256:945d84890bb20cc4a2f4a31fc4311c0c473af65ea318617f13a7257c9a58bc98"}, + {file = "decorator-5.0.7.tar.gz", hash = "sha256:6f201a6c4dac3d187352661f508b9364ec8091217442c9478f1f83c003a0f060"}, ] distlib = [ {file = "distlib-0.3.1-py2.py3-none-any.whl", hash = "sha256:8c09de2c67b3e7deef7184574fc060ab8a793e7adbb183d942c389c8b13c52fb"}, {file = "distlib-0.3.1.zip", hash = "sha256:edf6116872c863e1aa9d5bb7cb5e05a022c519a4594dc703843343a9ddd9bff1"}, ] docutils = [ - {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, - {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, + {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, + {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] filelock = [ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, ] flake8 = [ - {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, - {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, + {file = "flake8-3.9.1-py2.py3-none-any.whl", hash = "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"}, + {file = "flake8-3.9.1.tar.gz", hash = "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378"}, ] flake8-html = [ {file = "flake8-html-0.4.1.tar.gz", hash = "sha256:2fb436cbfe1e109275bc8fb7fdd0cb00e67b3b48cfeb397309b6b2c61eeb4cb4"}, @@ -1522,106 +1372,56 @@ furo = [ {file = "furo-2020.12.30b24-py3-none-any.whl", hash = "sha256:251dadee4dee96dddf2dc9b5243b88212e16923f53397bf12bc98574918bda41"}, {file = "furo-2020.12.30b24.tar.gz", hash = "sha256:30171899c9c06d692a778e6daf6cb2e5cbb05efc6006e1692e5e776007dc8a8c"}, ] -future = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, -] identify = [ - {file = "identify-1.5.13-py2.py3-none-any.whl", hash = "sha256:9dfb63a2e871b807e3ba62f029813552a24b5289504f5b071dea9b041aee9fe4"}, - {file = "identify-1.5.13.tar.gz", hash = "sha256:70b638cf4743f33042bebb3b51e25261a0a10e80f978739f17e7fd4837664a66"}, + {file = "identify-2.2.3-py2.py3-none-any.whl", hash = "sha256:398cb92a7599da0b433c65301a1b62b9b1f4bb8248719b84736af6c0b22289d6"}, + {file = "identify-2.2.3.tar.gz", hash = "sha256:4537474817e0bbb8cea3e5b7504b7de6d44e3f169a90846cbc6adb0fc8294502"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.1-py3-none-any.whl", hash = "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16"}, + {file = "idna-3.1.tar.gz", hash = "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, - {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, + {file = "importlib_metadata-4.0.0-py3-none-any.whl", hash = "sha256:19192b88d959336bfa6bdaaaef99aeafec179eca19c47c804e555703ee5f07ef"}, + {file = "importlib_metadata-4.0.0.tar.gz", hash = "sha256:2e881981c9748d7282b374b68e759c87745c25427b67ecf0cc67fb6637a1bff9"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] ipython = [ - {file = "ipython-7.19.0-py3-none-any.whl", hash = "sha256:c987e8178ced651532b3b1ff9965925bfd445c279239697052561a9ab806d28f"}, - {file = "ipython-7.19.0.tar.gz", hash = "sha256:cbb2ef3d5961d44e6a963b9817d4ea4e1fa2eb589c371a470fed14d8d40cbd6a"}, + {file = "ipython-7.22.0-py3-none-any.whl", hash = "sha256:c0ce02dfaa5f854809ab7413c601c4543846d9da81010258ecdab299b542d199"}, + {file = "ipython-7.22.0.tar.gz", hash = "sha256:9c900332d4c5a6de534b4befeeb7de44ad0cc42e8327fa41b7685abde58cec74"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, ] isort = [ - {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, - {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, + {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, + {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, ] jedi = [ {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, ] jinja2 = [ - {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, - {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, -] -joblib = [ - {file = "joblib-1.0.0-py3-none-any.whl", hash = "sha256:75ead23f13484a2a414874779d69ade40d4fa1abe62b222a23cd50d4bc822f6f"}, - {file = "joblib-1.0.0.tar.gz", hash = "sha256:7ad866067ac1fdec27d51c8678ea760601b70e32ff1881d4dc8e1171f2b64b24"}, + {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, + {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, ] livereload = [ {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, ] -lunr = [ - {file = "lunr-0.5.8-py2.py3-none-any.whl", hash = "sha256:aab3f489c4d4fab4c1294a257a30fec397db56f0a50273218ccc3efdbf01d6ca"}, - {file = "lunr-0.5.8.tar.gz", hash = "sha256:c4fb063b98eff775dd638b3df380008ae85e6cb1d1a24d1cd81a10ef6391c26e"}, -] -lxml = [ - {file = "lxml-4.6.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a9d6bc8642e2c67db33f1247a77c53476f3a166e09067c0474facb045756087f"}, - {file = "lxml-4.6.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:791394449e98243839fa822a637177dd42a95f4883ad3dec2a0ce6ac99fb0a9d"}, - {file = "lxml-4.6.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:68a5d77e440df94011214b7db907ec8f19e439507a70c958f750c18d88f995d2"}, - {file = "lxml-4.6.2-cp27-cp27m-win32.whl", hash = "sha256:fc37870d6716b137e80d19241d0e2cff7a7643b925dfa49b4c8ebd1295eb506e"}, - {file = "lxml-4.6.2-cp27-cp27m-win_amd64.whl", hash = "sha256:69a63f83e88138ab7642d8f61418cf3180a4d8cd13995df87725cb8b893e950e"}, - {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:42ebca24ba2a21065fb546f3e6bd0c58c3fe9ac298f3a320147029a4850f51a2"}, - {file = "lxml-4.6.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f83d281bb2a6217cd806f4cf0ddded436790e66f393e124dfe9731f6b3fb9afe"}, - {file = "lxml-4.6.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:535f067002b0fd1a4e5296a8f1bf88193080ff992a195e66964ef2a6cfec5388"}, - {file = "lxml-4.6.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:366cb750140f221523fa062d641393092813b81e15d0e25d9f7c6025f910ee80"}, - {file = "lxml-4.6.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:97db258793d193c7b62d4e2586c6ed98d51086e93f9a3af2b2034af01450a74b"}, - {file = "lxml-4.6.2-cp35-cp35m-win32.whl", hash = "sha256:648914abafe67f11be7d93c1a546068f8eff3c5fa938e1f94509e4a5d682b2d8"}, - {file = "lxml-4.6.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e751e77006da34643ab782e4a5cc21ea7b755551db202bc4d3a423b307db780"}, - {file = "lxml-4.6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:681d75e1a38a69f1e64ab82fe4b1ed3fd758717bed735fb9aeaa124143f051af"}, - {file = "lxml-4.6.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:127f76864468d6630e1b453d3ffbbd04b024c674f55cf0a30dc2595137892d37"}, - {file = "lxml-4.6.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4fb85c447e288df535b17ebdebf0ec1cf3a3f1a8eba7e79169f4f37af43c6b98"}, - {file = "lxml-4.6.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5be4a2e212bb6aa045e37f7d48e3e1e4b6fd259882ed5a00786f82e8c37ce77d"}, - {file = "lxml-4.6.2-cp36-cp36m-win32.whl", hash = "sha256:8c88b599e226994ad4db29d93bc149aa1aff3dc3a4355dd5757569ba78632bdf"}, - {file = "lxml-4.6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:6e4183800f16f3679076dfa8abf2db3083919d7e30764a069fb66b2b9eff9939"}, - {file = "lxml-4.6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d8d3d4713f0c28bdc6c806a278d998546e8efc3498949e3ace6e117462ac0a5e"}, - {file = "lxml-4.6.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8246f30ca34dc712ab07e51dc34fea883c00b7ccb0e614651e49da2c49a30711"}, - {file = "lxml-4.6.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:923963e989ffbceaa210ac37afc9b906acebe945d2723e9679b643513837b089"}, - {file = "lxml-4.6.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1471cee35eba321827d7d53d104e7b8c593ea3ad376aa2df89533ce8e1b24a01"}, - {file = "lxml-4.6.2-cp37-cp37m-win32.whl", hash = "sha256:2363c35637d2d9d6f26f60a208819e7eafc4305ce39dc1d5005eccc4593331c2"}, - {file = "lxml-4.6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4822c0660c3754f1a41a655e37cb4dbbc9be3d35b125a37fab6f82d47674ebc"}, - {file = "lxml-4.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0448576c148c129594d890265b1a83b9cd76fd1f0a6a04620753d9a6bcfd0a4d"}, - {file = "lxml-4.6.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:60a20bfc3bd234d54d49c388950195d23a5583d4108e1a1d47c9eef8d8c042b3"}, - {file = "lxml-4.6.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2e5cc908fe43fe1aa299e58046ad66981131a66aea3129aac7770c37f590a644"}, - {file = "lxml-4.6.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:50c348995b47b5a4e330362cf39fc503b4a43b14a91c34c83b955e1805c8e308"}, - {file = "lxml-4.6.2-cp38-cp38-win32.whl", hash = "sha256:94d55bd03d8671686e3f012577d9caa5421a07286dd351dfef64791cf7c6c505"}, - {file = "lxml-4.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:7a7669ff50f41225ca5d6ee0a1ec8413f3a0d8aa2b109f86d540887b7ec0d72a"}, - {file = "lxml-4.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0bfe9bb028974a481410432dbe1b182e8191d5d40382e5b8ff39cdd2e5c5931"}, - {file = "lxml-4.6.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6fd8d5903c2e53f49e99359b063df27fdf7acb89a52b6a12494208bf61345a03"}, - {file = "lxml-4.6.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7e9eac1e526386df7c70ef253b792a0a12dd86d833b1d329e038c7a235dfceb5"}, - {file = "lxml-4.6.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ee8af0b9f7de635c61cdd5b8534b76c52cd03536f29f51151b377f76e214a1a"}, - {file = "lxml-4.6.2-cp39-cp39-win32.whl", hash = "sha256:2e6fd1b8acd005bd71e6c94f30c055594bbd0aa02ef51a22bbfa961ab63b2d75"}, - {file = "lxml-4.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:535332fe9d00c3cd455bd3dd7d4bacab86e2d564bdf7606079160fa6251caacf"}, - {file = "lxml-4.6.2.tar.gz", hash = "sha256:cd11c7e8d21af997ee8079037fff88f16fda188a9776eb4b81c7e4c9c0a7d7fc"}, -] magic-filter = [ - {file = "magic-filter-0.1.2.tar.gz", hash = "sha256:dfd1a778493083ac1355791d1716c3beb6629598739f2c2ec078815952282c1d"}, - {file = "magic_filter-0.1.2-py3-none-any.whl", hash = "sha256:16d0c96584f0660fd7fa94b6cd16f92383616208a32568bf8f95a57fc1a69e9d"}, + {file = "magic-filter-1.0.0a1.tar.gz", hash = "sha256:af77522f1ab2a7aac6a960fb731097ada793da18f7ad96b1e29c11bd9c2d09cd"}, + {file = "magic_filter-1.0.0a1-py3-none-any.whl", hash = "sha256:ae4268493a6955887b63d1deb6f9409c063c7518d5e4bc6feb1dc1ce7ac61a0d"}, ] markdown = [ - {file = "Markdown-3.3.3-py3-none-any.whl", hash = "sha256:c109c15b7dc20a9ac454c9e6025927d44460b85bd039da028d85e2b6d0bcc328"}, - {file = "Markdown-3.3.3.tar.gz", hash = "sha256:5d9f2b5ca24bc4c7a390d22323ca4bad200368612b5aaa7796babf971d2b2f18"}, + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, ] markdown-include = [ {file = "markdown-include-0.6.0.tar.gz", hash = "sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2"}, @@ -1645,41 +1445,45 @@ markupsafe = [ {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, + {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] -mkautodoc = [ - {file = "mkautodoc-0.1.0.tar.gz", hash = "sha256:7c2595f40276b356e576ce7e343338f8b4fa1e02ea904edf33fadf82b68ca67c"}, -] -mkdocs = [ - {file = "mkdocs-1.1.2-py3-none-any.whl", hash = "sha256:096f52ff52c02c7e90332d2e53da862fde5c062086e1b5356a6e392d5d60f5e9"}, - {file = "mkdocs-1.1.2.tar.gz", hash = "sha256:f0b61e5402b99d7789efa032c7a74c90a20220a9c81749da06dbfbcbd52ffb39"}, -] -mkdocs-material = [ - {file = "mkdocs-material-6.2.5.tar.gz", hash = "sha256:26900f51e177eb7dcfc8140ffe33c71b22ffa2920271e093679f0670b78e7e8b"}, - {file = "mkdocs_material-6.2.5-py2.py3-none-any.whl", hash = "sha256:04574cbaeb12671da66cd58904d6066dd269239f4a1bdb819c2c6e1ac9d9947a"}, -] -mkdocs-material-extensions = [ - {file = "mkdocs-material-extensions-1.0.1.tar.gz", hash = "sha256:6947fb7f5e4291e3c61405bad3539d81e0b3cd62ae0d66ced018128af509c68f"}, - {file = "mkdocs_material_extensions-1.0.1-py3-none-any.whl", hash = "sha256:d90c807a88348aa6d1805657ec5c0b2d8d609c110e62b9dce4daf7fa981fa338"}, -] multidict = [ {file = "multidict-5.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f"}, {file = "multidict-5.1.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf"}, @@ -1720,47 +1524,44 @@ multidict = [ {file = "multidict-5.1.0.tar.gz", hash = "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5"}, ] mypy = [ - {file = "mypy-0.800-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:e1c84c65ff6d69fb42958ece5b1255394714e0aac4df5ffe151bc4fe19c7600a"}, - {file = "mypy-0.800-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:947126195bfe4709c360e89b40114c6746ae248f04d379dca6f6ab677aa07641"}, - {file = "mypy-0.800-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:b95068a3ce3b50332c40e31a955653be245666a4bc7819d3c8898aa9fb9ea496"}, - {file = "mypy-0.800-cp35-cp35m-win_amd64.whl", hash = "sha256:ca7ad5aed210841f1e77f5f2f7d725b62c78fa77519312042c719ed2ab937876"}, - {file = "mypy-0.800-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e32b7b282c4ed4e378bba8b8dfa08e1cfa6f6574067ef22f86bee5b1039de0c9"}, - {file = "mypy-0.800-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e497a544391f733eca922fdcb326d19e894789cd4ff61d48b4b195776476c5cf"}, - {file = "mypy-0.800-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:5615785d3e2f4f03ab7697983d82c4b98af5c321614f51b8f1034eb9ebe48363"}, - {file = "mypy-0.800-cp36-cp36m-win_amd64.whl", hash = "sha256:2b216eacca0ec0ee124af9429bfd858d5619a0725ee5f88057e6e076f9eb1a7b"}, - {file = "mypy-0.800-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e3b8432f8df19e3c11235c4563a7250666dc9aa7cdda58d21b4177b20256ca9f"}, - {file = "mypy-0.800-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d16c54b0dffb861dc6318a8730952265876d90c5101085a4bc56913e8521ba19"}, - {file = "mypy-0.800-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d2fc8beb99cd88f2d7e20d69131353053fbecea17904ee6f0348759302c52fa"}, - {file = "mypy-0.800-cp37-cp37m-win_amd64.whl", hash = "sha256:aa9d4901f3ee1a986a3a79fe079ffbf7f999478c281376f48faa31daaa814e86"}, - {file = "mypy-0.800-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:319ee5c248a7c3f94477f92a729b7ab06bf8a6d04447ef3aa8c9ba2aa47c6dcf"}, - {file = "mypy-0.800-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:74f5aa50d0866bc6fb8e213441c41e466c86678c800700b87b012ed11c0a13e0"}, - {file = "mypy-0.800-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a301da58d566aca05f8f449403c710c50a9860782148332322decf73a603280b"}, - {file = "mypy-0.800-cp38-cp38-win_amd64.whl", hash = "sha256:b9150db14a48a8fa114189bfe49baccdff89da8c6639c2717750c7ae62316738"}, - {file = "mypy-0.800-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5fdf935a46aa20aa937f2478480ebf4be9186e98e49cc3843af9a5795a49a25"}, - {file = "mypy-0.800-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6f8425fecd2ba6007e526209bb985ce7f49ed0d2ac1cc1a44f243380a06a84fb"}, - {file = "mypy-0.800-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5ff616787122774f510caeb7b980542a7cc2222be3f00837a304ea85cd56e488"}, - {file = "mypy-0.800-cp39-cp39-win_amd64.whl", hash = "sha256:90b6f46dc2181d74f80617deca611925d7e63007cf416397358aa42efb593e07"}, - {file = "mypy-0.800-py3-none-any.whl", hash = "sha256:3e0c159a7853e3521e3f582adb1f3eac66d0b0639d434278e2867af3a8c62653"}, - {file = "mypy-0.800.tar.gz", hash = "sha256:e0202e37756ed09daf4b0ba64ad2c245d357659e014c3f51d8cd0681ba66940a"}, + {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, + {file = "mypy-0.812-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c"}, + {file = "mypy-0.812-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521"}, + {file = "mypy-0.812-cp35-cp35m-win_amd64.whl", hash = "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"}, + {file = "mypy-0.812-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a"}, + {file = "mypy-0.812-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c"}, + {file = "mypy-0.812-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6"}, + {file = "mypy-0.812-cp36-cp36m-win_amd64.whl", hash = "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064"}, + {file = "mypy-0.812-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56"}, + {file = "mypy-0.812-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8"}, + {file = "mypy-0.812-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7"}, + {file = "mypy-0.812-cp37-cp37m-win_amd64.whl", hash = "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564"}, + {file = "mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506"}, + {file = "mypy-0.812-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5"}, + {file = "mypy-0.812-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66"}, + {file = "mypy-0.812-cp38-cp38-win_amd64.whl", hash = "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e"}, + {file = "mypy-0.812-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a"}, + {file = "mypy-0.812-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a"}, + {file = "mypy-0.812-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97"}, + {file = "mypy-0.812-cp39-cp39-win_amd64.whl", hash = "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df"}, + {file = "mypy-0.812-py3-none-any.whl", hash = "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4"}, + {file = "mypy-0.812.tar.gz", hash = "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] -nltk = [ - {file = "nltk-3.5.zip", hash = "sha256:845365449cd8c5f9731f7cb9f8bd6fd0767553b9d53af9eb1b3abf7700936b35"}, -] nodeenv = [ - {file = "nodeenv-1.5.0-py2.py3-none-any.whl", hash = "sha256:5304d424c529c997bc888453aeaa6362d242b6b4631e90f3d4bf1b290f1c84a9"}, - {file = "nodeenv-1.5.0.tar.gz", hash = "sha256:ab45090ae383b716c4ef89e690c41ff8c2b257b85b309f01f3654df3d084bd7c"}, + {file = "nodeenv-1.6.0-py2.py3-none-any.whl", hash = "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7"}, + {file = "nodeenv-1.6.0.tar.gz", hash = "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b"}, ] packaging = [ - {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, - {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, + {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, + {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] parso = [ - {file = "parso-0.8.1-py2.py3-none-any.whl", hash = "sha256:15b00182f472319383252c18d5913b69269590616c947747bc50bf4ac768f410"}, - {file = "parso-0.8.1.tar.gz", hash = "sha256:8519430ad07087d4c997fda3a7918f7cfa27cb58972a8c89c2a0295a1c940e9e"}, + {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, + {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, ] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, @@ -1779,12 +1580,12 @@ pluggy = [ {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] pre-commit = [ - {file = "pre_commit-2.9.3-py2.py3-none-any.whl", hash = "sha256:6c86d977d00ddc8a60d68eec19f51ef212d9462937acf3ea37c7adec32284ac0"}, - {file = "pre_commit-2.9.3.tar.gz", hash = "sha256:ee784c11953e6d8badb97d19bc46b997a3a9eded849881ec587accd8608d74a4"}, + {file = "pre_commit-2.12.1-py2.py3-none-any.whl", hash = "sha256:70c5ec1f30406250b706eda35e868b87e3e4ba099af8787e3e8b4b01e84f4712"}, + {file = "pre_commit-2.12.1.tar.gz", hash = "sha256:900d3c7e1bf4cf0374bb2893c24c23304952181405b4d88c9c40b72bda1bb8a9"}, ] prompt-toolkit = [ - {file = "prompt_toolkit-3.0.14-py3-none-any.whl", hash = "sha256:c96b30925025a7635471dc083ffb6af0cc67482a00611bd81aeaeeeb7e5a5e12"}, - {file = "prompt_toolkit-3.0.14.tar.gz", hash = "sha256:7e966747c18ececaec785699626b771c1ba8344c8d31759a1915d6b12fad6525"}, + {file = "prompt_toolkit-3.0.18-py3-none-any.whl", hash = "sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04"}, + {file = "prompt_toolkit-3.0.18.tar.gz", hash = "sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"}, ] ptyprocess = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, @@ -1795,56 +1596,56 @@ py = [ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pycodestyle = [ - {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, - {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, + {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, + {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, ] pydantic = [ - {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"}, - {file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"}, - {file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"}, - {file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"}, - {file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"}, - {file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"}, - {file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"}, - {file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"}, - {file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"}, - {file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"}, + {file = "pydantic-1.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0c40162796fc8d0aa744875b60e4dc36834db9f2a25dbf9ba9664b1915a23850"}, + {file = "pydantic-1.8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fff29fe54ec419338c522b908154a2efabeee4f483e48990f87e189661f31ce3"}, + {file = "pydantic-1.8.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:fbfb608febde1afd4743c6822c19060a8dbdd3eb30f98e36061ba4973308059e"}, + {file = "pydantic-1.8.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:eb8ccf12295113ce0de38f80b25f736d62f0a8d87c6b88aca645f168f9c78771"}, + {file = "pydantic-1.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:20d42f1be7c7acc352b3d09b0cf505a9fab9deb93125061b376fbe1f06a5459f"}, + {file = "pydantic-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dde4ca368e82791de97c2ec019681ffb437728090c0ff0c3852708cf923e0c7d"}, + {file = "pydantic-1.8.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:3bbd023c981cbe26e6e21c8d2ce78485f85c2e77f7bab5ec15b7d2a1f491918f"}, + {file = "pydantic-1.8.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:830ef1a148012b640186bf4d9789a206c56071ff38f2460a32ae67ca21880eb8"}, + {file = "pydantic-1.8.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:fb77f7a7e111db1832ae3f8f44203691e15b1fa7e5a1cb9691d4e2659aee41c4"}, + {file = "pydantic-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3bcb9d7e1f9849a6bdbd027aabb3a06414abd6068cb3b21c49427956cce5038a"}, + {file = "pydantic-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2287ebff0018eec3cc69b1d09d4b7cebf277726fa1bd96b45806283c1d808683"}, + {file = "pydantic-1.8.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4bbc47cf7925c86a345d03b07086696ed916c7663cb76aa409edaa54546e53e2"}, + {file = "pydantic-1.8.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6388ef4ef1435364c8cc9a8192238aed030595e873d8462447ccef2e17387125"}, + {file = "pydantic-1.8.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:dd4888b300769ecec194ca8f2699415f5f7760365ddbe243d4fd6581485fa5f0"}, + {file = "pydantic-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:8fbb677e4e89c8ab3d450df7b1d9caed23f254072e8597c33279460eeae59b99"}, + {file = "pydantic-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2f2736d9a996b976cfdfe52455ad27462308c9d3d0ae21a2aa8b4cd1a78f47b9"}, + {file = "pydantic-1.8.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:3114d74329873af0a0e8004627f5389f3bb27f956b965ddd3e355fe984a1789c"}, + {file = "pydantic-1.8.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:258576f2d997ee4573469633592e8b99aa13bda182fcc28e875f866016c8e07e"}, + {file = "pydantic-1.8.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c17a0b35c854049e67c68b48d55e026c84f35593c66d69b278b8b49e2484346f"}, + {file = "pydantic-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8bc082afef97c5fd3903d05c6f7bb3a6af9fc18631b4cc9fedeb4720efb0c58"}, + {file = "pydantic-1.8.1-py3-none-any.whl", hash = "sha256:e3f8790c47ac42549dc8b045a67b0ca371c7f66e73040d0197ce6172b385e520"}, + {file = "pydantic-1.8.1.tar.gz", hash = "sha256:26cf3cb2e68ec6c0cfcb6293e69fb3450c5fd1ace87f46b64f678b0d29eac4c3"}, ] pyflakes = [ - {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, - {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, + {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, + {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.7.4-py3-none-any.whl", hash = "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435"}, - {file = "Pygments-2.7.4.tar.gz", hash = "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337"}, + {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"}, + {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"}, ] pymdown-extensions = [ - {file = "pymdown-extensions-8.1.tar.gz", hash = "sha256:565583c5964ac8253896ef4a7f14023075503ca6514d7d470b343290b96fc6da"}, - {file = "pymdown_extensions-8.1-py2.py3-none-any.whl", hash = "sha256:c0b285fdd6e8438895b0c4422847af012f32a487ae083ffafa4c21a151b4983b"}, + {file = "pymdown-extensions-8.1.1.tar.gz", hash = "sha256:632371fa3bf1b21a0e3f4063010da59b41db049f261f4c0b0872069a9b6d1735"}, + {file = "pymdown_extensions-8.1.1-py3-none-any.whl", hash = "sha256:478b2c04513fbb2db61688d5f6e9030a92fb9be14f1f383535c43f7be9dff95b"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pytest = [ - {file = "pytest-6.2.1-py3-none-any.whl", hash = "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8"}, - {file = "pytest-6.2.1.tar.gz", hash = "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"}, + {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"}, + {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.14.0.tar.gz", hash = "sha256:9882c0c6b24429449f5f969a5158b528f39bde47dc32e85b9f0403965017e700"}, - {file = "pytest_asyncio-0.14.0-py3-none-any.whl", hash = "sha256:2eae1e34f6c68fc0a9dc12d4bea190483843ff4708d24277c41568d6b6044f1d"}, + {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, + {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, ] pytest-cov = [ {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"}, @@ -1859,20 +1660,20 @@ pytest-metadata = [ {file = "pytest_metadata-1.11.0-py2.py3-none-any.whl", hash = "sha256:576055b8336dd4a9006dd2a47615f76f2f8c30ab12b1b1c039d99e834583523f"}, ] pytest-mock = [ - {file = "pytest-mock-3.5.1.tar.gz", hash = "sha256:a1e2aba6af9560d313c642dae7e00a2a12b022b80301d9d7fc8ec6858e1dd9fc"}, - {file = "pytest_mock-3.5.1-py3-none-any.whl", hash = "sha256:379b391cfad22422ea2e252bdfc008edd08509029bcde3c25b2c0bd741e0424e"}, + {file = "pytest-mock-3.6.0.tar.gz", hash = "sha256:f7c3d42d6287f4e45846c8231c31902b6fa2bea98735af413a43da4cf5b727f1"}, + {file = "pytest_mock-3.6.0-py3-none-any.whl", hash = "sha256:952139a535b5b48ac0bb2f90b5dd36b67c7e1ba92601f3a8012678c4bd7f0bcc"}, ] pytest-mypy = [ - {file = "pytest-mypy-0.8.0.tar.gz", hash = "sha256:63d418a4fea7d598ac40b659723c00804d16a251d90a5cfbca213eeba5aaf01c"}, - {file = "pytest_mypy-0.8.0-py3-none-any.whl", hash = "sha256:8d2112972c1debf087943f48963a0daf04f3424840aea0cf437cc97053b1b0ef"}, + {file = "pytest-mypy-0.8.1.tar.gz", hash = "sha256:1fa55723a4bf1d054fcba1c3bd694215a2a65cc95ab10164f5808afd893f3b11"}, + {file = "pytest_mypy-0.8.1-py3-none-any.whl", hash = "sha256:6e68e8eb7ceeb7d1c83a1590912f784879f037b51adfb9c17b95c6b2fc57466b"}, ] python-socks = [ - {file = "python-socks-1.2.0.tar.gz", hash = "sha256:3054a8afa984a35144198e00fed1144eeae3287cc231ac7db3908d32ab642cd4"}, - {file = "python_socks-1.2.0-py3-none-any.whl", hash = "sha256:26e45b29e18ab7a28ad646e82d3e47a32fe13942b0b1c75ae3f6fe9e5c03efcb"}, + {file = "python-socks-1.2.4.tar.gz", hash = "sha256:7d0ef2578cead9f762b71317d25a6c118fabaf79535555e75b3e102f5158ddd8"}, + {file = "python_socks-1.2.4-py3-none-any.whl", hash = "sha256:9f12e8fe78629b87543fad0e4ea0ccf103a4fad6a7872c5d0ecb36d9903fa548"}, ] pytz = [ - {file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"}, - {file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"}, + {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, + {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, ] pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, @@ -1881,68 +1682,76 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] regex = [ - {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, - {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, - {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, - {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, - {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, - {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, - {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, - {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, - {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, - {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, - {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, - {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, - {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, + {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"}, + {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"}, + {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"}, + {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"}, + {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"}, + {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"}, + {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"}, + {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"}, + {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"}, + {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"}, + {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"}, + {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"}, + {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"}, ] requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.15.1-py2.py3-none-any.whl", hash = "sha256:ff753b2196cd18b1bbeddc9dcd5c864056599f7a7d9a4fb5677e723efa2b7fb9"}, + {file = "requests-2.15.1.tar.gz", hash = "sha256:e5659b9315a0610505e050bb7190bf6fa2ccee1ac295f2b760ef9d8a03ebbb2e"}, ] six = [ {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, @@ -1953,12 +1762,12 @@ snowballstemmer = [ {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, ] soupsieve = [ - {file = "soupsieve-2.1-py3-none-any.whl", hash = "sha256:4bb21a6ee4707bf43b61230e80740e71bfe56e55d1f1f50924b087bb2975c851"}, - {file = "soupsieve-2.1.tar.gz", hash = "sha256:6dc52924dc0bc710a5d16794e6b3480b2c7c08b07729505feab2b2c16661ff6e"}, + {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, + {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, ] sphinx = [ - {file = "Sphinx-3.4.3-py3-none-any.whl", hash = "sha256:c314c857e7cd47c856d2c5adff514ac2e6495f8b8e0f886a8a37e9305dfea0d8"}, - {file = "Sphinx-3.4.3.tar.gz", hash = "sha256:41cad293f954f7d37f803d97eb184158cfd90f51195131e94875bc07cd08b93c"}, + {file = "Sphinx-3.5.3-py3-none-any.whl", hash = "sha256:3f01732296465648da43dec8fb40dc451ba79eb3e2cc5c6d79005fd98197107d"}, + {file = "Sphinx-3.5.3.tar.gz", hash = "sha256:ce9c228456131bab09a3d7d10ae58474de562a6f79abb3dc811ae401cf8c1abc"}, ] sphinx-autobuild = [ {file = "sphinx-autobuild-2020.9.1.tar.gz", hash = "sha256:4b184a7db893f2100bbd831991ae54ca89167a2b9ce68faea71eaa9e37716aed"}, @@ -1973,8 +1782,8 @@ sphinx-intl = [ {file = "sphinx_intl-2.0.1-py3.8.egg", hash = "sha256:2ff97cba0e4e43249e339a3c29dd2f5b63c25ce794050aabca320ad95f5c5b55"}, ] sphinx-prompt = [ - {file = "sphinx-prompt-1.3.0.tar.gz", hash = "sha256:859f49774865ec06d0e24fa6d80dbe2cbc2922cf82c1a6869ff39ea1f14da9d1"}, - {file = "sphinx_prompt-1.3.0-py3-none-any.whl", hash = "sha256:f3d2389c55dadc790e10a936bf889706671538af442078d3f9dea634adf81d0b"}, + {file = "sphinx-prompt-1.4.0.tar.gz", hash = "sha256:70c8e66d1f36def1e295ed961c7562bbf8fc697eea5191b92b41e4784c264ef5"}, + {file = "sphinx_prompt-1.4.0-py3-none-any.whl", hash = "sha256:ac54b204c3e0ff75851d92060672b65407ff67f8942bde2eb6ba318b8e7ca595"}, ] sphinx-substitution-extensions = [ {file = "Sphinx Substitution Extensions-2020.9.30.0.tar.gz", hash = "sha256:578afc04eb4f701d9a922f8b75f678d3a1a897fa7a172a9226b92f17553f177a"}, @@ -2051,69 +1860,62 @@ tornado = [ {file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"}, {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"}, ] -tqdm = [ - {file = "tqdm-4.56.0-py2.py3-none-any.whl", hash = "sha256:4621f6823bab46a9cc33d48105753ccbea671b68bab2c50a9f0be23d4065cb5a"}, - {file = "tqdm-4.56.0.tar.gz", hash = "sha256:fe3d08dd00a526850568d542ff9de9bbc2a09a791da3c334f3213d8d0bbbca65"}, -] traitlets = [ {file = "traitlets-5.0.5-py3-none-any.whl", hash = "sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"}, {file = "traitlets-5.0.5.tar.gz", hash = "sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396"}, ] typed-ast = [ - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, - {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, - {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, - {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, - {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, - {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, - {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, - {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, - {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, - {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, - {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, - {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, - {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, - {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, - {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, - {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] -urllib3 = [ - {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, - {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, -] uvloop = [ - {file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"}, - {file = "uvloop-0.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726"}, - {file = "uvloop-0.14.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7"}, - {file = "uvloop-0.14.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"}, - {file = "uvloop-0.14.0-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891"}, - {file = "uvloop-0.14.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95"}, - {file = "uvloop-0.14.0-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5"}, - {file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"}, - {file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"}, + {file = "uvloop-0.15.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:19fa1d56c91341318ac5d417e7b61c56e9a41183946cc70c411341173de02c69"}, + {file = "uvloop-0.15.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e5e5f855c9bf483ee6cd1eb9a179b740de80cb0ae2988e3fa22309b78e2ea0e7"}, + {file = "uvloop-0.15.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:42eda9f525a208fbc4f7cecd00fa15c57cc57646c76632b3ba2fe005004f051d"}, + {file = "uvloop-0.15.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:90e56f17755e41b425ad19a08c41dc358fa7bf1226c0f8e54d4d02d556f7af7c"}, + {file = "uvloop-0.15.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7ae39b11a5f4cec1432d706c21ecc62f9e04d116883178b09671aa29c46f7a47"}, + {file = "uvloop-0.15.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b45218c99795803fb8bdbc9435ff7f54e3a591b44cd4c121b02fa83affb61c7c"}, + {file = "uvloop-0.15.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:114543c84e95df1b4ff546e6e3a27521580466a30127f12172a3278172ad68bc"}, + {file = "uvloop-0.15.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44cac8575bf168601424302045234d74e3561fbdbac39b2b54cc1d1d00b70760"}, + {file = "uvloop-0.15.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:6de130d0cb78985a5d080e323b86c5ecaf3af82f4890492c05981707852f983c"}, + {file = "uvloop-0.15.2.tar.gz", hash = "sha256:2bb0624a8a70834e54dde8feed62ed63b50bad7a1265c40d6403a2ac447bce01"}, ] virtualenv = [ - {file = "virtualenv-20.4.0-py2.py3-none-any.whl", hash = "sha256:227a8fed626f2f20a6cdb0870054989f82dd27b2560a911935ba905a2a5e0034"}, - {file = "virtualenv-20.4.0.tar.gz", hash = "sha256:219ee956e38b08e32d5639289aaa5bd190cfbe7dafcb8fa65407fca08e808f9c"}, + {file = "virtualenv-20.4.3-py2.py3-none-any.whl", hash = "sha256:83f95875d382c7abafe06bd2a4cdd1b363e1bb77e02f155ebe8ac082a916b37c"}, + {file = "virtualenv-20.4.3.tar.gz", hash = "sha256:49ec4eb4c224c6f7dd81bb6d0a28a09ecae5894f4e593c89b0db0885f565a107"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, @@ -2159,6 +1961,6 @@ yarl = [ {file = "yarl-1.6.3.tar.gz", hash = "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, + {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, ] diff --git a/pyproject.toml b/pyproject.toml index a27f8059..b465f2a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "aiogram" -version = "3.0.0-alpha.6" +version = "3.0.0-alpha.7" description = "Modern and fully asynchronous framework for Telegram Bot API" authors = ["Alex Root Junior "] license = "MIT" @@ -33,15 +33,14 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.7" -aiohttp = "^3.6" -pydantic = "^1.5" -Babel = "^2.7" +aiohttp = "^3.7.4" +pydantic = "^1.8.1" +Babel = "^2.9.1" aiofiles = "^0.6.0" -uvloop = { version = "^0.14.0", markers = "sys_platform == 'darwin' or sys_platform == 'linux'", optional = true } -async_lru = "^1.0" +async_lru = "^1.0.2" aiohttp-socks = { version = "^0.5.5", optional = true } typing-extensions = { version = "^3.7.4", python = "<3.8" } -magic-filter = "^0.1.2" +magic-filter = {version = "1.0.0a1", allow-prereleases = true} sphinx = { version = "^3.1.0", optional = true } sphinx-intl = { version = "^2.0.1", optional = true } sphinx-autobuild = { version = "^2020.9.1", optional = true } @@ -51,28 +50,26 @@ sphinx-prompt = { version = "^1.3.0", optional = true } Sphinx-Substitution-Extensions = { version = "^2020.9.30", optional = true } [tool.poetry.dev-dependencies] -uvloop = { version = "^0.14.0", markers = "sys_platform == 'darwin' or sys_platform == 'linux'" } -pytest = "^6.1" -pytest-html = "^3.1" -pytest-asyncio = "^0.14.0" -pytest-mypy = "^0.8" -pytest-mock = "^3.3" -pytest-cov = "^2.8" -aresponses = "^2.0" -asynctest = { version = "^0.13.0", python = "<3.8" } -isort = "^5.6" -flake8 = "^3.7" -flake8-html = "^0.4.0" -mypy = "^0.800" -mkdocs = "^1.0" -mkdocs-material = "^6.1" -mkautodoc = "^0.1.0" +aiohttp-socks = "^0.5" +ipython = "^7.22.0" +uvloop = { version = "^0.15.2", markers = "sys_platform == 'darwin' or sys_platform == 'linux'" } +black = "^21.4b2" +isort = "^5.8.0" +flake8 = "^3.9.1" +flake8-html = "^0.4.1" +mypy = "^0.812" +pytest = "^6.2.3" +pytest-html = "^3.1.1" +pytest-asyncio = "^0.15.1" +pytest-mypy = "^0.8.1" +pytest-mock = "^3.6.0" +pytest-cov = "^2.11.1" +aresponses = "^2.1.4" +asynctest = "^0.13.0" +toml = "^0.10.2" pygments = "^2.4" pymdown-extensions = "^8.0" -lxml = "^4.4" -ipython = "^7.10" markdown-include = "^0.6" -aiohttp-socks = "^0.5" pre-commit = "^2.3.0" packaging = "^20.3" typing-extensions = "^3.7.4" @@ -83,8 +80,6 @@ sphinx-copybutton = "^0.3.1" furo = "^2020.11.15-beta.17" sphinx-prompt = "^1.3.0" Sphinx-Substitution-Extensions = "^2020.9.30" -black = "^20.8b1" -toml = "^0.10.2" [tool.poetry.extras] fast = ["uvloop"] diff --git a/tests/test_api/test_types/test_message.py b/tests/test_api/test_types/test_message.py index a6cf235e..15ea6087 100644 --- a/tests/test_api/test_types/test_message.py +++ b/tests/test_api/test_types/test_message.py @@ -1,5 +1,5 @@ import datetime -from typing import Any, Dict, Type, Union +from typing import Any, Dict, Type, Union, Optional import pytest @@ -21,6 +21,8 @@ from aiogram.methods import ( SendVideo, SendVideoNote, SendVoice, + CopyMessage, + TelegramMethod, ) from aiogram.types import ( Animation, @@ -44,374 +46,334 @@ from aiogram.types import ( Video, VideoNote, Voice, + MessageAutoDeleteTimerChanged, + VoiceChatStarted, + VoiceChatEnded, + VoiceChatParticipantsInvited, ) from aiogram.types.message import ContentType, Message +TEST_MESSAGE_TEXT = Message( + message_id=42, + date=datetime.datetime.now(), + text="test", + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_AUDIO = Message( + message_id=42, + date=datetime.datetime.now(), + audio=Audio(file_id="file id", file_unique_id="file id", duration=42), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_ANIMATION = Message( + message_id=42, + date=datetime.datetime.now(), + animation=Animation( + file_id="file id", file_unique_id="file id", width=42, height=42, duration=0, + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_DOCUMENT = Message( + message_id=42, + date=datetime.datetime.now(), + document=Document(file_id="file id", file_unique_id="file id"), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_GAME = Message( + message_id=42, + date=datetime.datetime.now(), + game=Game( + title="title", + description="description", + photo=[PhotoSize(file_id="file id", file_unique_id="file id", width=42, height=42)], + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_PHOTO = Message( + message_id=42, + date=datetime.datetime.now(), + photo=[PhotoSize(file_id="file id", file_unique_id="file id", width=42, height=42)], + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) + +TEST_MESSAGE_STICKER = Message( + message_id=42, + date=datetime.datetime.now(), + sticker=Sticker( + file_id="file id", file_unique_id="file id", width=42, height=42, is_animated=False, + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_VIDEO = Message( + message_id=42, + date=datetime.datetime.now(), + video=Video(file_id="file id", file_unique_id="file id", width=42, height=42, duration=0,), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_VIDEO_NOTE = Message( + message_id=42, + date=datetime.datetime.now(), + video_note=VideoNote(file_id="file id", file_unique_id="file id", length=0, duration=0), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_VOICE = Message( + message_id=42, + date=datetime.datetime.now(), + voice=Voice(file_id="file id", file_unique_id="file id", duration=0), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_CONTACT = Message( + message_id=42, + date=datetime.datetime.now(), + contact=Contact(phone_number="911", first_name="911"), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_VENUE = Message( + message_id=42, + date=datetime.datetime.now(), + venue=Venue( + location=Location(latitude=3.14, longitude=3.14), + title="Cupboard Under the Stairs", + address="Under the stairs, 4 Privet Drive, " + "Little Whinging, Surrey, England, Great Britain", + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_LOCATION = Message( + message_id=42, + date=datetime.datetime.now(), + location=Location(longitude=3.14, latitude=3.14), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_NEW_CHAT_MEMBERS = Message( + message_id=42, + date=datetime.datetime.now(), + new_chat_members=[User(id=42, is_bot=False, first_name="Test")], + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_LEFT_CHAT_MEMBER = Message( + message_id=42, + date=datetime.datetime.now(), + left_chat_member=User(id=42, is_bot=False, first_name="Test"), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_INVOICE = Message( + message_id=42, + date=datetime.datetime.now(), + invoice=Invoice( + title="test", + description="test", + start_parameter="brilliant", + currency="BTC", + total_amount=1, + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_SUCCESSFUL_PAYMENT = Message( + message_id=42, + date=datetime.datetime.now(), + successful_payment=SuccessfulPayment( + currency="BTC", + total_amount=42, + invoice_payload="payload", + telegram_payment_charge_id="charge", + provider_payment_charge_id="payment", + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_CONNECTED_WEBSITE = Message( + message_id=42, + date=datetime.datetime.now(), + connected_website="token", + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_MIGRATE_FROM_CHAT_ID = Message( + message_id=42, + date=datetime.datetime.now(), + migrate_from_chat_id=42, + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_MIGRATE_TO_CHAT_ID = Message( + message_id=42, + date=datetime.datetime.now(), + migrate_to_chat_id=42, + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_PINNED_MESSAGE = Message( + message_id=42, + date=datetime.datetime.now(), + pinned_message=Message( + message_id=42, + date=datetime.datetime.now(), + text="pinned", + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_NEW_CHAT_TITLE = Message( + message_id=42, + date=datetime.datetime.now(), + new_chat_title="test", + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_NEW_CHAT_PHOTO = Message( + message_id=42, + date=datetime.datetime.now(), + new_chat_photo=[PhotoSize(file_id="file id", file_unique_id="file id", width=42, height=42)], + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_DELETE_CHAT_PHOTO = Message( + message_id=42, + date=datetime.datetime.now(), + delete_chat_photo=True, + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_GROUP_CHAT_CREATED = Message( + message_id=42, + date=datetime.datetime.now(), + group_chat_created=True, + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_PASSPORT_DATA = Message( + message_id=42, + date=datetime.datetime.now(), + passport_data=PassportData( + data=[], credentials=EncryptedCredentials(data="test", hash="test", secret="test"), + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_POLL = Message( + message_id=42, + date=datetime.datetime.now(), + poll=Poll( + id="QA", + question="Q", + options=[PollOption(text="A", voter_count=0), PollOption(text="B", voter_count=0),], + is_closed=False, + is_anonymous=False, + type="quiz", + allows_multiple_answers=False, + total_voter_count=0, + correct_option_id=1, + ), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + message_auto_delete_timer_changed=MessageAutoDeleteTimerChanged(message_auto_delete_time=42), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_VOICE_CHAT_STARTED = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + voice_chat_started=VoiceChatStarted(), +) +TEST_MESSAGE_VOICE_CHAT_ENDED = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + voice_chat_ended=VoiceChatEnded(duration=42), +) +TEST_MESSAGE_VOICE_CHAT_PARTICIPANTS_INVITED = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + voice_chat_participants_invited=VoiceChatParticipantsInvited( + users=[User(id=69, is_bot=False, first_name="Test")] + ), +) +TEST_MESSAGE_DICE = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + dice=Dice(value=6, emoji="X"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) +TEST_MESSAGE_UNKNOWN = Message( + message_id=42, + date=datetime.datetime.now(), + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), +) + class TestMessage: @pytest.mark.parametrize( "message,content_type", [ + [TEST_MESSAGE_TEXT, ContentType.TEXT], + [TEST_MESSAGE_AUDIO, ContentType.AUDIO], + [TEST_MESSAGE_ANIMATION, ContentType.ANIMATION], + [TEST_MESSAGE_DOCUMENT, ContentType.DOCUMENT], + [TEST_MESSAGE_GAME, ContentType.GAME], + [TEST_MESSAGE_PHOTO, ContentType.PHOTO], + [TEST_MESSAGE_STICKER, ContentType.STICKER], + [TEST_MESSAGE_VIDEO, ContentType.VIDEO], + [TEST_MESSAGE_VIDEO_NOTE, ContentType.VIDEO_NOTE], + [TEST_MESSAGE_VOICE, ContentType.VOICE], + [TEST_MESSAGE_CONTACT, ContentType.CONTACT], + [TEST_MESSAGE_VENUE, ContentType.VENUE], + [TEST_MESSAGE_LOCATION, ContentType.LOCATION], + [TEST_MESSAGE_NEW_CHAT_MEMBERS, ContentType.NEW_CHAT_MEMBERS], + [TEST_MESSAGE_LEFT_CHAT_MEMBER, ContentType.LEFT_CHAT_MEMBER], + [TEST_MESSAGE_INVOICE, ContentType.INVOICE], + [TEST_MESSAGE_SUCCESSFUL_PAYMENT, ContentType.SUCCESSFUL_PAYMENT], + [TEST_MESSAGE_CONNECTED_WEBSITE, ContentType.CONNECTED_WEBSITE], + [TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, ContentType.MIGRATE_FROM_CHAT_ID], + [TEST_MESSAGE_MIGRATE_TO_CHAT_ID, ContentType.MIGRATE_TO_CHAT_ID], + [TEST_MESSAGE_PINNED_MESSAGE, ContentType.PINNED_MESSAGE], + [TEST_MESSAGE_NEW_CHAT_TITLE, ContentType.NEW_CHAT_TITLE], + [TEST_MESSAGE_NEW_CHAT_PHOTO, ContentType.NEW_CHAT_PHOTO], + [TEST_MESSAGE_DELETE_CHAT_PHOTO, ContentType.DELETE_CHAT_PHOTO], + [TEST_MESSAGE_GROUP_CHAT_CREATED, ContentType.GROUP_CHAT_CREATED], + [TEST_MESSAGE_PASSPORT_DATA, ContentType.PASSPORT_DATA], + [TEST_MESSAGE_POLL, ContentType.POLL], [ - Message( - message_id=42, - date=datetime.datetime.now(), - text="test", - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.TEXT, + TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED, + ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED, ], + [TEST_MESSAGE_VOICE_CHAT_STARTED, ContentType.VOICE_CHAT_STARTED], + [TEST_MESSAGE_VOICE_CHAT_ENDED, ContentType.VOICE_CHAT_ENDED], [ - Message( - message_id=42, - date=datetime.datetime.now(), - audio=Audio(file_id="file id", file_unique_id="file id", duration=42), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.AUDIO, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - animation=Animation( - file_id="file id", - file_unique_id="file id", - width=42, - height=42, - duration=0, - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.ANIMATION, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - document=Document(file_id="file id", file_unique_id="file id"), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.DOCUMENT, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - game=Game( - title="title", - description="description", - photo=[ - PhotoSize( - file_id="file id", file_unique_id="file id", width=42, height=42 - ) - ], - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.GAME, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - photo=[ - PhotoSize(file_id="file id", file_unique_id="file id", width=42, height=42) - ], - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.PHOTO, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - sticker=Sticker( - file_id="file id", - file_unique_id="file id", - width=42, - height=42, - is_animated=False, - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.STICKER, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - video=Video( - file_id="file id", - file_unique_id="file id", - width=42, - height=42, - duration=0, - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.VIDEO, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - video_note=VideoNote( - file_id="file id", file_unique_id="file id", length=0, duration=0 - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.VIDEO_NOTE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - voice=Voice(file_id="file id", file_unique_id="file id", duration=0), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.VOICE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - contact=Contact(phone_number="911", first_name="911"), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.CONTACT, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - venue=Venue( - location=Location(latitude=3.14, longitude=3.14), - title="Cupboard Under the Stairs", - address="Under the stairs, 4 Privet Drive, " - "Little Whinging, Surrey, England, Great Britain", - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.VENUE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - location=Location(longitude=3.14, latitude=3.14), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.LOCATION, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - new_chat_members=[User(id=42, is_bot=False, first_name="Test")], - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.NEW_CHAT_MEMBERS, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - left_chat_member=User(id=42, is_bot=False, first_name="Test"), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.LEFT_CHAT_MEMBER, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - invoice=Invoice( - title="test", - description="test", - start_parameter="brilliant", - currency="BTC", - total_amount=1, - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.INVOICE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - successful_payment=SuccessfulPayment( - currency="BTC", - total_amount=42, - invoice_payload="payload", - telegram_payment_charge_id="charge", - provider_payment_charge_id="payment", - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.SUCCESSFUL_PAYMENT, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - connected_website="token", - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.CONNECTED_WEBSITE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - migrate_from_chat_id=42, - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.MIGRATE_FROM_CHAT_ID, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - migrate_to_chat_id=42, - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.MIGRATE_TO_CHAT_ID, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - pinned_message=Message( - message_id=42, - date=datetime.datetime.now(), - text="pinned", - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.PINNED_MESSAGE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - new_chat_title="test", - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.NEW_CHAT_TITLE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - new_chat_photo=[ - PhotoSize(file_id="file id", file_unique_id="file id", width=42, height=42) - ], - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.NEW_CHAT_PHOTO, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - delete_chat_photo=True, - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.DELETE_CHAT_PHOTO, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - group_chat_created=True, - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.GROUP_CHAT_CREATED, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - passport_data=PassportData( - data=[], - credentials=EncryptedCredentials(data="test", hash="test", secret="test"), - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.PASSPORT_DATA, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - poll=Poll( - id="QA", - question="Q", - options=[ - PollOption(text="A", voter_count=0), - PollOption(text="B", voter_count=0), - ], - is_closed=False, - is_anonymous=False, - type="quiz", - allows_multiple_answers=False, - total_voter_count=0, - correct_option_id=1, - ), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.POLL, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - chat=Chat(id=42, type="private"), - dice=Dice(value=6, emoji="X"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.DICE, - ], - [ - Message( - message_id=42, - date=datetime.datetime.now(), - chat=Chat(id=42, type="private"), - from_user=User(id=42, is_bot=False, first_name="Test"), - ), - ContentType.UNKNOWN, + TEST_MESSAGE_VOICE_CHAT_PARTICIPANTS_INVITED, + ContentType.VOICE_CHAT_PARTICIPANTS_INVITED, ], + [TEST_MESSAGE_DICE, ContentType.DICE], + [TEST_MESSAGE_UNKNOWN, ContentType.UNKNOWN], ], ) def test_content_type(self, message: Message, content_type: str): @@ -448,12 +410,7 @@ class TestMessage: ["sticker", dict(sticker="sticker"), SendSticker], [ "venue", - dict( - latitude=0.42, - longitude=0.42, - title="title", - address="address", - ), + dict(latitude=0.42, longitude=0.42, title="title", address="address",), SendVenue, ], ["video", dict(video="video"), SendVideo], @@ -508,3 +465,62 @@ class TestMessage: for key, value in kwargs.items(): assert getattr(api_method, key) == value + + def test_copy_to(self): + message = Message( + message_id=42, chat=Chat(id=42, type="private"), date=datetime.datetime.now() + ) + method = message.copy_to(chat_id=message.chat.id) + assert isinstance(method, CopyMessage) + assert method.chat_id == message.chat.id + + @pytest.mark.parametrize( + "message,expected_method", + [ + [TEST_MESSAGE_TEXT, SendMessage], + [TEST_MESSAGE_AUDIO, SendAudio], + [TEST_MESSAGE_ANIMATION, SendAnimation], + [TEST_MESSAGE_DOCUMENT, SendDocument], + [TEST_MESSAGE_GAME, None], + [TEST_MESSAGE_PHOTO, SendPhoto], + [TEST_MESSAGE_STICKER, SendSticker], + [TEST_MESSAGE_VIDEO, SendVideo], + [TEST_MESSAGE_VIDEO_NOTE, SendVideoNote], + [TEST_MESSAGE_VOICE, SendVoice], + [TEST_MESSAGE_CONTACT, SendContact], + [TEST_MESSAGE_VENUE, SendVenue], + [TEST_MESSAGE_LOCATION, SendLocation], + [TEST_MESSAGE_NEW_CHAT_MEMBERS, None], + [TEST_MESSAGE_LEFT_CHAT_MEMBER, None], + [TEST_MESSAGE_INVOICE, None], + [TEST_MESSAGE_SUCCESSFUL_PAYMENT, None], + [TEST_MESSAGE_CONNECTED_WEBSITE, None], + [TEST_MESSAGE_MIGRATE_FROM_CHAT_ID, None], + [TEST_MESSAGE_MIGRATE_TO_CHAT_ID, None], + [TEST_MESSAGE_PINNED_MESSAGE, None], + [TEST_MESSAGE_NEW_CHAT_TITLE, None], + [TEST_MESSAGE_NEW_CHAT_PHOTO, None], + [TEST_MESSAGE_DELETE_CHAT_PHOTO, None], + [TEST_MESSAGE_GROUP_CHAT_CREATED, None], + [TEST_MESSAGE_PASSPORT_DATA, None], + [TEST_MESSAGE_POLL, SendPoll], + [TEST_MESSAGE_MESSAGE_AUTO_DELETE_TIMER_CHANGED, None], + [TEST_MESSAGE_VOICE_CHAT_STARTED, None], + [TEST_MESSAGE_VOICE_CHAT_ENDED, None], + [TEST_MESSAGE_VOICE_CHAT_PARTICIPANTS_INVITED, None], + [TEST_MESSAGE_DICE, SendDice], + [TEST_MESSAGE_UNKNOWN, None], + ], + ) + def test_send_copy( + self, message: Message, expected_method: Optional[Type[TelegramMethod]], + ): + if expected_method is None: + with pytest.raises(TypeError, match="This type of message can't be copied."): + message.send_copy(chat_id=42) + return + + method = message.send_copy(chat_id=42) + if method: + assert isinstance(method, expected_method) + # TODO: Check additional fields diff --git a/tests/test_dispatcher/test_dispatcher.py b/tests/test_dispatcher/test_dispatcher.py index 9603e733..6c5280b7 100644 --- a/tests/test_dispatcher/test_dispatcher.py +++ b/tests/test_dispatcher/test_dispatcher.py @@ -26,6 +26,8 @@ from aiogram.types import ( ShippingQuery, Update, User, + ChatMemberUpdated, + ChatMember, ) from tests.mocked_bot import MockedBot @@ -157,7 +159,7 @@ class TestDispatcher: dispatcher = Dispatcher() result = await dispatcher._process_update(bot=bot, update=Update(update_id=42)) - assert result + assert not result @pytest.mark.asyncio async def test_process_update_handled(self, bot: MockedBot): @@ -364,6 +366,44 @@ class TestDispatcher: False, True, ), + pytest.param( + "my_chat_member", + Update( + update_id=42, + my_chat_member=ChatMemberUpdated( + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + date=datetime.datetime.now(), + old_chat_member=ChatMember( + user=User(id=42, is_bot=False, first_name="Test"), status="restricted" + ), + new_chat_member=ChatMember( + user=User(id=42, is_bot=False, first_name="Test"), status="restricted" + ), + ), + ), + True, + True, + ), + pytest.param( + "chat_member", + Update( + update_id=42, + chat_member=ChatMemberUpdated( + chat=Chat(id=42, type="private"), + from_user=User(id=42, is_bot=False, first_name="Test"), + date=datetime.datetime.now(), + old_chat_member=ChatMember( + user=User(id=42, is_bot=False, first_name="Test"), status="restricted" + ), + new_chat_member=ChatMember( + user=User(id=42, is_bot=False, first_name="Test"), status="restricted" + ), + ), + ), + True, + True, + ), ], ) async def test_listen_update( diff --git a/tests/test_dispatcher/test_event/test_handler.py b/tests/test_dispatcher/test_event/test_handler.py index f67b848e..d7e6a1da 100644 --- a/tests/test_dispatcher/test_event/test_handler.py +++ b/tests/test_dispatcher/test_event/test_handler.py @@ -3,6 +3,7 @@ from typing import Any, Dict, Union import pytest +from aiogram import F from aiogram.dispatcher.event.handler import CallableMixin, FilterObject, HandlerObject from aiogram.dispatcher.filters import Text from aiogram.dispatcher.filters.base import BaseFilter @@ -127,6 +128,14 @@ class TestCallableMixin: assert result == {"foo": 42, "bar": "test", "baz": "fuz"} +class TestFilterObject: + def test_post_init(self): + case = F.test + filter_obj = FilterObject(callback=case) + print(filter_obj.callback) + assert filter_obj.callback == case.resolve + + async def simple_handler(*args, **kwargs): return args, kwargs diff --git a/tests/test_dispatcher/test_filters/test_content_types.py b/tests/test_dispatcher/test_filters/test_content_types.py index a009acfa..63eb207e 100644 --- a/tests/test_dispatcher/test_filters/test_content_types.py +++ b/tests/test_dispatcher/test_filters/test_content_types.py @@ -23,7 +23,7 @@ class TestContentTypesFilter: def test_validator_empty_list(self): filter_ = ContentTypesFilter(content_types=[]) - assert filter_.content_types == ["text"] + assert filter_.content_types == [] def test_convert_to_list(self): filter_ = ContentTypesFilter(content_types="text")