Bump Bot API 5.2. Added integration with MagicFilter

This commit is contained in:
Alex Root Junior 2021-05-05 05:43:55 +03:00
parent 51f0b77a9e
commit eff414b9e5
20 changed files with 208 additions and 62 deletions

View file

@ -283,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)
@ -543,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
@ -579,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_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.
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
@ -1519,7 +1522,7 @@ class Bot(ContextInstanceMixin["Bot"]):
: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_manage_voice_chats: Pass True, if the administrator can manage voice chats, supergroups only
: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_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
@ -2531,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,
@ -2562,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 <https://t.me/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 <https://core.telegram.org/bots/payments#supported-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 <https://core.telegram.org/bots/payments/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
@ -2595,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,

View file

@ -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):

View file

@ -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_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.
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
"""

View file

@ -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
"""

View file

@ -32,7 +32,7 @@ class PromoteChatMember(TelegramMethod[bool]):
can_delete_messages: Optional[bool] = None
"""Pass True, if the administrator can delete messages of other users"""
can_manage_voice_chats: Optional[bool] = None
"""Pass True, if the administrator can manage voice chats, supergroups only"""
"""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_promote_members: Optional[bool] = None

View file

@ -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 <https://t.me/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 <https://core.telegram.org/bots/payments#supported-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 <https://core.telegram.org/bots/payments/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

View file

@ -48,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
@ -106,6 +107,7 @@ 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
@ -140,6 +142,7 @@ __all__ = (
"Venue",
"ProximityAlertTriggered",
"MessageAutoDeleteTimerChanged",
"VoiceChatScheduled",
"VoiceChatStarted",
"VoiceChatEnded",
"VoiceChatParticipantsInvited",
@ -199,6 +202,7 @@ __all__ = (
"InputLocationMessageContent",
"InputVenueMessageContent",
"InputContactMessageContent",
"InputInvoiceMessageContent",
"ChosenInlineResult",
"LabeledPrice",
"Invoice",

View file

@ -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"""

View file

@ -28,7 +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.
**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
"""

View file

@ -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 <https://core.telegram.org/bots/api#inputmessagecontent>`_ 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 <https://t.me/botfather>`_"""
currency: str
"""Three-letter ISO 4217 currency code, see `more on currencies <https://core.telegram.org/bots/payments#supported-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 <https://core.telegram.org/bots/payments/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"""

View file

@ -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
"""

View file

@ -62,6 +62,7 @@ if TYPE_CHECKING: # pragma: no cover
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
@ -174,6 +175,8 @@ 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

View file

@ -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)

View file

@ -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"""

View file

@ -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

View file

@ -42,6 +42,7 @@ Available types
venue
proximity_alert_triggered
message_auto_delete_timer_changed
voice_chat_scheduled
voice_chat_started
voice_chat_ended
voice_chat_participants_invited
@ -117,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

View file

@ -0,0 +1,9 @@
##########################
InputInvoiceMessageContent
##########################
.. automodule:: aiogram.types.input_invoice_message_content
:members:
:member-order: bysource
:undoc-members: True

View file

@ -0,0 +1,9 @@
##################
VoiceChatScheduled
##################
.. automodule:: aiogram.types.voice_chat_scheduled
:members:
:member-order: bysource
:undoc-members: True

48
poetry.lock generated
View file

@ -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,25 +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"]
python2 = ["typed-ast (>=1.4.2)"]
[[package]]
name = "cfgv"
@ -441,11 +442,11 @@ tornado = {version = "*", markers = "python_version > \"2.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"
@ -718,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"
@ -770,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"
@ -1171,7 +1172,7 @@ proxy = ["aiohttp-socks"]
[metadata]
lock-version = "1.1"
python-versions = "^3.7"
content-hash = "0ac1a8626f409f57f8b7f5e1ef3325d7896cc60b42f323f566353a95debe6ebc"
content-hash = "9a787135a6d8ed2a395c07246db424e9961281cf7e0dc00fc08507da3081143e"
[metadata.files]
aiofiles = [
@ -1257,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"},
@ -1270,7 +1271,8 @@ beautifulsoup4 = [
{file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"},
]
black = [
{file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
{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"},
@ -1414,8 +1416,8 @@ livereload = [
{file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"},
]
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.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"},
@ -1642,8 +1644,8 @@ pytest = [
{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"},
@ -1658,8 +1660,8 @@ 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.1.tar.gz", hash = "sha256:1fa55723a4bf1d054fcba1c3bd694215a2a65cc95ab10164f5808afd893f3b11"},

View file

@ -33,14 +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"
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,18 +51,18 @@ Sphinx-Substitution-Extensions = { version = "^2020.9.30", optional = true }
[tool.poetry.dev-dependencies]
aiohttp-socks = "^0.5"
ipython = "^7.10"
ipython = "^7.22.0"
uvloop = { version = "^0.15.2", markers = "sys_platform == 'darwin' or sys_platform == 'linux'" }
black = "^20.8b1"
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.14.0"
pytest-asyncio = "^0.15.1"
pytest-mypy = "^0.8.1"
pytest-mock = "^3.5.1"
pytest-mock = "^3.6.0"
pytest-cov = "^2.11.1"
aresponses = "^2.1.4"
asynctest = "^0.13.0"