From 286cf39c8ae0d2d80c7185cf49af2668703b2e4f Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sat, 16 Apr 2022 19:07:32 +0300 Subject: [PATCH] Beta 3 (#884) * Rework middlewares, separate management to `MiddlewareManager` class * Rework middlewares * Added changes description for redis * Added changes description for redis * Fixed tests with Redis // aioredis replacement * Changed msg._text attributes behaviour * Added changelog for spoilers * Added possibility to get command magic result as handler arguments --- .pre-commit-config.yaml | 6 +- CHANGES/{839.bugix => 839.bugix.rst} | 0 CHANGES/865.bugfix.rst | 1 + CHANGES/{873.misc => 873.misc.rst} | 0 CHANGES/874.misc.rst | 2 + CHANGES/882.misc.rst | 1 + CHANGES/883.misc.rst | 3 + CHANGES/885.bugfix.rst | 1 + CHANGES/889.feature.rst | 1 + Makefile | 5 +- aiogram/client/session/base.py | 44 +- aiogram/client/session/middlewares/base.py | 22 +- aiogram/client/session/middlewares/manager.py | 79 ++ .../session/middlewares/request_logging.py | 9 +- aiogram/dispatcher/dispatcher.py | 47 +- aiogram/dispatcher/event/telegram.py | 145 +-- aiogram/dispatcher/filters/callback_data.py | 79 +- aiogram/dispatcher/filters/command.py | 18 +- aiogram/dispatcher/filters/magic_data.py | 8 +- aiogram/dispatcher/flags/flag.py | 25 +- aiogram/dispatcher/fsm/storage/redis.py | 8 +- aiogram/dispatcher/middlewares/manager.py | 61 ++ aiogram/dispatcher/router.py | 178 +++- aiogram/methods/base.py | 2 + aiogram/types/keyboard_button.py | 5 + aiogram/types/message.py | 11 +- aiogram/utils/chat_action.py | 2 +- aiogram/utils/link.py | 34 +- aiogram/utils/text_decorations.py | 42 +- docs/dispatcher/filters/callback_data.rst | 118 +++ docs/dispatcher/filters/index.rst | 1 + docs/utils/index.rst | 2 +- examples/echo_bot.py | 1 - mypy.ini | 2 +- poetry.lock | 970 +++++++++--------- pyproject.toml | 25 +- tests/conftest.py | 2 +- .../test_session/test_base_session.py | 6 +- .../test_middlewares/test_manager.py | 45 + tests/test_api/test_types/test_message.py | 19 +- tests/test_dispatcher/test_deprecated.py | 37 +- tests/test_dispatcher/test_dispatcher.py | 17 +- .../test_event/test_middleware.py | 42 + .../test_event/test_telegram.py | 11 +- .../test_filters/test_callback_data.py | 6 +- .../test_filters/test_command.py | 12 + .../test_filters/test_exception.py | 2 +- .../test_filters/test_magic_data.py | 6 +- tests/test_utils/test_i18n.py | 4 +- tests/test_utils/test_link.py | 11 +- tests/test_utils/test_text_decorations.py | 6 + 51 files changed, 1380 insertions(+), 804 deletions(-) rename CHANGES/{839.bugix => 839.bugix.rst} (100%) create mode 100644 CHANGES/865.bugfix.rst rename CHANGES/{873.misc => 873.misc.rst} (100%) create mode 100644 CHANGES/874.misc.rst create mode 100644 CHANGES/882.misc.rst create mode 100644 CHANGES/883.misc.rst create mode 100644 CHANGES/885.bugfix.rst create mode 100644 CHANGES/889.feature.rst create mode 100644 aiogram/client/session/middlewares/manager.py create mode 100644 aiogram/dispatcher/middlewares/manager.py create mode 100644 docs/dispatcher/filters/callback_data.rst create mode 100644 tests/test_api/test_client/test_session/test_middlewares/test_manager.py create mode 100644 tests/test_dispatcher/test_event/test_middleware.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 07fbe618..98dda96a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,20 +2,20 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.2.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - id: check-merge-conflict - repo: https://github.com/psf/black - rev: 21.8b0 + rev: 22.3.0 hooks: - id: black files: &files '^(aiogram|tests|examples)' - repo: https://github.com/pre-commit/mirrors-isort - rev: v5.9.3 + rev: v5.10.1 hooks: - id: isort additional_dependencies: [ toml ] diff --git a/CHANGES/839.bugix b/CHANGES/839.bugix.rst similarity index 100% rename from CHANGES/839.bugix rename to CHANGES/839.bugix.rst diff --git a/CHANGES/865.bugfix.rst b/CHANGES/865.bugfix.rst new file mode 100644 index 00000000..bab93962 --- /dev/null +++ b/CHANGES/865.bugfix.rst @@ -0,0 +1 @@ +Added parsing of spoiler message entity diff --git a/CHANGES/873.misc b/CHANGES/873.misc.rst similarity index 100% rename from CHANGES/873.misc rename to CHANGES/873.misc.rst diff --git a/CHANGES/874.misc.rst b/CHANGES/874.misc.rst new file mode 100644 index 00000000..d167c1d8 --- /dev/null +++ b/CHANGES/874.misc.rst @@ -0,0 +1,2 @@ +Changed :code:`Message.html_text` and :code:`Message.md_text` attributes behaviour when message has no text. +The empty string will be used instead of raising error. diff --git a/CHANGES/882.misc.rst b/CHANGES/882.misc.rst new file mode 100644 index 00000000..ca8b0ba4 --- /dev/null +++ b/CHANGES/882.misc.rst @@ -0,0 +1 @@ +Used `redis-py` instead of `aioredis` package in due to this packages was merged into single one diff --git a/CHANGES/883.misc.rst b/CHANGES/883.misc.rst new file mode 100644 index 00000000..8496c902 --- /dev/null +++ b/CHANGES/883.misc.rst @@ -0,0 +1,3 @@ +Solved common naming problem with middlewares that confusing too much developers +- now you can't see the `middleware` and `middlewares` attributes at the same point +because this functionality encapsulated to special interface. diff --git a/CHANGES/885.bugfix.rst b/CHANGES/885.bugfix.rst new file mode 100644 index 00000000..6d1bb095 --- /dev/null +++ b/CHANGES/885.bugfix.rst @@ -0,0 +1 @@ +Fixed CallbackData factory parsing IntEnum's diff --git a/CHANGES/889.feature.rst b/CHANGES/889.feature.rst new file mode 100644 index 00000000..8e58304c --- /dev/null +++ b/CHANGES/889.feature.rst @@ -0,0 +1 @@ +Added possibility to get command magic result as handler argument diff --git a/Makefile b/Makefile index c0508fea..8d9abab8 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ help: .PHONY: install install: - poetry install -E fast -E redis -E proxy -E i18n -E docs + poetry install -E fast -E redis -E proxy -E i18n -E docs --remove-untracked $(py) pre-commit install .PHONY: clean @@ -94,9 +94,6 @@ test: test-run-services test-coverage: test-run-services mkdir -p $(reports_dir)/tests/ $(py) pytest --cov=aiogram --cov-config .coveragerc --html=$(reports_dir)/tests/index.html tests/ --redis $(redis_connection) - -.PHONY: test-coverage-report -test-coverage-report: $(py) coverage html -d $(reports_dir)/coverage .PHONY: test-coverage-view diff --git a/aiogram/client/session/base.py b/aiogram/client/session/base.py index d5a95622..ba337c94 100644 --- a/aiogram/client/session/base.py +++ b/aiogram/client/session/base.py @@ -3,22 +3,9 @@ from __future__ import annotations import abc import datetime import json -from functools import partial from http import HTTPStatus from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - AsyncGenerator, - Awaitable, - Callable, - Final, - List, - Optional, - Type, - Union, - cast, -) +from typing import TYPE_CHECKING, Any, AsyncGenerator, Callable, Final, Optional, Type, Union, cast from aiogram.exceptions import ( RestartingTelegram, @@ -36,26 +23,15 @@ from aiogram.exceptions import ( from ...methods import Response, TelegramMethod from ...methods.base import TelegramType -from ...types import UNSET, TelegramObject +from ...types import UNSET from ..telegram import PRODUCTION, TelegramAPIServer -from .middlewares.base import BaseRequestMiddleware +from .middlewares.manager import RequestMiddlewareManager if TYPE_CHECKING: from ..bot import Bot _JsonLoads = Callable[..., Any] _JsonDumps = Callable[..., str] -NextRequestMiddlewareType = Callable[ - ["Bot", TelegramMethod[TelegramObject]], Awaitable[Response[TelegramObject]] -] - -RequestMiddlewareType = Union[ - BaseRequestMiddleware, - Callable[ - [NextRequestMiddlewareType, "Bot", TelegramMethod[TelegramType]], - Awaitable[Response[TelegramType]], - ], -] DEFAULT_TIMEOUT: Final[float] = 60.0 @@ -80,7 +56,7 @@ class BaseSession(abc.ABC): self.json_dumps = json_dumps self.timeout = timeout - self.middlewares: List[RequestMiddlewareType[TelegramObject]] = [] + self.middleware = RequestMiddlewareManager() def check_response( self, method: TelegramMethod[TelegramType], status_code: int, content: str @@ -185,19 +161,11 @@ class BaseSession(abc.ABC): return {k: self.clean_json(v) for k, v in value.items() if v is not None} return value - def middleware( - self, middleware: RequestMiddlewareType[TelegramObject] - ) -> RequestMiddlewareType[TelegramObject]: - self.middlewares.append(middleware) - return middleware - async def __call__( self, bot: Bot, method: TelegramMethod[TelegramType], timeout: Optional[int] = UNSET ) -> TelegramType: - middleware = partial(self.make_request, timeout=timeout) - for m in reversed(self.middlewares): - middleware = partial(m, middleware) # type: ignore - return await middleware(bot, method) + middleware = self.middleware.wrap_middlewares(self.make_request, timeout=timeout) + return cast(TelegramType, await middleware(bot, method)) async def __aenter__(self) -> BaseSession: return self diff --git a/aiogram/client/session/middlewares/base.py b/aiogram/client/session/middlewares/base.py index 5b8d0f2b..90dcd09f 100644 --- a/aiogram/client/session/middlewares/base.py +++ b/aiogram/client/session/middlewares/base.py @@ -1,15 +1,23 @@ +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Awaitable, Callable +from typing import TYPE_CHECKING, Awaitable, Callable, Union from aiogram.methods import Response, TelegramMethod -from aiogram.types import TelegramObject +from aiogram.methods.base import TelegramType if TYPE_CHECKING: from ...bot import Bot - NextRequestMiddlewareType = Callable[ - ["Bot", TelegramMethod[TelegramObject]], Awaitable[Response[TelegramObject]] + ["Bot", TelegramMethod[TelegramType]], Awaitable[Response[TelegramType]] +] +RequestMiddlewareType = Union[ + "BaseRequestMiddleware", + Callable[ + [NextRequestMiddlewareType[TelegramType], "Bot", TelegramMethod[TelegramType]], + Awaitable[Response[TelegramType]], + ], ] @@ -21,10 +29,10 @@ class BaseRequestMiddleware(ABC): @abstractmethod async def __call__( self, - make_request: NextRequestMiddlewareType, + make_request: NextRequestMiddlewareType[TelegramType], bot: "Bot", - method: TelegramMethod[TelegramObject], - ) -> Response[TelegramObject]: + method: TelegramMethod[TelegramType], + ) -> Response[TelegramType]: """ Execute middleware diff --git a/aiogram/client/session/middlewares/manager.py b/aiogram/client/session/middlewares/manager.py new file mode 100644 index 00000000..0e76801e --- /dev/null +++ b/aiogram/client/session/middlewares/manager.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from functools import partial +from typing import ( + TYPE_CHECKING, + Any, + Awaitable, + Callable, + List, + Optional, + Sequence, + Union, + overload, +) + +from aiogram.client.session.middlewares.base import ( + NextRequestMiddlewareType, + RequestMiddlewareType, +) +from aiogram.methods import Response +from aiogram.methods.base import TelegramMethod, TelegramType +from aiogram.types import TelegramObject + +if TYPE_CHECKING: + from aiogram import Bot + + +class RequestMiddlewareManager(Sequence[RequestMiddlewareType[TelegramObject]]): + def __init__(self) -> None: + self._middlewares: List[RequestMiddlewareType[TelegramObject]] = [] + + def register( + self, + middleware: RequestMiddlewareType[TelegramObject], + ) -> RequestMiddlewareType[TelegramObject]: + self._middlewares.append(middleware) + return middleware + + def unregister(self, middleware: RequestMiddlewareType[TelegramObject]) -> None: + self._middlewares.remove(middleware) + + def __call__( + self, + middleware: Optional[RequestMiddlewareType[TelegramObject]] = None, + ) -> Union[ + Callable[[RequestMiddlewareType[TelegramObject]], RequestMiddlewareType[TelegramObject]], + RequestMiddlewareType[TelegramObject], + ]: + if middleware is None: + return self.register + return self.register(middleware) + + @overload + def __getitem__(self, item: int) -> RequestMiddlewareType[TelegramObject]: + pass + + @overload + def __getitem__(self, item: slice) -> Sequence[RequestMiddlewareType[TelegramObject]]: + pass + + def __getitem__( + self, item: Union[int, slice] + ) -> Union[ + RequestMiddlewareType[TelegramObject], Sequence[RequestMiddlewareType[TelegramObject]] + ]: + return self._middlewares[item] + + def __len__(self) -> int: + return len(self._middlewares) + + def wrap_middlewares( + self, + callback: Callable[[Bot, TelegramMethod[TelegramType]], Awaitable[Response[TelegramType]]], + **kwargs: Any, + ) -> NextRequestMiddlewareType[TelegramType]: + middleware = partial(callback, **kwargs) + for m in reversed(self._middlewares): + middleware = partial(m, middleware) # type: ignore + return middleware diff --git a/aiogram/client/session/middlewares/request_logging.py b/aiogram/client/session/middlewares/request_logging.py index 67df277d..af7b9d6e 100644 --- a/aiogram/client/session/middlewares/request_logging.py +++ b/aiogram/client/session/middlewares/request_logging.py @@ -3,8 +3,7 @@ from typing import TYPE_CHECKING, Any, List, Optional, Type from aiogram import loggers from aiogram.methods import TelegramMethod -from aiogram.methods.base import Response -from aiogram.types import TelegramObject +from aiogram.methods.base import Response, TelegramType from .base import BaseRequestMiddleware, NextRequestMiddlewareType @@ -25,10 +24,10 @@ class RequestLogging(BaseRequestMiddleware): async def __call__( self, - make_request: NextRequestMiddlewareType, + make_request: NextRequestMiddlewareType[TelegramType], bot: "Bot", - method: TelegramMethod[TelegramObject], - ) -> Response[TelegramObject]: + method: TelegramMethod[TelegramType], + ) -> Response[TelegramType]: if type(method) not in self.ignore_methods: loggers.middlewares.info( "Make request with method=%r by bot id=%d", diff --git a/aiogram/dispatcher/dispatcher.py b/aiogram/dispatcher/dispatcher.py index 610053db..9b84262c 100644 --- a/aiogram/dispatcher/dispatcher.py +++ b/aiogram/dispatcher/dispatcher.py @@ -36,8 +36,19 @@ class Dispatcher(Router): storage: Optional[BaseStorage] = None, fsm_strategy: FSMStrategy = FSMStrategy.USER_IN_CHAT, events_isolation: Optional[BaseEventIsolation] = None, + disable_fsm: bool = False, **kwargs: Any, ) -> None: + """ + Root router + + :param storage: Storage for FSM + :param fsm_strategy: FSM strategy + :param events_isolation: Events isolation + :param disable_fsm: Disable FSM, note that if you disable FSM + then you should not use storage and events isolation + :param kwargs: Other arguments, will be passed as keyword arguments to handlers + """ super(Dispatcher, self).__init__(**kwargs) # Telegram API provides originally only one event type - Update @@ -48,7 +59,8 @@ class Dispatcher(Router): ) self.update.register(self._listen_update) - # Error handlers should work is out of all other functions and be registered before all others middlewares + # Error handlers should work is out of all other functions + # and should be registered before all others middlewares self.update.outer_middleware(ErrorsMiddleware(self)) # User context middleware makes small optimization for all other builtin @@ -62,11 +74,31 @@ class Dispatcher(Router): strategy=fsm_strategy, events_isolation=events_isolation if events_isolation else DisabledEventIsolation(), ) - self.update.outer_middleware(self.fsm) + if not disable_fsm: + # Note that when FSM middleware is disabled, the event isolation is also disabled + # Because the isolation mechanism is a part of the FSM + self.update.outer_middleware(self.fsm) self.shutdown.register(self.fsm.close) + self._data: Dict[str, Any] = {} self._running_lock = Lock() + def __getitem__(self, item: str) -> Any: + return self._data[item] + + def __setitem__(self, key: str, value: Any) -> None: + self._data[key] = value + + def __delitem__(self, key: str) -> None: + del self._data[key] + + def get(self, key: str, /, default: Optional[Any] = None) -> Optional[Any]: + return self._data.get(key, default) + + @property + def storage(self) -> BaseStorage: + return self.fsm.storage + @property def parent_router(self) -> None: """ @@ -100,8 +132,15 @@ class Dispatcher(Router): token = Bot.set_current(bot) try: - kwargs.update(bot=bot) - response = await self.update.wrap_outer_middleware(self.update.trigger, update, kwargs) + response = await self.update.wrap_outer_middleware( + self.update.trigger, + update, + { + **self._data, + **kwargs, + "bot": bot, + }, + ) handled = response is not UNHANDLED return response finally: diff --git a/aiogram/dispatcher/event/telegram.py b/aiogram/dispatcher/event/telegram.py index a08d7cb1..fcf3d7d2 100644 --- a/aiogram/dispatcher/event/telegram.py +++ b/aiogram/dispatcher/event/telegram.py @@ -1,33 +1,17 @@ from __future__ import annotations -import functools +from inspect import isclass from itertools import chain -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - Generator, - List, - Optional, - Tuple, - Type, - Union, -) +from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Tuple, Type from pydantic import ValidationError +from aiogram.dispatcher.middlewares.manager import MiddlewareManager + from ...exceptions import FiltersResolveError from ...types import TelegramObject from ..filters.base import BaseFilter -from .bases import ( - REJECTED, - UNHANDLED, - MiddlewareEventType, - MiddlewareType, - NextMiddlewareType, - SkipHandler, -) +from .bases import REJECTED, UNHANDLED, MiddlewareType, SkipHandler from .handler import CallbackType, FilterObject, FilterType, HandlerObject, HandlerType if TYPE_CHECKING: @@ -48,8 +32,9 @@ class TelegramEventObserver: self.handlers: List[HandlerObject] = [] self.filters: List[Type[BaseFilter]] = [] - self.outer_middlewares: List[MiddlewareType[TelegramObject]] = [] - self.middlewares: List[MiddlewareType[TelegramObject]] = [] + + self.middleware = MiddlewareManager() + self.outer_middleware = MiddlewareManager() # Re-used filters check method from already implemented handler object # with dummy callback which never will be used @@ -75,7 +60,11 @@ class TelegramEventObserver: :param bound_filter: """ - if not issubclass(bound_filter, BaseFilter): + # TODO: This functionality should be deprecated in the future + # in due to bound filter has uncontrollable ordering and + # makes debugging process is harder that explicit using filters + + if not isclass(bound_filter) or not issubclass(bound_filter, BaseFilter): raise TypeError( "bound_filter() argument 'bound_filter' must be subclass of BaseFilter" ) @@ -97,18 +86,11 @@ class TelegramEventObserver: yield filter_ registry.append(filter_) - def _resolve_middlewares(self, *, outer: bool = False) -> List[MiddlewareType[TelegramObject]]: - """ - Get all middlewares in a tree - :param *: - """ - middlewares = [] - if outer: - middlewares.extend(self.outer_middlewares) - else: - for router in reversed(tuple(self.router.chain_head)): - observer = router.observers[self.event_name] - middlewares.extend(observer.middlewares) + def _resolve_middlewares(self) -> List[MiddlewareType[TelegramObject]]: + middlewares: List[MiddlewareType[TelegramObject]] = [] + for router in reversed(tuple(self.router.chain_head)): + observer = router.observers[self.event_name] + middlewares.extend(observer.middleware) return middlewares @@ -198,23 +180,13 @@ class TelegramEventObserver: ) return callback - @classmethod - def _wrap_middleware( - cls, middlewares: List[MiddlewareType[MiddlewareEventType]], handler: HandlerType - ) -> NextMiddlewareType[MiddlewareEventType]: - @functools.wraps(handler) - def mapper(event: TelegramObject, kwargs: Dict[str, Any]) -> Any: - return handler(event, **kwargs) - - middleware = mapper - for m in reversed(middlewares): - middleware = functools.partial(m, middleware) - return middleware - def wrap_outer_middleware( self, callback: Any, event: TelegramObject, data: Dict[str, Any] ) -> Any: - wrapped_outer = self._wrap_middleware(self._resolve_middlewares(outer=True), callback) + wrapped_outer = self.middleware.wrap_middlewares( + self.outer_middleware, + callback, + ) return wrapped_outer(event, data) async def trigger(self, event: TelegramObject, **kwargs: Any) -> Any: @@ -233,8 +205,9 @@ class TelegramEventObserver: if result: kwargs.update(data, handler=handler) try: - wrapped_inner = self._wrap_middleware( - self._resolve_middlewares(), handler.call + wrapped_inner = self.outer_middleware.wrap_middlewares( + self._resolve_middlewares(), + handler.call, ) return await wrapped_inner(event, kwargs) except SkipHandler: @@ -254,71 +227,3 @@ class TelegramEventObserver: return callback return wrapper - - def middleware( - self, - middleware: Optional[MiddlewareType[TelegramObject]] = None, - ) -> Union[ - Callable[[MiddlewareType[TelegramObject]], MiddlewareType[TelegramObject]], - MiddlewareType[TelegramObject], - ]: - """ - Decorator for registering inner middlewares - - Usage: - - .. code-block:: python - - @.middleware() # via decorator (variant 1) - - .. code-block:: python - - @.middleware # via decorator (variant 2) - - .. code-block:: python - - async def my_middleware(handler, event, data): ... - .middleware(my_middleware) # via method - """ - - def wrapper(m: MiddlewareType[TelegramObject]) -> MiddlewareType[TelegramObject]: - self.middlewares.append(m) - return m - - if middleware is None: - return wrapper - return wrapper(middleware) - - def outer_middleware( - self, - middleware: Optional[MiddlewareType[TelegramObject]] = None, - ) -> Union[ - Callable[[MiddlewareType[TelegramObject]], MiddlewareType[TelegramObject]], - MiddlewareType[TelegramObject], - ]: - """ - Decorator for registering outer middlewares - - Usage: - - .. code-block:: python - - @.outer_middleware() # via decorator (variant 1) - - .. code-block:: python - - @.outer_middleware # via decorator (variant 2) - - .. code-block:: python - - async def my_middleware(handler, event, data): ... - .outer_middleware(my_middleware) # via method - """ - - def wrapper(m: MiddlewareType[TelegramObject]) -> MiddlewareType[TelegramObject]: - self.outer_middlewares.append(m) - return m - - if middleware is None: - return wrapper - return wrapper(middleware) diff --git a/aiogram/dispatcher/filters/callback_data.py b/aiogram/dispatcher/filters/callback_data.py index d220da70..21aa6700 100644 --- a/aiogram/dispatcher/filters/callback_data.py +++ b/aiogram/dispatcher/filters/callback_data.py @@ -3,7 +3,7 @@ from __future__ import annotations from decimal import Decimal from enum import Enum from fractions import Fraction -from typing import TYPE_CHECKING, Any, Dict, Literal, Optional, Type, TypeVar, Union +from typing import TYPE_CHECKING, Any, ClassVar, Dict, Literal, Optional, Type, TypeVar, Union from uuid import UUID from magic_filter import MagicFilter @@ -22,9 +22,20 @@ class CallbackDataException(Exception): class CallbackData(BaseModel): + """ + Base class for callback data wrapper + + This class should be used as super-class of user-defined callbacks. + + The class-keyword :code:`prefix` is required to define prefix + and also the argument :code:`sep` can be passed to define separator (default is :code:`:`). + """ + if TYPE_CHECKING: - sep: str - prefix: str + __separator__: ClassVar[str] + """Data separator (default is :code:`:`)""" + __prefix__: ClassVar[str] + """Callback prefix""" def __init_subclass__(cls, **kwargs: Any) -> None: if "prefix" not in kwargs: @@ -32,12 +43,14 @@ class CallbackData(BaseModel): f"prefix required, usage example: " f"`class {cls.__name__}(CallbackData, prefix='my_callback'): ...`" ) - cls.sep = kwargs.pop("sep", ":") - cls.prefix = kwargs.pop("prefix") - if cls.sep in cls.prefix: + cls.__separator__ = kwargs.pop("sep", ":") + cls.__prefix__ = kwargs.pop("prefix") + if cls.__separator__ in cls.__prefix__: raise ValueError( - f"Separator symbol {cls.sep!r} can not be used inside prefix {cls.prefix!r}" + f"Separator symbol {cls.__separator__!r} can not be used " + f"inside prefix {cls.__prefix__!r}" ) + super().__init_subclass__(**kwargs) def _encode_value(self, key: str, value: Any) -> str: if value is None: @@ -52,31 +65,45 @@ class CallbackData(BaseModel): ) def pack(self) -> str: - result = [self.prefix] + """ + Generate callback data string + + :return: valid callback data for Telegram Bot API + """ + result = [self.__prefix__] for key, value in self.dict().items(): encoded = self._encode_value(key, value) - if self.sep in encoded: + if self.__separator__ in encoded: raise ValueError( - f"Separator symbol {self.sep!r} can not be used in value {key}={encoded!r}" + f"Separator symbol {self.__separator__!r} can not be used " + f"in value {key}={encoded!r}" ) result.append(encoded) - callback_data = self.sep.join(result) + callback_data = self.__separator__.join(result) if len(callback_data.encode()) > MAX_CALLBACK_LENGTH: raise ValueError( - f"Resulted callback data is too long! len({callback_data!r}.encode()) > {MAX_CALLBACK_LENGTH}" + f"Resulted callback data is too long! " + f"len({callback_data!r}.encode()) > {MAX_CALLBACK_LENGTH}" ) return callback_data @classmethod def unpack(cls: Type[T], value: str) -> T: - prefix, *parts = value.split(cls.sep) + """ + Parse callback data string + + :param value: value from Telegram + :return: instance of CallbackData + """ + prefix, *parts = value.split(cls.__separator__) names = cls.__fields__.keys() if len(parts) != len(names): raise TypeError( - f"Callback data {cls.__name__!r} takes {len(names)} arguments but {len(parts)} were given" + f"Callback data {cls.__name__!r} takes {len(names)} arguments " + f"but {len(parts)} were given" ) - if prefix != cls.prefix: - raise ValueError(f"Bad prefix ({prefix!r} != {cls.prefix!r})") + if prefix != cls.__prefix__: + raise ValueError(f"Bad prefix ({prefix!r} != {cls.__prefix__!r})") payload = {} for k, v in zip(names, parts): # type: str, Optional[str] if field := cls.__fields__.get(k): @@ -87,15 +114,30 @@ class CallbackData(BaseModel): @classmethod def filter(cls, rule: Optional[MagicFilter] = None) -> CallbackQueryFilter: + """ + Generates a filter for callback query with rule + + :param rule: magic rule + :return: instance of filter + """ return CallbackQueryFilter(callback_data=cls, rule=rule) - class Config: - use_enum_values = True + # class Config: + # use_enum_values = True class CallbackQueryFilter(BaseFilter): + """ + This filter helps to handle callback query. + + Should not be used directly, you should create the instance of this filter + via callback data instance + """ + callback_data: Type[CallbackData] + """Expected type of callback data""" rule: Optional[MagicFilter] = None + """Magic rule""" async def __call__(self, query: CallbackQuery) -> Union[Literal[False], Dict[str, Any]]: if not isinstance(query, CallbackQuery) or not query.data: @@ -111,3 +153,4 @@ class CallbackQueryFilter(BaseFilter): class Config: arbitrary_types_allowed = True + use_enum_values = True diff --git a/aiogram/dispatcher/filters/command.py b/aiogram/dispatcher/filters/command.py index 03cb41c7..3690f884 100644 --- a/aiogram/dispatcher/filters/command.py +++ b/aiogram/dispatcher/filters/command.py @@ -59,7 +59,10 @@ class Command(BaseFilter): command = await self.parse_command(text=text, bot=bot) except CommandException: return False - return {"command": command} + result = {"command": command} + if command.magic_result and isinstance(command.magic_result, dict): + result.update(command.magic_result) + return result def extract_command(self, text: str) -> CommandObject: # First step: separate command with arguments @@ -110,20 +113,22 @@ class Command(BaseFilter): self.validate_prefix(command=command) await self.validate_mention(bot=bot, command=command) command = self.validate_command(command) - self.do_magic(command=command) + command = self.do_magic(command=command) return command - def do_magic(self, command: CommandObject) -> None: + def do_magic(self, command: CommandObject) -> Any: if not self.command_magic: - return - if not self.command_magic.resolve(command): + return command + result = self.command_magic.resolve(command) + if not result: raise CommandException("Rejected via magic filter") + return replace(command, magic_result=result) class Config: arbitrary_types_allowed = True -@dataclass +@dataclass(frozen=True) class CommandObject: """ Instance of this object is always has command and it prefix. @@ -140,6 +145,7 @@ class CommandObject: """Command argument""" regexp_match: Optional[Match[str]] = field(repr=False, default=None) """Will be presented match result if the command is presented as regexp in filter""" + magic_result: Optional[Any] = field(repr=False, default=None) @property def mentioned(self) -> bool: diff --git a/aiogram/dispatcher/filters/magic_data.py b/aiogram/dispatcher/filters/magic_data.py index 2fa5f46a..3c98806a 100644 --- a/aiogram/dispatcher/filters/magic_data.py +++ b/aiogram/dispatcher/filters/magic_data.py @@ -12,9 +12,7 @@ class MagicData(BaseFilter): class Config: arbitrary_types_allowed = True - async def __call__(self, event: TelegramObject, *args: Any, **kwargs: Any) -> bool: - return bool( - self.magic_data.resolve( - AttrDict({"event": event, **{k: v for k, v in enumerate(args)}, **kwargs}) - ) + async def __call__(self, event: TelegramObject, *args: Any, **kwargs: Any) -> Any: + return self.magic_data.resolve( + AttrDict({"event": event, **{k: v for k, v in enumerate(args)}, **kwargs}) ) diff --git a/aiogram/dispatcher/flags/flag.py b/aiogram/dispatcher/flags/flag.py index 845b898b..1028393a 100644 --- a/aiogram/dispatcher/flags/flag.py +++ b/aiogram/dispatcher/flags/flag.py @@ -1,10 +1,13 @@ from dataclasses import dataclass -from typing import Any, Callable, Optional, Union, cast, overload +from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast, overload from magic_filter import AttrDict from aiogram.dispatcher.flags.getter import extract_flags_from_object +if TYPE_CHECKING: + pass + @dataclass(frozen=True) class Flag: @@ -25,11 +28,11 @@ class FlagDecorator: return self._with_flag(new_flag) @overload - def __call__(self, value: Callable[..., Any]) -> Callable[..., Any]: # type: ignore + def __call__(self, value: Callable[..., Any], /) -> Callable[..., Any]: # type: ignore pass @overload - def __call__(self, value: Any) -> "FlagDecorator": + def __call__(self, value: Any, /) -> "FlagDecorator": pass @overload @@ -53,8 +56,24 @@ class FlagDecorator: return self._with_value(AttrDict(kwargs) if value is None else value) +if TYPE_CHECKING: + + class _ChatActionFlagProtocol(FlagDecorator): + def __call__( # type: ignore[override] + self, + action: str = ..., + interval: float = ..., + initial_sleep: float = ..., + **kwargs: Any, + ) -> FlagDecorator: + pass + + class FlagGenerator: def __getattr__(self, name: str) -> FlagDecorator: if name[0] == "_": raise AttributeError("Flag name must NOT start with underscore") return FlagDecorator(Flag(name, True)) + + if TYPE_CHECKING: + chat_action: _ChatActionFlagProtocol diff --git a/aiogram/dispatcher/fsm/storage/redis.py b/aiogram/dispatcher/fsm/storage/redis.py index 5ab880de..36ac57c3 100644 --- a/aiogram/dispatcher/fsm/storage/redis.py +++ b/aiogram/dispatcher/fsm/storage/redis.py @@ -2,7 +2,9 @@ from abc import ABC, abstractmethod from contextlib import asynccontextmanager from typing import Any, AsyncGenerator, Dict, Literal, Optional, cast -from aioredis import ConnectionPool, Redis +from redis.asyncio.client import Redis +from redis.asyncio.connection import ConnectionPool +from redis.asyncio.lock import Lock from aiogram import Bot from aiogram.dispatcher.fsm.state import State @@ -131,7 +133,7 @@ class RedisStorage(BaseStorage): return RedisEventIsolation(redis=self.redis, key_builder=self.key_builder, **kwargs) async def close(self) -> None: - await self.redis.close() # type: ignore + await self.redis.close() async def set_state( self, @@ -223,7 +225,7 @@ class RedisEventIsolation(BaseEventIsolation): key: StorageKey, ) -> AsyncGenerator[None, None]: redis_key = self.key_builder.build(key, "lock") - async with self.redis.lock(name=redis_key, **self.lock_kwargs): + async with self.redis.lock(name=redis_key, **self.lock_kwargs, lock_class=Lock): yield None async def close(self) -> None: diff --git a/aiogram/dispatcher/middlewares/manager.py b/aiogram/dispatcher/middlewares/manager.py new file mode 100644 index 00000000..89892e77 --- /dev/null +++ b/aiogram/dispatcher/middlewares/manager.py @@ -0,0 +1,61 @@ +import functools +from typing import Any, Callable, Dict, List, Optional, Sequence, Union, overload + +from aiogram.dispatcher.event.bases import MiddlewareEventType, MiddlewareType, NextMiddlewareType +from aiogram.dispatcher.event.handler import HandlerType +from aiogram.types import TelegramObject + + +class MiddlewareManager(Sequence[MiddlewareType[TelegramObject]]): + def __init__(self) -> None: + self._middlewares: List[MiddlewareType[TelegramObject]] = [] + + def register( + self, + middleware: MiddlewareType[TelegramObject], + ) -> MiddlewareType[TelegramObject]: + self._middlewares.append(middleware) + return middleware + + def unregister(self, middleware: MiddlewareType[TelegramObject]) -> None: + self._middlewares.remove(middleware) + + def __call__( + self, + middleware: Optional[MiddlewareType[TelegramObject]] = None, + ) -> Union[ + Callable[[MiddlewareType[TelegramObject]], MiddlewareType[TelegramObject]], + MiddlewareType[TelegramObject], + ]: + if middleware is None: + return self.register + return self.register(middleware) + + @overload + def __getitem__(self, item: int) -> MiddlewareType[TelegramObject]: + pass + + @overload + def __getitem__(self, item: slice) -> Sequence[MiddlewareType[TelegramObject]]: + pass + + def __getitem__( + self, item: Union[int, slice] + ) -> Union[MiddlewareType[TelegramObject], Sequence[MiddlewareType[TelegramObject]]]: + return self._middlewares[item] + + def __len__(self) -> int: + return len(self._middlewares) + + @staticmethod + def wrap_middlewares( + middlewares: Sequence[MiddlewareType[MiddlewareEventType]], handler: HandlerType + ) -> NextMiddlewareType[MiddlewareEventType]: + @functools.wraps(handler) + def handler_wrapper(event: TelegramObject, kwargs: Dict[str, Any]) -> Any: + return handler(event, **kwargs) + + middleware = handler_wrapper + for m in reversed(middlewares): + middleware = functools.partial(m, middleware) + return middleware diff --git a/aiogram/dispatcher/router.py b/aiogram/dispatcher/router.py index c9e7dea9..32e82195 100644 --- a/aiogram/dispatcher/router.py +++ b/aiogram/dispatcher/router.py @@ -8,6 +8,7 @@ from ..utils.imports import import_module from ..utils.warnings import CodeHasNoEffect from .event.bases import REJECTED, UNHANDLED from .event.event import EventObserver +from .event.handler import HandlerType from .event.telegram import TelegramEventObserver from .filters import BUILTIN_FILTERS @@ -253,7 +254,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.message @property @@ -264,7 +264,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.edited_message @property @@ -275,7 +274,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.channel_post @property @@ -286,7 +284,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.edited_channel_post @property @@ -297,7 +294,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.inline_query @property @@ -308,7 +304,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.chosen_inline_result @property @@ -319,7 +314,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.callback_query @property @@ -330,7 +324,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.shipping_query @property @@ -341,7 +334,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.pre_checkout_query @property @@ -352,7 +344,6 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.poll @property @@ -363,9 +354,38 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.poll_answer + @property + def my_chat_member_handler(self) -> TelegramEventObserver: + warnings.warn( + "`Router.my_chat_member_handler(...)` is deprecated and will be removed in version 3.2 " + "use `Router.my_chat_member(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.my_chat_member + + @property + def chat_member_handler(self) -> TelegramEventObserver: + warnings.warn( + "`Router.chat_member_handler(...)` is deprecated and will be removed in version 3.2 " + "use `Router.chat_member(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.chat_member + + @property + def chat_join_request_handler(self) -> TelegramEventObserver: + warnings.warn( + "`Router.chat_join_request_handler(...)` is deprecated and will be removed in version 3.2 " + "use `Router.chat_join_request(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.chat_join_request + @property def errors_handler(self) -> TelegramEventObserver: warnings.warn( @@ -374,5 +394,139 @@ class Router: DeprecationWarning, stacklevel=2, ) - return self.errors + + def register_message(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_message(...)` is deprecated and will be removed in version 3.2 " + "use `Router.message.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.message.register(*args, **kwargs) + + def register_edited_message(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_edited_message(...)` is deprecated and will be removed in version 3.2 " + "use `Router.edited_message.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.edited_message.register(*args, **kwargs) + + def register_channel_post(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_channel_post(...)` is deprecated and will be removed in version 3.2 " + "use `Router.channel_post.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.channel_post.register(*args, **kwargs) + + def register_edited_channel_post(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_edited_channel_post(...)` is deprecated and will be removed in version 3.2 " + "use `Router.edited_channel_post.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.edited_channel_post.register(*args, **kwargs) + + def register_inline_query(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_inline_query(...)` is deprecated and will be removed in version 3.2 " + "use `Router.inline_query.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.inline_query.register(*args, **kwargs) + + def register_chosen_inline_result(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_chosen_inline_result(...)` is deprecated and will be removed in version 3.2 " + "use `Router.chosen_inline_result.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.chosen_inline_result.register(*args, **kwargs) + + def register_callback_query(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_callback_query(...)` is deprecated and will be removed in version 3.2 " + "use `Router.callback_query.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.callback_query.register(*args, **kwargs) + + def register_shipping_query(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_shipping_query(...)` is deprecated and will be removed in version 3.2 " + "use `Router.shipping_query.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.shipping_query.register(*args, **kwargs) + + def register_pre_checkout_query(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_pre_checkout_query(...)` is deprecated and will be removed in version 3.2 " + "use `Router.pre_checkout_query.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.pre_checkout_query.register(*args, **kwargs) + + def register_poll(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_poll(...)` is deprecated and will be removed in version 3.2 " + "use `Router.poll.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.poll.register(*args, **kwargs) + + def register_poll_answer(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_poll_answer(...)` is deprecated and will be removed in version 3.2 " + "use `Router.poll_answer.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.poll_answer.register(*args, **kwargs) + + def register_my_chat_member(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_my_chat_member(...)` is deprecated and will be removed in version 3.2 " + "use `Router.my_chat_member.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.my_chat_member.register(*args, **kwargs) + + def register_chat_member(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_chat_member(...)` is deprecated and will be removed in version 3.2 " + "use `Router.chat_member.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.chat_member.register(*args, **kwargs) + + def register_chat_join_request(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_chat_join_request(...)` is deprecated and will be removed in version 3.2 " + "use `Router.chat_join_request.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.chat_join_request.register(*args, **kwargs) + + def register_errors(self, *args: Any, **kwargs: Any) -> HandlerType: + warnings.warn( + "`Router.register_errors(...)` is deprecated and will be removed in version 3.2 " + "use `Router.errors.register(...)`", + DeprecationWarning, + stacklevel=2, + ) + return self.errors.register(*args, **kwargs) diff --git a/aiogram/methods/base.py b/aiogram/methods/base.py index 6b1d9619..4d787a7b 100644 --- a/aiogram/methods/base.py +++ b/aiogram/methods/base.py @@ -84,6 +84,8 @@ class TelegramMethod(abc.ABC, BaseModel, Generic[TelegramType]): async def emit(self, bot: Bot) -> TelegramType: return await bot(self) + as_ = emit + def __await__(self) -> Generator[Any, None, TelegramType]: from aiogram.client.bot import Bot diff --git a/aiogram/types/keyboard_button.py b/aiogram/types/keyboard_button.py index c1e3e5f5..c4eed8d1 100644 --- a/aiogram/types/keyboard_button.py +++ b/aiogram/types/keyboard_button.py @@ -8,6 +8,10 @@ if TYPE_CHECKING: from .keyboard_button_poll_type import KeyboardButtonPollType +class WebApp(MutableTelegramObject): + url: str + + class KeyboardButton(MutableTelegramObject): """ This object represents one button of the reply keyboard. For simple text buttons *String* can be used instead of this object to specify text of the button. Optional fields *request_contact*, *request_location*, and *request_poll* are mutually exclusive. @@ -26,3 +30,4 @@ class KeyboardButton(MutableTelegramObject): """*Optional*. If :code:`True`, the user's current location will be sent when the button is pressed. Available in private chats only""" request_poll: Optional[KeyboardButtonPollType] = None """*Optional*. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only""" + web_app: Optional[WebApp] = None diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 5ee37d00..d1ab7cbd 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -71,7 +71,7 @@ if TYPE_CHECKING: from .voice_chat_started import VoiceChatStarted -class Message(TelegramObject): +class _BaseMessage(TelegramObject): """ This object represents a message. @@ -195,6 +195,8 @@ class Message(TelegramObject): reply_markup: Optional[InlineKeyboardMarkup] = None """*Optional*. Inline keyboard attached to the message. :code:`login_url` buttons are represented as ordinary :code:`url` buttons.""" + +class Message(_BaseMessage): @property def content_type(self) -> str: if self.text: @@ -265,11 +267,8 @@ class Message(TelegramObject): return ContentType.UNKNOWN def _unparse_entities(self, text_decoration: TextDecoration) -> str: - text = self.text or self.caption - if text is None: - raise TypeError("This message doesn't have any text.") - - entities = self.entities or self.caption_entities + text = self.text or self.caption or "" + entities = self.entities or self.caption_entities or [] return text_decoration.unparse(text=text, entities=entities) @property diff --git a/aiogram/utils/chat_action.py b/aiogram/utils/chat_action.py index 2a9dddcc..358c9336 100644 --- a/aiogram/utils/chat_action.py +++ b/aiogram/utils/chat_action.py @@ -12,7 +12,7 @@ from aiogram.types import Message, TelegramObject logger = logging.getLogger(__name__) DEFAULT_INTERVAL = 5.0 -DEFAULT_INITIAL_SLEEP = 0.1 +DEFAULT_INITIAL_SLEEP = 0.0 class ChatActionSender: diff --git a/aiogram/utils/link.py b/aiogram/utils/link.py index 87d402e2..e4bc28f2 100644 --- a/aiogram/utils/link.py +++ b/aiogram/utils/link.py @@ -1,18 +1,28 @@ -from typing import Any +from typing import Any, Optional from urllib.parse import urlencode, urljoin +BASE_DOCS_URL = "https://docs.aiogram.dev/" +BRANCH = "dev-3.x" + +BASE_PAGE_URL = f"{BASE_DOCS_URL}/en/{BRANCH}/" + + +def _format_url(url: str, *path: str, fragment_: Optional[str] = None, **query: Any) -> str: + url = urljoin(url, "/".join(path), allow_fragments=True) + if query: + url += "?" + urlencode(query) + if fragment_: + url += "#" + fragment_ + return url + + +def docs_url(*path: str, fragment_: Optional[str] = None, **query: Any) -> str: + return _format_url(BASE_PAGE_URL, *path, fragment_=fragment_, **query) + def create_tg_link(link: str, **kwargs: Any) -> str: - url = f"tg://{link}" - if kwargs: - query = urlencode(kwargs) - url += f"?{query}" - return url + return _format_url(f"tg://{link}", **kwargs) -def create_telegram_link(uri: str, **kwargs: Any) -> str: - url = urljoin("https://t.me", uri) - if kwargs: - query = urlencode(query=kwargs) - url += f"?{query}" - return url +def create_telegram_link(*path: str, **kwargs: Any) -> str: + return _format_url("https://t.me", *path, **kwargs) diff --git a/aiogram/utils/text_decorations.py b/aiogram/utils/text_decorations.py index bd45fae8..70b5bc63 100644 --- a/aiogram/utils/text_decorations.py +++ b/aiogram/utils/text_decorations.py @@ -37,7 +37,7 @@ class TextDecoration(ABC): if entity.type in {"bot_command", "url", "mention", "phone_number"}: # This entities should not be changed return text - if entity.type in {"bold", "italic", "code", "underline", "strikethrough"}: + if entity.type in {"bold", "italic", "code", "underline", "strikethrough", "spoiler"}: return cast(str, getattr(self, entity.type)(value=text)) if entity.type == "pre": return ( @@ -102,35 +102,39 @@ class TextDecoration(ABC): yield self.quote(remove_surrogates(text[offset:length])) @abstractmethod - def link(self, value: str, link: str) -> str: # pragma: no cover + def link(self, value: str, link: str) -> str: pass @abstractmethod - def bold(self, value: str) -> str: # pragma: no cover + def bold(self, value: str) -> str: pass @abstractmethod - def italic(self, value: str) -> str: # pragma: no cover + def italic(self, value: str) -> str: pass @abstractmethod - def code(self, value: str) -> str: # pragma: no cover + def code(self, value: str) -> str: pass @abstractmethod - def pre(self, value: str) -> str: # pragma: no cover + def pre(self, value: str) -> str: pass @abstractmethod - def pre_language(self, value: str, language: str) -> str: # pragma: no cover + def pre_language(self, value: str, language: str) -> str: pass @abstractmethod - def underline(self, value: str) -> str: # pragma: no cover + def underline(self, value: str) -> str: pass @abstractmethod - def strikethrough(self, value: str) -> str: # pragma: no cover + def strikethrough(self, value: str) -> str: + pass + + @abstractmethod + def spoiler(self, value: str) -> str: pass @abstractmethod @@ -139,14 +143,20 @@ class TextDecoration(ABC): class HtmlDecoration(TextDecoration): + BOLD_TAG = "b" + ITALIC_TAG = "i" + UNDERLINE_TAG = "u" + STRIKETHROUGH_TAG = "s" + SPOILER_TAG = ('span class="tg-spoiler"', "span") + def link(self, value: str, link: str) -> str: return f'{value}' def bold(self, value: str) -> str: - return f"{value}" + return f"<{self.BOLD_TAG}>{value}" def italic(self, value: str) -> str: - return f"{value}" + return f"<{self.ITALIC_TAG}>{value}" def code(self, value: str) -> str: return f"{value}" @@ -158,10 +168,13 @@ class HtmlDecoration(TextDecoration): return f'
{value}
' def underline(self, value: str) -> str: - return f"{value}" + return f"<{self.UNDERLINE_TAG}>{value}" def strikethrough(self, value: str) -> str: - return f"{value}" + return f"<{self.STRIKETHROUGH_TAG}>{value}" + + def spoiler(self, value: str) -> str: + return f"<{self.SPOILER_TAG[0]}>{value}" def quote(self, value: str) -> str: return html.escape(value, quote=False) @@ -194,6 +207,9 @@ class MarkdownDecoration(TextDecoration): def strikethrough(self, value: str) -> str: return f"~{value}~" + def spoiler(self, value: str) -> str: + return f"|{value}|" + def quote(self, value: str) -> str: return re.sub(pattern=self.MARKDOWN_QUOTE_PATTERN, repl=r"\\\1", string=value) diff --git a/docs/dispatcher/filters/callback_data.rst b/docs/dispatcher/filters/callback_data.rst new file mode 100644 index 00000000..6ff777c4 --- /dev/null +++ b/docs/dispatcher/filters/callback_data.rst @@ -0,0 +1,118 @@ +============================== +Callback Data Factory & Filter +============================== + +.. autoclass:: aiogram.dispatcher.filters.callback_data.CallbackData + :members: + :member-order: bysource + :undoc-members: False + +Usage +===== + +Create subclass of :code:`CallbackData`: + +.. code-block:: python + + class MyCallback(CallbackData, prefix="my"): + foo: str + bar: int + +After that you can generate any callback based on this class, for example: + +.. code-block:: python + + cb1 = MyCallback(foo="demo", bar=42) + cb1.pack() # returns 'my:demo:42' + cb1.unpack('my:demo:42') # returns + +So... Now you can use this class to generate any callbacks with defined structure + +.. code-block:: python + + ... + # Pass it into the markup + InlineKeyboardButton( + text="demo", + callback_data=MyCallback(foo="demo", bar="42").pack() # value should be packed to string + ) + ... + +... and handle by specific rules + +.. code-block:: python + + # Filter callback by type and value of field :code:`foo` + @router.callback_query(MyCallback.filter(F.foo == "demo")) + async def my_callback_foo(query: CallbackQuery, callback_data: MyCallback): + await query.answer(...) + ... + print("bar =", callback_data.bar) + +Also can be used in :doc:`Keyboard builder `: + +.. code-block:: python + + builder = InlineKeyboardBuilder() + builder.button( + text="demo", + callback_data=MyCallback(foo="demo", bar="42") # Value can be not packed to string inplace, because builder knows what to do with callback instance + ) + + +Another abstract example: + +.. code-block:: python + + class Action(str, Enum): + ban = "ban" + kick = "kick" + warn = "warn" + + class AdminAction(CallbackData, prefix="adm"): + action: Action + chat_id: int + user_id: int + + ... + # Inside handler + builder = InlineKeyboardBuilder() + for action in Action: + builder.button( + text=action.value.title(), + callback_data=AdminAction(action=action, chat_id=chat_id, user_id=user_id), + ) + await bot.send_message( + chat_id=admins_chat, + text=f"What do you want to do with {html.quote(name)}", + reply_markup=builder.as_markup(), + ) + ... + + @router.callback_query(AdminAction.filter(F.action == Action.ban)) + async def ban_user(query: CallbackQuery, callback_data: AdminAction, bot: Bot): + await bot.ban_chat_member( + chat_id=callback_data.chat_id, + user_id=callback_data.user_id, + ... + ) + +Known limitations +================= + +Allowed types and their subclasses: + +- :code:`str` +- :code:`int` +- :code:`bool` +- :code:`float` +- :code:`Decimal` (:code:`from decimal import Decimal`) +- :code:`Fraction` (:code:`from fractions import Fraction`) +- :code:`UUID` (:code:`from uuid import UUID`) +- :code:`Enum` (:code:`from enum import Enum`, only for string enums) +- :code:`IntEnum` (:code:`from enum import IntEnum`, only for int enums) + + +.. note:: + + Note that the integer Enum's should be always is subclasses of :code:`IntEnum` in due to parsing issues. diff --git a/docs/dispatcher/filters/index.rst b/docs/dispatcher/filters/index.rst index 106e0b0c..5c54f1bd 100644 --- a/docs/dispatcher/filters/index.rst +++ b/docs/dispatcher/filters/index.rst @@ -22,6 +22,7 @@ Here is list of builtin filters: exception magic_filters magic_data + callback_data Own filters specification ========================= diff --git a/docs/utils/index.rst b/docs/utils/index.rst index 9390e8ac..4f6eccf5 100644 --- a/docs/utils/index.rst +++ b/docs/utils/index.rst @@ -4,6 +4,6 @@ Utils .. toctree:: - i18n keyboard + i18n chat_action diff --git a/examples/echo_bot.py b/examples/echo_bot.py index 3c9b1218..f590ee57 100644 --- a/examples/echo_bot.py +++ b/examples/echo_bot.py @@ -1,5 +1,4 @@ import logging -from typing import Any from aiogram import Bot, Dispatcher, types from aiogram.types import Message diff --git a/mypy.ini b/mypy.ini index 2c1b8b31..c6ca9065 100644 --- a/mypy.ini +++ b/mypy.ini @@ -30,7 +30,7 @@ ignore_missing_imports = True [mypy-uvloop] ignore_missing_imports = True -[mypy-aioredis] +[mypy-redis.*] ignore_missing_imports = True [mypy-babel.*] diff --git a/poetry.lock b/poetry.lock index bd66ff27..0ac8ef45 100644 --- a/poetry.lock +++ b/poetry.lock @@ -39,21 +39,6 @@ aiohttp = ">=2.3.2" attrs = ">=19.2.0" python-socks = {version = ">=2.0.0,<3.0.0", extras = ["asyncio"]} -[[package]] -name = "aioredis" -version = "2.0.1" -description = "asyncio (PEP 3156) Redis support" -category = "main" -optional = true -python-versions = ">=3.6" - -[package.dependencies] -async-timeout = "*" -typing-extensions = "*" - -[package.extras] -hiredis = ["hiredis (>=1.0)"] - [[package]] name = "aiosignal" version = "1.2.0" @@ -75,7 +60,7 @@ python-versions = "*" [[package]] name = "appnope" -version = "0.1.2" +version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" category = "dev" optional = false @@ -109,15 +94,12 @@ test = ["astroid", "pytest"] [[package]] name = "async-timeout" -version = "4.0.0" +version = "4.0.2" description = "Timeout context manager for asyncio programs" category = "main" optional = false python-versions = ">=3.6" -[package.dependencies] -typing-extensions = ">=3.6.5" - [[package]] name = "asynctest" version = "0.13.0" @@ -136,17 +118,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.2.0" +version = "21.4.0" description = "Classes Without Boilerplate" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] [[package]] name = "babel" @@ -167,25 +149,13 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "backports.entry-points-selectable" -version = "1.1.0" -description = "Compatibility shim providing selectable entry points for older implementations" -category = "dev" -optional = false -python-versions = ">=2.7" - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"] - [[package]] name = "beautifulsoup4" -version = "4.10.0" +version = "4.11.1" description = "Screen-scraping library" category = "main" optional = true -python-versions = ">3.0.0" +python-versions = ">=3.6.0" [package.dependencies] soupsieve = ">1.2" @@ -196,7 +166,7 @@ lxml = ["lxml"] [[package]] name = "black" -version = "22.1.0" +version = "22.3.0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -207,7 +177,7 @@ click = ">=8.0.0" mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = ">=1.1.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] @@ -234,7 +204,7 @@ python-versions = ">=3.6.1" [[package]] name = "charset-normalizer" -version = "2.0.7" +version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -245,11 +215,11 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.3" +version = "8.1.2" description = "Composable command line interface toolkit" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -289,15 +259,29 @@ toml = ["tomli"] [[package]] name = "decorator" -version = "5.1.0" +version = "5.1.1" description = "Decorators for Humans" category = "dev" optional = false python-versions = ">=3.5" +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["tox", "bump2version (<1)", "sphinx (<2)", "importlib-metadata (<3)", "importlib-resources (<4)", "configparser (<5)", "sphinxcontrib-websupport (<2)", "zipp (<2)", "PyTest (<5)", "PyTest-Cov (<2.6)", "pytest", "pytest-cov"] + [[package]] name = "distlib" -version = "0.3.3" +version = "0.3.4" description = "Distribution utilities" category = "dev" optional = false @@ -313,7 +297,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "executing" -version = "0.8.2" +version = "0.8.3" description = "Get the currently executing AST node of a frame, and other information" category = "dev" optional = false @@ -321,11 +305,11 @@ python-versions = "*" [[package]] name = "filelock" -version = "3.3.2" +version = "3.6.0" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] @@ -344,31 +328,17 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" -[[package]] -name = "flake8-html" -version = "0.4.1" -description = "Generate HTML reports of flake8 violations" -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -flake8 = ">=3.3.0" -importlib-metadata = "*" -jinja2 = ">=2.9.0" -pygments = ">=2.2.0" - [[package]] name = "frozenlist" -version = "1.2.0" +version = "1.3.0" description = "A list-like structure which implements collections.abc.MutableSequence" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "furo" -version = "2022.2.14.1" +version = "2022.4.7" description = "A clean customisable Sphinx documentation theme." category = "main" optional = true @@ -379,20 +349,16 @@ beautifulsoup4 = "*" pygments = ">=2.7,<3.0" sphinx = ">=4.0,<5.0" -[package.extras] -test = ["pytest", "pytest-cov", "pytest-xdist"] -doc = ["myst-parser", "sphinx-copybutton", "sphinx-design", "sphinx-inline-tabs"] - [[package]] name = "identify" -version = "2.3.4" +version = "2.4.12" description = "File identification library for Python" category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.extras] -license = ["editdistance-s"] +license = ["ukkonen"] [[package]] name = "idna" @@ -404,7 +370,7 @@ python-versions = ">=3.5" [[package]] name = "imagesize" -version = "1.2.0" +version = "1.3.0" description = "Getting image size from png/jpeg/jpeg2000/gif file" category = "main" optional = true @@ -412,19 +378,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.8.1" +version = "4.11.3" description = "Read metadata from Python packages" -category = "dev" -optional = false -python-versions = ">=3.6" +category = "main" +optional = true +python-versions = ">=3.7" [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] [[package]] name = "incremental" @@ -447,7 +413,7 @@ python-versions = "*" [[package]] name = "ipython" -version = "8.0.1" +version = "8.2.0" description = "IPython: Productive Interactive Computing" category = "dev" optional = false @@ -456,7 +422,6 @@ python-versions = ">=3.8" [package.dependencies] appnope = {version = "*", markers = "sys_platform == \"darwin\""} backcall = "*" -black = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" jedi = ">=0.16" @@ -464,21 +429,22 @@ matplotlib-inline = "*" 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" -pygments = "*" +pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" [package.extras] -all = ["Sphinx (>=1.3)", "curio", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.19)", "pandas", "pygments", "pytest", "pytest-asyncio", "qtconsole", "testpath", "trio"] +all = ["black", "Sphinx (>=1.3)", "ipykernel", "nbconvert", "nbformat", "ipywidgets", "notebook", "ipyparallel", "qtconsole", "pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "numpy (>=1.19)", "pandas", "trio"] +black = ["black"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] -notebook = ["notebook", "ipywidgets"] +notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest", "pytest-asyncio", "testpath", "pygments"] -test_extra = ["pytest", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "pygments", "trio"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.19)", "pandas", "trio"] [[package]] name = "isort" @@ -496,7 +462,7 @@ plugins = ["setuptools"] [[package]] name = "jedi" -version = "0.18.0" +version = "0.18.1" description = "An autocompletion tool for Python that can be used for text editors." category = "dev" optional = false @@ -507,15 +473,15 @@ parso = ">=0.8.0,<0.9.0" [package.extras] qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"] +testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jinja2" -version = "3.0.2" +version = "3.1.1" description = "A very fast and expressive template engine." category = "main" -optional = false -python-versions = ">=3.6" +optional = true +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=2.0" @@ -537,7 +503,7 @@ tornado = {version = "*", markers = "python_version > \"2.7\""} [[package]] name = "magic-filter" -version = "1.0.5" +version = "1.0.6" description = "This package provides magic filter based on dynamic attribute getter" category = "main" optional = false @@ -545,12 +511,15 @@ python-versions = ">=3.6.2,<4.0.0" [[package]] name = "markdown" -version = "3.3.4" +version = "3.3.6" description = "Python implementation of Markdown." category = "main" optional = true python-versions = ">=3.6" +[package.dependencies] +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} + [package.extras] testing = ["coverage", "pyyaml"] @@ -567,11 +536,11 @@ markdown = "*" [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" -optional = false -python-versions = ">=3.6" +optional = true +python-versions = ">=3.7" [[package]] name = "matplotlib-inline" @@ -594,15 +563,15 @@ python-versions = "*" [[package]] name = "multidict" -version = "5.2.0" +version = "6.0.2" description = "multidict implementation" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "mypy" -version = "0.931" +version = "0.942" description = "Optional static typing for Python" category = "dev" optional = false @@ -616,6 +585,7 @@ typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] [[package]] name = "mypy-extensions" @@ -646,7 +616,7 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "parso" -version = "0.8.2" +version = "0.8.3" description = "A Python Parser" category = "dev" optional = false @@ -685,11 +655,11 @@ python-versions = "*" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] @@ -709,11 +679,11 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.17.0" +version = "2.18.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] cfgv = ">=2.0.0" @@ -725,7 +695,7 @@ virtualenv = ">=20.0.8" [[package]] name = "prompt-toolkit" -version = "3.0.22" +version = "3.0.29" description = "Library for building powerful interactive command lines in Python" category = "dev" optional = false @@ -802,7 +772,7 @@ python-versions = ">=3.5" [[package]] name = "pymdown-extensions" -version = "9.2" +version = "9.3" description = "Extension pack for Python Markdown." category = "main" optional = true @@ -813,22 +783,22 @@ Markdown = ">=3.2" [[package]] name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" +version = "3.0.8" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pytest" -version = "7.0.1" +version = "7.1.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} @@ -861,7 +831,7 @@ testing = ["coverage (==6.2)", "mypy (==0.931)"] [[package]] name = "pytest-asyncio" -version = "0.18.1" +version = "0.18.3" description = "Pytest support for asyncio" category = "dev" optional = false @@ -871,7 +841,7 @@ python-versions = ">=3.7" pytest = ">=6.1.0" [package.extras] -testing = ["coverage (==6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (==0.931)"] +testing = ["coverage (==6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (==0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" @@ -913,14 +883,14 @@ pytest = ">=3.2.5" [[package]] name = "pytest-metadata" -version = "1.11.0" +version = "2.0.0" description = "pytest plugin for test session metadata" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7,<4.0" [package.dependencies] -pytest = ">=2.9.0" +pytest = ">=7.1.1,<8.0.0" [[package]] name = "pytest-mock" @@ -975,7 +945,7 @@ trio = ["trio (>=0.16.0)"] [[package]] name = "pytz" -version = "2021.3" +version = "2022.1" description = "World timezone definitions, modern and historical" category = "main" optional = true @@ -989,9 +959,26 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "redis" +version = "4.2.2" +description = "Python client for Redis database and key-value store" +category = "main" +optional = true +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=4.0.2" +deprecated = ">=1.2.3" +packaging = ">=20.4" + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + [[package]] name = "requests" -version = "2.26.0" +version = "2.27.1" description = "Python HTTP for Humans." category = "main" optional = true @@ -1009,7 +996,7 @@ use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "sentry-sdk" -version = "1.5.5" +version = "1.5.8" description = "Python client for Sentry (https://sentry.io)" category = "dev" optional = false @@ -1047,7 +1034,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "snowballstemmer" -version = "2.1.0" +version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." category = "main" optional = true @@ -1055,7 +1042,7 @@ python-versions = "*" [[package]] name = "soupsieve" -version = "2.3" +version = "2.3.2" description = "A modern CSS selector implementation for Beautiful Soup." category = "main" optional = true @@ -1063,7 +1050,7 @@ python-versions = ">=3.6" [[package]] name = "sphinx" -version = "4.2.0" +version = "4.5.0" description = "Python documentation generator" category = "main" optional = true @@ -1075,6 +1062,7 @@ babel = ">=1.3" colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} docutils = ">=0.14,<0.18" imagesize = "*" +importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} Jinja2 = ">=2.3" packaging = "*" Pygments = ">=2.0" @@ -1089,7 +1077,7 @@ sphinxcontrib-serializinghtml = ">=1.1.5" [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.900)", "docutils-stubs", "types-typed-ast", "types-pkg-resources", "types-requests"] +lint = ["flake8 (>=3.5.0)", "isort", "mypy (>=0.931)", "docutils-stubs", "types-typed-ast", "types-requests"] test = ["pytest", "pytest-cov", "html5lib", "cython", "typed-ast"] [[package]] @@ -1265,11 +1253,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" -version = "1.2.2" +version = "2.0.1" description = "A lil' TOML parser" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "tornado" @@ -1318,14 +1306,14 @@ python-versions = ">=3.6" [[package]] name = "urllib3" -version = "1.26.7" +version = "1.26.9" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "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)"] @@ -1344,14 +1332,13 @@ test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,< [[package]] name = "virtualenv" -version = "20.10.0" +version = "20.14.0" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] -"backports.entry-points-selectable" = ">=1.0.4" distlib = ">=0.3.1,<1" filelock = ">=3.2,<4" platformdirs = ">=2,<3" @@ -1369,6 +1356,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "wrapt" +version = "1.14.0" +description = "Module for decorators, wrappers and monkey patching." +category = "main" +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + [[package]] name = "yarl" version = "1.7.2" @@ -1383,27 +1378,27 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.6.0" +version = "3.8.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "dev" -optional = false -python-versions = ">=3.6" +category = "main" +optional = true +python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [extras] docs = ["Sphinx", "sphinx-intl", "sphinx-autobuild", "sphinx-copybutton", "furo", "sphinx-prompt", "Sphinx-Substitution-Extensions", "towncrier", "pygments", "pymdown-extensions", "markdown-include"] fast = ["uvloop"] i18n = ["Babel"] proxy = ["aiohttp-socks"] -redis = ["aioredis"] +redis = ["redis"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "1f20a68c7d58bc8113a73a2cef1cf9e0027fc0a69507e3ac0a81d158e33b3acc" +content-hash = "610623143deda7ddf0a604a0447178549a89c8914509d2c1bff4367917e8aaa1" [metadata.files] aiofiles = [ @@ -1488,10 +1483,6 @@ aiohttp-socks = [ {file = "aiohttp_socks-0.7.1-py3-none-any.whl", hash = "sha256:94bcff5ef73611c6c6231c2ffc1be4af1599abec90dbd2fdbbd63233ec2fb0ff"}, {file = "aiohttp_socks-0.7.1.tar.gz", hash = "sha256:2215cac4891ef3fa14b7d600ed343ed0f0a670c23b10e4142aa862b3db20341a"}, ] -aioredis = [ - {file = "aioredis-2.0.1-py3-none-any.whl", hash = "sha256:9ac0d0b3b485d293b8ca1987e6de8658d7dafcca1cddfcd1d506cae8cdebfdd6"}, - {file = "aioredis-2.0.1.tar.gz", hash = "sha256:eaa51aaf993f2d71f54b70527c440437ba65340588afeb786cd87c55c89cd98e"}, -] aiosignal = [ {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"}, {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"}, @@ -1501,8 +1492,8 @@ alabaster = [ {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] appnope = [ - {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, - {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, ] aresponses = [ {file = "aresponses-2.1.5-py3-none-any.whl", hash = "sha256:06161209a39880aaf8ec3c67ab76d677aaea41944672e6a3e23a4464544879b1"}, @@ -1513,8 +1504,8 @@ asttokens = [ {file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"}, ] async-timeout = [ - {file = "async-timeout-4.0.0.tar.gz", hash = "sha256:7d87a4e8adba8ededb52e579ce6bc8276985888913620c935094c2276fd83382"}, - {file = "async_timeout-4.0.0-py3-none-any.whl", hash = "sha256:f3303dddf6cafa748a92747ab6c2ecf60e0aeca769aee4c151adfce243a05d9b"}, + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] asynctest = [ {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, @@ -1525,8 +1516,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] babel = [ {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, @@ -1536,38 +1527,34 @@ backcall = [ {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, ] -"backports.entry-points-selectable" = [ - {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"}, - {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"}, -] beautifulsoup4 = [ - {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, - {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, + {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, + {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, ] black = [ - {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, - {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, - {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, - {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, - {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, - {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, - {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, - {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, - {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, - {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, - {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, - {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, - {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, - {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, - {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, - {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, - {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, - {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, - {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"}, + {file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"}, + {file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"}, + {file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"}, + {file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"}, + {file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"}, + {file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"}, + {file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"}, + {file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"}, + {file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"}, + {file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"}, + {file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"}, + {file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"}, + {file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"}, + {file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"}, + {file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"}, + {file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"}, + {file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"}, + {file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"}, + {file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"}, + {file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"}, ] certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, @@ -1578,12 +1565,12 @@ cfgv = [ {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, - {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, + {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, + {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, ] click-default-group = [ {file = "click-default-group-1.2.2.tar.gz", hash = "sha256:d9560e8e8dfa44b3562fbc9425042a0fd6d21956fcc2db0077f63f34253ab904"}, @@ -1636,126 +1623,113 @@ coverage = [ {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, ] decorator = [ - {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"}, - {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"}, + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] +deprecated = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, ] distlib = [ - {file = "distlib-0.3.3-py2.py3-none-any.whl", hash = "sha256:c8b54e8454e5bf6237cc84c20e8264c3e991e824ef27e8f1e81049867d861e31"}, - {file = "distlib-0.3.3.zip", hash = "sha256:d982d0751ff6eaaab5e2ec8e691d949ee80eddf01a62eaa96ddb11531fe16b05"}, + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, ] docutils = [ {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"}, {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] executing = [ - {file = "executing-0.8.2-py2.py3-none-any.whl", hash = "sha256:32fc6077b103bd19e6494a72682d66d5763cf20a106d5aa7c5ccbea4e47b0df7"}, - {file = "executing-0.8.2.tar.gz", hash = "sha256:c23bf42e9a7b9b212f185b1b2c3c91feb895963378887bb10e64a2e612ec0023"}, + {file = "executing-0.8.3-py2.py3-none-any.whl", hash = "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9"}, + {file = "executing-0.8.3.tar.gz", hash = "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501"}, ] filelock = [ - {file = "filelock-3.3.2-py3-none-any.whl", hash = "sha256:bb2a1c717df74c48a2d00ed625e5a66f8572a3a30baacb7657add1d7bac4097b"}, - {file = "filelock-3.3.2.tar.gz", hash = "sha256:7afc856f74fa7006a289fd10fa840e1eebd8bbff6bffb69c26c54a0512ea8cf8"}, + {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"}, + {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"}, ] flake8 = [ {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, ] -flake8-html = [ - {file = "flake8-html-0.4.1.tar.gz", hash = "sha256:2fb436cbfe1e109275bc8fb7fdd0cb00e67b3b48cfeb397309b6b2c61eeb4cb4"}, - {file = "flake8_html-0.4.1-py2.py3-none-any.whl", hash = "sha256:17324eb947e7006807e4184ee26953e67baf421b3cf9e646a38bfec34eec5a94"}, -] frozenlist = [ - {file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:977a1438d0e0d96573fd679d291a1542097ea9f4918a8b6494b06610dfeefbf9"}, - {file = "frozenlist-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8d86547a5e98d9edd47c432f7a14b0c5592624b496ae9880fb6332f34af1edc"}, - {file = "frozenlist-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:181754275d5d32487431a0a29add4f897968b7157204bc1eaaf0a0ce80c5ba7d"}, - {file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5df31bb2b974f379d230a25943d9bf0d3bc666b4b0807394b131a28fca2b0e5f"}, - {file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4766632cd8a68e4f10f156a12c9acd7b1609941525569dd3636d859d79279ed3"}, - {file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16eef427c51cb1203a7c0ab59d1b8abccaba9a4f58c4bfca6ed278fc896dc193"}, - {file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:01d79515ed5aa3d699b05f6bdcf1fe9087d61d6b53882aa599a10853f0479c6c"}, - {file = "frozenlist-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:28e164722ea0df0cf6d48c4d5bdf3d19e87aaa6dfb39b0ba91153f224b912020"}, - {file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e63ad0beef6ece06475d29f47d1f2f29727805376e09850ebf64f90777962792"}, - {file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41de4db9b9501679cf7cddc16d07ac0f10ef7eb58c525a1c8cbff43022bddca4"}, - {file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c6a9d84ee6427b65a81fc24e6ef589cb794009f5ca4150151251c062773e7ed2"}, - {file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:f5f3b2942c3b8b9bfe76b408bbaba3d3bb305ee3693e8b1d631fe0a0d4f93673"}, - {file = "frozenlist-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c98d3c04701773ad60d9545cd96df94d955329efc7743fdb96422c4b669c633b"}, - {file = "frozenlist-1.2.0-cp310-cp310-win32.whl", hash = "sha256:72cfbeab7a920ea9e74b19aa0afe3b4ad9c89471e3badc985d08756efa9b813b"}, - {file = "frozenlist-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:11ff401951b5ac8c0701a804f503d72c048173208490c54ebb8d7bb7c07a6d00"}, - {file = "frozenlist-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b46f997d5ed6d222a863b02cdc9c299101ee27974d9bbb2fd1b3c8441311c408"}, - {file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351686ca020d1bcd238596b1fa5c8efcbc21bffda9d0efe237aaa60348421e2a"}, - {file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfbaa08cf1452acad9cb1c1d7b89394a41e712f88df522cea1a0f296b57782a0"}, - {file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2ae2f5e9fa10805fb1c9adbfefaaecedd9e31849434be462c3960a0139ed729"}, - {file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6790b8d96bbb74b7a6f4594b6f131bd23056c25f2aa5d816bd177d95245a30e3"}, - {file = "frozenlist-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:41f62468af1bd4e4b42b5508a3fe8cc46a693f0cdd0ca2f443f51f207893d837"}, - {file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:ec6cf345771cdb00791d271af9a0a6fbfc2b6dd44cb753f1eeaa256e21622adb"}, - {file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:14a5cef795ae3e28fb504b73e797c1800e9249f950e1c964bb6bdc8d77871161"}, - {file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8b54cdd2fda15467b9b0bfa78cee2ddf6dbb4585ef23a16e14926f4b076dfae4"}, - {file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f025f1d6825725b09c0038775acab9ae94264453a696cc797ce20c0769a7b367"}, - {file = "frozenlist-1.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:84e97f59211b5b9083a2e7a45abf91cfb441369e8bb6d1f5287382c1c526def3"}, - {file = "frozenlist-1.2.0-cp36-cp36m-win32.whl", hash = "sha256:c5328ed53fdb0a73c8a50105306a3bc013e5ca36cca714ec4f7bd31d38d8a97f"}, - {file = "frozenlist-1.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9ade70aea559ca98f4b1b1e5650c45678052e76a8ab2f76d90f2ac64180215a2"}, - {file = "frozenlist-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0d3ffa8772464441b52489b985d46001e2853a3b082c655ec5fad9fb6a3d618"}, - {file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3457f8cf86deb6ce1ba67e120f1b0128fcba1332a180722756597253c465fc1d"}, - {file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a72eecf37eface331636951249d878750db84034927c997d47f7f78a573b72b"}, - {file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:acc4614e8d1feb9f46dd829a8e771b8f5c4b1051365d02efb27a3229048ade8a"}, - {file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:87521e32e18a2223311afc2492ef2d99946337da0779ddcda77b82ee7319df59"}, - {file = "frozenlist-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b4c7665a17c3a5430edb663e4ad4e1ad457614d1b2f2b7f87052e2ef4fa45ca"}, - {file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ed58803563a8c87cf4c0771366cf0ad1aa265b6b0ae54cbbb53013480c7ad74d"}, - {file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa44c4740b4e23fcfa259e9dd52315d2b1770064cde9507457e4c4a65a04c397"}, - {file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2de5b931701257d50771a032bba4e448ff958076380b049fd36ed8738fdb375b"}, - {file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6e105013fa84623c057a4381dc8ea0361f4d682c11f3816cc80f49a1f3bc17c6"}, - {file = "frozenlist-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:705c184b77565955a99dc360f359e8249580c6b7eaa4dc0227caa861ef46b27a"}, - {file = "frozenlist-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:a37594ad6356e50073fe4f60aa4187b97d15329f2138124d252a5a19c8553ea4"}, - {file = "frozenlist-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:25b358aaa7dba5891b05968dd539f5856d69f522b6de0bf34e61f133e077c1a4"}, - {file = "frozenlist-1.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af2a51c8a381d76eabb76f228f565ed4c3701441ecec101dd18be70ebd483cfd"}, - {file = "frozenlist-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:82d22f6e6f2916e837c91c860140ef9947e31194c82aaeda843d6551cec92f19"}, - {file = "frozenlist-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cfe6fef507f8bac40f009c85c7eddfed88c1c0d38c75e72fe10476cef94e10f"}, - {file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f602e380a5132880fa245c92030abb0fc6ff34e0c5500600366cedc6adb06a"}, - {file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ad065b2ebd09f32511ff2be35c5dfafee6192978b5a1e9d279a5c6e121e3b03"}, - {file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bc93f5f62df3bdc1f677066327fc81f92b83644852a31c6aa9b32c2dde86ea7d"}, - {file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:89fdfc84c6bf0bff2ff3170bb34ecba8a6911b260d318d377171429c4be18c73"}, - {file = "frozenlist-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:47b2848e464883d0bbdcd9493c67443e5e695a84694efff0476f9059b4cb6257"}, - {file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f52d0732e56906f8ddea4bd856192984650282424049c956857fed43697ea43"}, - {file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:16ef7dd5b7d17495404a2e7a49bac1bc13d6d20c16d11f4133c757dd94c4144c"}, - {file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1cf63243bc5f5c19762943b0aa9e0d3fb3723d0c514d820a18a9b9a5ef864315"}, - {file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:54a1e09ab7a69f843cd28fefd2bcaf23edb9e3a8d7680032c8968b8ac934587d"}, - {file = "frozenlist-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:954b154a4533ef28bd3e83ffdf4eadf39deeda9e38fb8feaf066d6069885e034"}, - {file = "frozenlist-1.2.0-cp38-cp38-win32.whl", hash = "sha256:cb3957c39668d10e2b486acc85f94153520a23263b6401e8f59422ef65b9520d"}, - {file = "frozenlist-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0a7c7cce70e41bc13d7d50f0e5dd175f14a4f1837a8549b0936ed0cbe6170bf9"}, - {file = "frozenlist-1.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4c457220468d734e3077580a3642b7f682f5fd9507f17ddf1029452450912cdc"}, - {file = "frozenlist-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e74f8b4d8677ebb4015ac01fcaf05f34e8a1f22775db1f304f497f2f88fdc697"}, - {file = "frozenlist-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fbd4844ff111449f3bbe20ba24fbb906b5b1c2384d0f3287c9f7da2354ce6d23"}, - {file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0081a623c886197ff8de9e635528fd7e6a387dccef432149e25c13946cb0cd0"}, - {file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b6e21e5770df2dea06cb7b6323fbc008b13c4a4e3b52cb54685276479ee7676"}, - {file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:406aeb340613b4b559db78d86864485f68919b7141dec82aba24d1477fd2976f"}, - {file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:878ebe074839d649a1cdb03a61077d05760624f36d196884a5cafb12290e187b"}, - {file = "frozenlist-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1fef737fd1388f9b93bba8808c5f63058113c10f4e3c0763ced68431773f72f9"}, - {file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a495c3d513573b0b3f935bfa887a85d9ae09f0627cf47cad17d0cc9b9ba5c38"}, - {file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e7d0dd3e727c70c2680f5f09a0775525229809f1a35d8552b92ff10b2b14f2c2"}, - {file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:66a518731a21a55b7d3e087b430f1956a36793acc15912e2878431c7aec54210"}, - {file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:94728f97ddf603d23c8c3dd5cae2644fa12d33116e69f49b1644a71bb77b89ae"}, - {file = "frozenlist-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c1e8e9033d34c2c9e186e58279879d78c94dd365068a3607af33f2bc99357a53"}, - {file = "frozenlist-1.2.0-cp39-cp39-win32.whl", hash = "sha256:83334e84a290a158c0c4cc4d22e8c7cfe0bba5b76d37f1c2509dabd22acafe15"}, - {file = "frozenlist-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:735f386ec522e384f511614c01d2ef9cf799f051353876b4c6fb93ef67a6d1ee"}, - {file = "frozenlist-1.2.0.tar.gz", hash = "sha256:68201be60ac56aff972dc18085800b6ee07973c49103a8aba669dee3d71079de"}, + {file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2257aaba9660f78c7b1d8fea963b68f3feffb1a9d5d05a18401ca9eb3e8d0a3"}, + {file = "frozenlist-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a44ebbf601d7bac77976d429e9bdb5a4614f9f4027777f9e54fd765196e9d3b"}, + {file = "frozenlist-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:45334234ec30fc4ea677f43171b18a27505bfb2dba9aca4398a62692c0ea8868"}, + {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47be22dc27ed933d55ee55845d34a3e4e9f6fee93039e7f8ebadb0c2f60d403f"}, + {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03a7dd1bfce30216a3f51a84e6dd0e4a573d23ca50f0346634916ff105ba6e6b"}, + {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:691ddf6dc50480ce49f68441f1d16a4c3325887453837036e0fb94736eae1e58"}, + {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bde99812f237f79eaf3f04ebffd74f6718bbd216101b35ac7955c2d47c17da02"}, + {file = "frozenlist-1.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a202458d1298ced3768f5a7d44301e7c86defac162ace0ab7434c2e961166e8"}, + {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9e3e9e365991f8cc5f5edc1fd65b58b41d0514a6a7ad95ef5c7f34eb49b3d3e"}, + {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:04cb491c4b1c051734d41ea2552fde292f5f3a9c911363f74f39c23659c4af78"}, + {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:436496321dad302b8b27ca955364a439ed1f0999311c393dccb243e451ff66aa"}, + {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:754728d65f1acc61e0f4df784456106e35afb7bf39cfe37227ab00436fb38676"}, + {file = "frozenlist-1.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6eb275c6385dd72594758cbe96c07cdb9bd6becf84235f4a594bdf21e3596c9d"}, + {file = "frozenlist-1.3.0-cp310-cp310-win32.whl", hash = "sha256:e30b2f9683812eb30cf3f0a8e9f79f8d590a7999f731cf39f9105a7c4a39489d"}, + {file = "frozenlist-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f7353ba3367473d1d616ee727945f439e027f0bb16ac1a750219a8344d1d5d3c"}, + {file = "frozenlist-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88aafd445a233dbbf8a65a62bc3249a0acd0d81ab18f6feb461cc5a938610d24"}, + {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4406cfabef8f07b3b3af0f50f70938ec06d9f0fc26cbdeaab431cbc3ca3caeaa"}, + {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf829bd2e2956066dd4de43fd8ec881d87842a06708c035b37ef632930505a2"}, + {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:603b9091bd70fae7be28bdb8aa5c9990f4241aa33abb673390a7f7329296695f"}, + {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25af28b560e0c76fa41f550eacb389905633e7ac02d6eb3c09017fa1c8cdfde1"}, + {file = "frozenlist-1.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c7a8a9fc9383b52c410a2ec952521906d355d18fccc927fca52ab575ee8b93"}, + {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:65bc6e2fece04e2145ab6e3c47428d1bbc05aede61ae365b2c1bddd94906e478"}, + {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3f7c935c7b58b0d78c0beea0c7358e165f95f1fd8a7e98baa40d22a05b4a8141"}, + {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd89acd1b8bb4f31b47072615d72e7f53a948d302b7c1d1455e42622de180eae"}, + {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6983a31698490825171be44ffbafeaa930ddf590d3f051e397143a5045513b01"}, + {file = "frozenlist-1.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:adac9700675cf99e3615eb6a0eb5e9f5a4143c7d42c05cea2e7f71c27a3d0846"}, + {file = "frozenlist-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:0c36e78b9509e97042ef869c0e1e6ef6429e55817c12d78245eb915e1cca7468"}, + {file = "frozenlist-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:57f4d3f03a18facacb2a6bcd21bccd011e3b75d463dc49f838fd699d074fabd1"}, + {file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8c905a5186d77111f02144fab5b849ab524f1e876a1e75205cd1386a9be4b00a"}, + {file = "frozenlist-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5009062d78a8c6890d50b4e53b0ddda31841b3935c1937e2ed8c1bda1c7fb9d"}, + {file = "frozenlist-1.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2fdc3cd845e5a1f71a0c3518528bfdbfe2efaf9886d6f49eacc5ee4fd9a10953"}, + {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e650bd09b5dda929523b9f8e7f99b24deac61240ecc1a32aeba487afcd970f"}, + {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40dff8962b8eba91fd3848d857203f0bd704b5f1fa2b3fc9af64901a190bba08"}, + {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:768efd082074bb203c934e83a61654ed4931ef02412c2fbdecea0cff7ecd0274"}, + {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:006d3595e7d4108a12025ddf415ae0f6c9e736e726a5db0183326fd191b14c5e"}, + {file = "frozenlist-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:871d42623ae15eb0b0e9df65baeee6976b2e161d0ba93155411d58ff27483ad8"}, + {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aff388be97ef2677ae185e72dc500d19ecaf31b698986800d3fc4f399a5e30a5"}, + {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9f892d6a94ec5c7b785e548e42722e6f3a52f5f32a8461e82ac3e67a3bd073f1"}, + {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e982878792c971cbd60ee510c4ee5bf089a8246226dea1f2138aa0bb67aff148"}, + {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c6c321dd013e8fc20735b92cb4892c115f5cdb82c817b1e5b07f6b95d952b2f0"}, + {file = "frozenlist-1.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:30530930410855c451bea83f7b272fb1c495ed9d5cc72895ac29e91279401db3"}, + {file = "frozenlist-1.3.0-cp38-cp38-win32.whl", hash = "sha256:40ec383bc194accba825fbb7d0ef3dda5736ceab2375462f1d8672d9f6b68d07"}, + {file = "frozenlist-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:f20baa05eaa2bcd5404c445ec51aed1c268d62600362dc6cfe04fae34a424bd9"}, + {file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0437fe763fb5d4adad1756050cbf855bbb2bf0d9385c7bb13d7a10b0dd550486"}, + {file = "frozenlist-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b684c68077b84522b5c7eafc1dc735bfa5b341fb011d5552ebe0968e22ed641c"}, + {file = "frozenlist-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93641a51f89473837333b2f8100f3f89795295b858cd4c7d4a1f18e299dc0a4f"}, + {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6d32ff213aef0fd0bcf803bffe15cfa2d4fde237d1d4838e62aec242a8362fa"}, + {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31977f84828b5bb856ca1eb07bf7e3a34f33a5cddce981d880240ba06639b94d"}, + {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c62964192a1c0c30b49f403495911298810bada64e4f03249ca35a33ca0417a"}, + {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4eda49bea3602812518765810af732229b4291d2695ed24a0a20e098c45a707b"}, + {file = "frozenlist-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acb267b09a509c1df5a4ca04140da96016f40d2ed183cdc356d237286c971b51"}, + {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e1e26ac0a253a2907d654a37e390904426d5ae5483150ce3adedb35c8c06614a"}, + {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f96293d6f982c58ebebb428c50163d010c2f05de0cde99fd681bfdc18d4b2dc2"}, + {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e84cb61b0ac40a0c3e0e8b79c575161c5300d1d89e13c0e02f76193982f066ed"}, + {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:ff9310f05b9d9c5c4dd472983dc956901ee6cb2c3ec1ab116ecdde25f3ce4951"}, + {file = "frozenlist-1.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d26b650b71fdc88065b7a21f8ace70175bcf3b5bdba5ea22df4bfd893e795a3b"}, + {file = "frozenlist-1.3.0-cp39-cp39-win32.whl", hash = "sha256:01a73627448b1f2145bddb6e6c2259988bb8aee0fb361776ff8604b99616cd08"}, + {file = "frozenlist-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:772965f773757a6026dea111a15e6e2678fbd6216180f82a48a40b27de1ee2ab"}, + {file = "frozenlist-1.3.0.tar.gz", hash = "sha256:ce6f2ba0edb7b0c1d8976565298ad2deba6f8064d2bebb6ffce2ca896eb35b0b"}, ] furo = [ - {file = "furo-2022.2.14.1-py3-none-any.whl", hash = "sha256:d7cb8126034637212332350ec8490cb95732d36506b024318a58cee2e7de0fda"}, - {file = "furo-2022.2.14.1.tar.gz", hash = "sha256:1af3a3053e594666e27eefd347b84beae5d74d6d20f6294cc47777d46f5761a7"}, + {file = "furo-2022.4.7-py3-none-any.whl", hash = "sha256:7f3e3d2fb977483590f8ecb2c2cd511bd82661b79c18efb24de9558bc9cdf2d7"}, + {file = "furo-2022.4.7.tar.gz", hash = "sha256:96204ab7cd047e4b6c523996e0279c4c629a8fc31f4f109b2efd470c17f49c80"}, ] identify = [ - {file = "identify-2.3.4-py2.py3-none-any.whl", hash = "sha256:4de55a93e0ba72bf917c840b3794eb1055a67272a1732351c557c88ec42011b1"}, - {file = "identify-2.3.4.tar.gz", hash = "sha256:595283a1c3a078ac5774ad4dc4d1bdd0c1602f60bcf11ae673b64cb2b1945762"}, + {file = "identify-2.4.12-py2.py3-none-any.whl", hash = "sha256:5f06b14366bd1facb88b00540a1de05b69b310cbc2654db3c7e07fa3a4339323"}, + {file = "identify-2.4.12.tar.gz", hash = "sha256:3f3244a559290e7d3deb9e9adc7b33594c1bc85a9dd82e0f1be519bf12a1ec17"}, ] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] imagesize = [ - {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, - {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, + {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, + {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, - {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, + {file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"}, + {file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"}, ] incremental = [ {file = "incremental-21.3.0-py2.py3-none-any.whl", hash = "sha256:92014aebc6a20b78a8084cdd5645eeaa7f74b8933f70fa3ada2cfbd1e3b54321"}, @@ -1766,105 +1740,76 @@ iniconfig = [ {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] ipython = [ - {file = "ipython-8.0.1-py3-none-any.whl", hash = "sha256:c503a0dd6ccac9c8c260b211f2dd4479c042b49636b097cc9a0d55fe62dff64c"}, - {file = "ipython-8.0.1.tar.gz", hash = "sha256:ab564d4521ea8ceaac26c3a2c6e5ddbca15c8848fd5a5cc325f960da88d42974"}, + {file = "ipython-8.2.0-py3-none-any.whl", hash = "sha256:1b672bfd7a48d87ab203d9af8727a3b0174a4566b4091e9447c22fb63ea32857"}, + {file = "ipython-8.2.0.tar.gz", hash = "sha256:70e5eb132cac594a34b5f799bd252589009905f05104728aea6a403ec2519dc1"}, ] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] jedi = [ - {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"}, - {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"}, + {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, + {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, ] jinja2 = [ - {file = "Jinja2-3.0.2-py3-none-any.whl", hash = "sha256:8569982d3f0889eed11dd620c706d39b60c36d6d25843961f33f77fb6bc6b20c"}, - {file = "Jinja2-3.0.2.tar.gz", hash = "sha256:827a0e32839ab1600d4eb1c4c33ec5a8edfbc5cb42dafa13b81f182f97784b45"}, + {file = "Jinja2-3.1.1-py3-none-any.whl", hash = "sha256:539835f51a74a69f41b848a9645dbdc35b4f20a3b601e2d9a7e22947b15ff119"}, + {file = "Jinja2-3.1.1.tar.gz", hash = "sha256:640bed4bb501cbd17194b3cace1dc2126f5b619cf068a726b98192a0fde74ae9"}, ] livereload = [ {file = "livereload-2.6.3.tar.gz", hash = "sha256:776f2f865e59fde56490a56bcc6773b6917366bce0c267c60ee8aaf1a0959869"}, ] magic-filter = [ - {file = "magic-filter-1.0.5.tar.gz", hash = "sha256:974cf2793bb02a770f202d3179abfb600d1917f4e0c2af1727ef0edbb90cd0c2"}, - {file = "magic_filter-1.0.5-py3-none-any.whl", hash = "sha256:fa0c5f94da30d6cae1f0cec34fa526056db9f2636c099527513d529cb0299787"}, + {file = "magic-filter-1.0.6.tar.gz", hash = "sha256:dd022b088df644b94fd087b4ef8bb3eabb7d96dfc93f59ae9a859ca26881ef61"}, + {file = "magic_filter-1.0.6-py3-none-any.whl", hash = "sha256:499a76a4c023fd6e90e49c4fca6edaf338725c3a923987a6dcdb52fdf4d93ed9"}, ] markdown = [ - {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, - {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, + {file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"}, + {file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"}, ] markdown-include = [ {file = "markdown-include-0.6.0.tar.gz", hash = "sha256:6f5d680e36f7780c7f0f61dca53ca581bd50d1b56137ddcd6353efafa0c3e4a2"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] matplotlib-inline = [ {file = "matplotlib-inline-0.1.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"}, @@ -1875,100 +1820,90 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] multidict = [ - {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3822c5894c72e3b35aae9909bef66ec83e44522faf767c0ad39e0e2de11d3b55"}, - {file = "multidict-5.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:28e6d883acd8674887d7edc896b91751dc2d8e87fbdca8359591a13872799e4e"}, - {file = "multidict-5.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b61f85101ef08cbbc37846ac0e43f027f7844f3fade9b7f6dd087178caedeee7"}, - {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9b668c065968c5979fe6b6fa6760bb6ab9aeb94b75b73c0a9c1acf6393ac3bf"}, - {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517d75522b7b18a3385726b54a081afd425d4f41144a5399e5abd97ccafdf36b"}, - {file = "multidict-5.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1b4ac3ba7a97b35a5ccf34f41b5a8642a01d1e55454b699e5e8e7a99b5a3acf5"}, - {file = "multidict-5.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:df23c83398715b26ab09574217ca21e14694917a0c857e356fd39e1c64f8283f"}, - {file = "multidict-5.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e58a9b5cc96e014ddf93c2227cbdeca94b56a7eb77300205d6e4001805391747"}, - {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f76440e480c3b2ca7f843ff8a48dc82446b86ed4930552d736c0bac507498a52"}, - {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cfde464ca4af42a629648c0b0d79b8f295cf5b695412451716531d6916461628"}, - {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0fed465af2e0eb6357ba95795d003ac0bdb546305cc2366b1fc8f0ad67cc3fda"}, - {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:b70913cbf2e14275013be98a06ef4b412329fe7b4f83d64eb70dce8269ed1e1a"}, - {file = "multidict-5.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a5635bcf1b75f0f6ef3c8a1ad07b500104a971e38d3683167b9454cb6465ac86"}, - {file = "multidict-5.2.0-cp310-cp310-win32.whl", hash = "sha256:77f0fb7200cc7dedda7a60912f2059086e29ff67cefbc58d2506638c1a9132d7"}, - {file = "multidict-5.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:9416cf11bcd73c861267e88aea71e9fcc35302b3943e45e1dbb4317f91a4b34f"}, - {file = "multidict-5.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fd77c8f3cba815aa69cb97ee2b2ef385c7c12ada9c734b0f3b32e26bb88bbf1d"}, - {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ec9aea6223adf46999f22e2c0ab6cf33f5914be604a404f658386a8f1fba37"}, - {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5283c0a00f48e8cafcecadebfa0ed1dac8b39e295c7248c44c665c16dc1138b"}, - {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5f79c19c6420962eb17c7e48878a03053b7ccd7b69f389d5831c0a4a7f1ac0a1"}, - {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e4a67f1080123de76e4e97a18d10350df6a7182e243312426d508712e99988d4"}, - {file = "multidict-5.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:94b117e27efd8e08b4046c57461d5a114d26b40824995a2eb58372b94f9fca02"}, - {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2e77282fd1d677c313ffcaddfec236bf23f273c4fba7cdf198108f5940ae10f5"}, - {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:116347c63ba049c1ea56e157fa8aa6edaf5e92925c9b64f3da7769bdfa012858"}, - {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:dc3a866cf6c13d59a01878cd806f219340f3e82eed514485e094321f24900677"}, - {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ac42181292099d91217a82e3fa3ce0e0ddf3a74fd891b7c2b347a7f5aa0edded"}, - {file = "multidict-5.2.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:f0bb0973f42ffcb5e3537548e0767079420aefd94ba990b61cf7bb8d47f4916d"}, - {file = "multidict-5.2.0-cp36-cp36m-win32.whl", hash = "sha256:ea21d4d5104b4f840b91d9dc8cbc832aba9612121eaba503e54eaab1ad140eb9"}, - {file = "multidict-5.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:e6453f3cbeb78440747096f239d282cc57a2997a16b5197c9bc839099e1633d0"}, - {file = "multidict-5.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3def943bfd5f1c47d51fd324df1e806d8da1f8e105cc7f1c76a1daf0f7e17b0"}, - {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35591729668a303a02b06e8dba0eb8140c4a1bfd4c4b3209a436a02a5ac1de11"}, - {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8cacda0b679ebc25624d5de66c705bc53dcc7c6f02a7fb0f3ca5e227d80422"}, - {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:baf1856fab8212bf35230c019cde7c641887e3fc08cadd39d32a421a30151ea3"}, - {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a43616aec0f0d53c411582c451f5d3e1123a68cc7b3475d6f7d97a626f8ff90d"}, - {file = "multidict-5.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:25cbd39a9029b409167aa0a20d8a17f502d43f2efebfe9e3ac019fe6796c59ac"}, - {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a2cbcfbea6dc776782a444db819c8b78afe4db597211298dd8b2222f73e9cd0"}, - {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d2d7d1fff8e09d99354c04c3fd5b560fb04639fd45926b34e27cfdec678a704"}, - {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a37e9a68349f6abe24130846e2f1d2e38f7ddab30b81b754e5a1fde32f782b23"}, - {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:637c1896497ff19e1ee27c1c2c2ddaa9f2d134bbb5e0c52254361ea20486418d"}, - {file = "multidict-5.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9815765f9dcda04921ba467957be543423e5ec6a1136135d84f2ae092c50d87b"}, - {file = "multidict-5.2.0-cp37-cp37m-win32.whl", hash = "sha256:8b911d74acdc1fe2941e59b4f1a278a330e9c34c6c8ca1ee21264c51ec9b67ef"}, - {file = "multidict-5.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:380b868f55f63d048a25931a1632818f90e4be71d2081c2338fcf656d299949a"}, - {file = "multidict-5.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e7d81ce5744757d2f05fc41896e3b2ae0458464b14b5a2c1e87a6a9d69aefaa8"}, - {file = "multidict-5.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d1d55cdf706ddc62822d394d1df53573d32a7a07d4f099470d3cb9323b721b6"}, - {file = "multidict-5.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4771d0d0ac9d9fe9e24e33bed482a13dfc1256d008d101485fe460359476065"}, - {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7d57ea65744d249427793c042094c4016789eb2562576fb831870f9c878d9e"}, - {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdd68778f96216596218b4e8882944d24a634d984ee1a5a049b300377878fa7c"}, - {file = "multidict-5.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecc99bce8ee42dcad15848c7885197d26841cb24fa2ee6e89d23b8993c871c64"}, - {file = "multidict-5.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:067150fad08e6f2dd91a650c7a49ba65085303fcc3decbd64a57dc13a2733031"}, - {file = "multidict-5.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:78c106b2b506b4d895ddc801ff509f941119394b89c9115580014127414e6c2d"}, - {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e6c4fa1ec16e01e292315ba76eb1d012c025b99d22896bd14a66628b245e3e01"}, - {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b227345e4186809d31f22087d0265655114af7cda442ecaf72246275865bebe4"}, - {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:06560fbdcf22c9387100979e65b26fba0816c162b888cb65b845d3def7a54c9b"}, - {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7878b61c867fb2df7a95e44b316f88d5a3742390c99dfba6c557a21b30180cac"}, - {file = "multidict-5.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:246145bff76cc4b19310f0ad28bd0769b940c2a49fc601b86bfd150cbd72bb22"}, - {file = "multidict-5.2.0-cp38-cp38-win32.whl", hash = "sha256:c30ac9f562106cd9e8071c23949a067b10211917fdcb75b4718cf5775356a940"}, - {file = "multidict-5.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:f19001e790013ed580abfde2a4465388950728861b52f0da73e8e8a9418533c0"}, - {file = "multidict-5.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c1ff762e2ee126e6f1258650ac641e2b8e1f3d927a925aafcfde943b77a36d24"}, - {file = "multidict-5.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bd6c9c50bf2ad3f0448edaa1a3b55b2e6866ef8feca5d8dbec10ec7c94371d21"}, - {file = "multidict-5.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc66d4016f6e50ed36fb39cd287a3878ffcebfa90008535c62e0e90a7ab713ae"}, - {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9acb76d5f3dd9421874923da2ed1e76041cb51b9337fd7f507edde1d86535d6"}, - {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dfc924a7e946dd3c6360e50e8f750d51e3ef5395c95dc054bc9eab0f70df4f9c"}, - {file = "multidict-5.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32fdba7333eb2351fee2596b756d730d62b5827d5e1ab2f84e6cbb287cc67fe0"}, - {file = "multidict-5.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b9aad49466b8d828b96b9e3630006234879c8d3e2b0a9d99219b3121bc5cdb17"}, - {file = "multidict-5.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:93de39267c4c676c9ebb2057e98a8138bade0d806aad4d864322eee0803140a0"}, - {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9bef5cff994ca3026fcc90680e326d1a19df9841c5e3d224076407cc21471a1"}, - {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5f841c4f14331fd1e36cbf3336ed7be2cb2a8f110ce40ea253e5573387db7621"}, - {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:38ba256ee9b310da6a1a0f013ef4e422fca30a685bcbec86a969bd520504e341"}, - {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:3bc3b1621b979621cee9f7b09f024ec76ec03cc365e638126a056317470bde1b"}, - {file = "multidict-5.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ee908c070020d682e9b42c8f621e8bb10c767d04416e2ebe44e37d0f44d9ad5"}, - {file = "multidict-5.2.0-cp39-cp39-win32.whl", hash = "sha256:1c7976cd1c157fa7ba5456ae5d31ccdf1479680dc9b8d8aa28afabc370df42b8"}, - {file = "multidict-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:c9631c642e08b9fff1c6255487e62971d8b8e821808ddd013d8ac058087591ac"}, - {file = "multidict-5.2.0.tar.gz", hash = "sha256:0dd1c93edb444b33ba2274b66f63def8a327d607c6c790772f448a53b6ea59ce"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, + {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, + {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, + {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, + {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, + {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, + {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, + {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, + {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, + {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, + {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, ] mypy = [ - {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"}, - {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"}, - {file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"}, - {file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"}, - {file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"}, - {file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"}, - {file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"}, - {file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"}, - {file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"}, - {file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"}, - {file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"}, - {file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"}, - {file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"}, - {file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"}, - {file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"}, - {file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"}, - {file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"}, - {file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"}, - {file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"}, - {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"}, + {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, + {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, + {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"}, + {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"}, + {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"}, + {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"}, + {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"}, + {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"}, + {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"}, + {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"}, + {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"}, + {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"}, + {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"}, + {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"}, + {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"}, + {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"}, + {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"}, + {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"}, + {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"}, + {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"}, + {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -1983,8 +1918,8 @@ packaging = [ {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] parso = [ - {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"}, - {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"}, + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, ] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, @@ -1999,20 +1934,20 @@ pickleshare = [ {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, ] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, + {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, + {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] pre-commit = [ - {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"}, - {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"}, + {file = "pre_commit-2.18.1-py2.py3-none-any.whl", hash = "sha256:02226e69564ebca1a070bd1f046af866aa1c318dbc430027c50ab832ed2b73f2"}, + {file = "pre_commit-2.18.1.tar.gz", hash = "sha256:5d445ee1fa8738d506881c5d84f83c62bb5be6b2838e32207433647e8e5ebe10"}, ] prompt-toolkit = [ - {file = "prompt_toolkit-3.0.22-py3-none-any.whl", hash = "sha256:48d85cdca8b6c4f16480c7ce03fd193666b62b0a21667ca56b4bb5ad679d1170"}, - {file = "prompt_toolkit-3.0.22.tar.gz", hash = "sha256:449f333dd120bd01f5d296a8ce1452114ba3a71fae7288d2f0ae2c918764fa72"}, + {file = "prompt_toolkit-3.0.29-py3-none-any.whl", hash = "sha256:62291dad495e665fca0bda814e342c69952086afb0f4094d0893d357e5c78752"}, + {file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"}, ] ptyprocess = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, @@ -2076,24 +2011,25 @@ pygments = [ {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, ] pymdown-extensions = [ - {file = "pymdown-extensions-9.2.tar.gz", hash = "sha256:ed8f69a18bc158f00cbf03abc536b88b6e541b7e699156501e767c48f81d8850"}, - {file = "pymdown_extensions-9.2-py3-none-any.whl", hash = "sha256:f2fa7d9317c672a419868c893c20a28fb7ed7fc60d4ec4774c35e01398ab330c"}, + {file = "pymdown-extensions-9.3.tar.gz", hash = "sha256:a80553b243d3ed2d6c27723bcd64ca9887e560e6f4808baa96f36e93061eaf90"}, + {file = "pymdown_extensions-9.3-py3-none-any.whl", hash = "sha256:b37461a181c1c8103cfe1660081726a0361a8294cbfda88e5b02cefe976f0546"}, ] pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, + {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, + {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, ] pytest = [ - {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, - {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, + {file = "pytest-7.1.1-py3-none-any.whl", hash = "sha256:92f723789a8fdd7180b6b06483874feca4c48a5c76968e03bb3e7f806a1869ea"}, + {file = "pytest-7.1.1.tar.gz", hash = "sha256:841132caef6b1ad17a9afde46dc4f6cfa59a05f9555aae5151f73bdf2820ca63"}, ] pytest-aiohttp = [ {file = "pytest-aiohttp-1.0.4.tar.gz", hash = "sha256:39ff3a0d15484c01d1436cbedad575c6eafbf0f57cdf76fb94994c97b5b8c5a4"}, {file = "pytest_aiohttp-1.0.4-py3-none-any.whl", hash = "sha256:1d2dc3a304c2be1fd496c0c2fb6b31ab60cd9fc33984f761f951f8ea1eb4ca95"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.18.1.tar.gz", hash = "sha256:c43fcdfea2335dd82ffe0f2774e40285ddfea78a8e81e56118d47b6a90fbb09e"}, - {file = "pytest_asyncio-0.18.1-py3-none-any.whl", hash = "sha256:c9ec48e8bbf5cc62755e18c4d8bc6907843ec9c5f4ac8f61464093baeba24a7e"}, + {file = "pytest-asyncio-0.18.3.tar.gz", hash = "sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91"}, + {file = "pytest_asyncio-0.18.3-1-py3-none-any.whl", hash = "sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213"}, + {file = "pytest_asyncio-0.18.3-py3-none-any.whl", hash = "sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84"}, ] pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, @@ -2108,8 +2044,8 @@ pytest-lazy-fixture = [ {file = "pytest_lazy_fixture-0.6.3-py3-none-any.whl", hash = "sha256:e0b379f38299ff27a653f03eaa69b08a6fd4484e46fd1c9907d984b9f9daeda6"}, ] pytest-metadata = [ - {file = "pytest-metadata-1.11.0.tar.gz", hash = "sha256:71b506d49d34e539cc3cfdb7ce2c5f072bea5c953320002c95968e0238f8ecf1"}, - {file = "pytest_metadata-1.11.0-py2.py3-none-any.whl", hash = "sha256:576055b8336dd4a9006dd2a47615f76f2f8c30ab12b1b1c039d99e834583523f"}, + {file = "pytest-metadata-2.0.0.tar.gz", hash = "sha256:08dcc2779f4393309dd6d341ea1ddc15265239b6c4d51671737e784406ec07dc"}, + {file = "pytest_metadata-2.0.0-py3-none-any.whl", hash = "sha256:e25f1a77ed02baf1d83911604247a70d60d7dcb970aa12be38e1ed58d4d38e65"}, ] pytest-mock = [ {file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"}, @@ -2124,8 +2060,8 @@ python-socks = [ {file = "python_socks-2.0.3-py3-none-any.whl", hash = "sha256:950723f27d2cf401e193a9e0a0d45baab848341298f5b397d27fda0c4635e9a9"}, ] pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, ] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, @@ -2162,29 +2098,33 @@ pyyaml = [ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] +redis = [ + {file = "redis-4.2.2-py3-none-any.whl", hash = "sha256:4e95f4ec5f49e636efcf20061a5a9110c20852f607cfca6865c07aaa8a739ee2"}, + {file = "redis-4.2.2.tar.gz", hash = "sha256:0107dc8e98a4f1d1d4aa00100e044287f77121a1e6d2085545c4b7fa94a7a27f"}, +] requests = [ - {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, - {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, ] sentry-sdk = [ - {file = "sentry-sdk-1.5.5.tar.gz", hash = "sha256:98fd155fa5d5fec1dbabed32a1a4ae2705f1edaa5dae4e7f7b62a384ba30e759"}, - {file = "sentry_sdk-1.5.5-py2.py3-none-any.whl", hash = "sha256:3817274fba2498c8ebf6b896ee98ac916c5598706340573268c07bf2bb30d831"}, + {file = "sentry-sdk-1.5.8.tar.gz", hash = "sha256:38fd16a92b5ef94203db3ece10e03bdaa291481dd7e00e77a148aa0302267d47"}, + {file = "sentry_sdk-1.5.8-py2.py3-none-any.whl", hash = "sha256:32af1a57954576709242beb8c373b3dbde346ac6bd616921def29d68846fb8c3"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] snowballstemmer = [ - {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, - {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] soupsieve = [ - {file = "soupsieve-2.3-py3-none-any.whl", hash = "sha256:617ffc4d0dfd39c66f4d1413a6e165663a34eca86be9b54f97b91756300ff6df"}, - {file = "soupsieve-2.3.tar.gz", hash = "sha256:e4860f889dfa88774c07da0b276b70c073b6470fa1a4a8350800bb7bce3dcc76"}, + {file = "soupsieve-2.3.2-py3-none-any.whl", hash = "sha256:a714129d3021ec17ce5be346b1007300558b378332c289a1a20e7d4de6ff18a5"}, + {file = "soupsieve-2.3.2.tar.gz", hash = "sha256:0bcc6d7432153063e3df09c3ac9442af3eba488715bfcad6a4c38ccb2a523124"}, ] sphinx = [ - {file = "Sphinx-4.2.0-py3-none-any.whl", hash = "sha256:98a535c62a4fcfcc362528592f69b26f7caec587d32cd55688db580be0287ae0"}, - {file = "Sphinx-4.2.0.tar.gz", hash = "sha256:94078db9184491e15bce0a56d9186e0aec95f16ac20b12d00e06d4e36f1058a6"}, + {file = "Sphinx-4.5.0-py3-none-any.whl", hash = "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226"}, + {file = "Sphinx-4.5.0.tar.gz", hash = "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6"}, ] sphinx-autobuild = [ {file = "sphinx-autobuild-2021.3.14.tar.gz", hash = "sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"}, @@ -2238,8 +2178,8 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ - {file = "tomli-1.2.2-py3-none-any.whl", hash = "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade"}, - {file = "tomli-1.2.2.tar.gz", hash = "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] tornado = [ {file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"}, @@ -2297,8 +2237,8 @@ typing-extensions = [ {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] urllib3 = [ - {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, - {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, + {file = "urllib3-1.26.9-py2.py3-none-any.whl", hash = "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14"}, + {file = "urllib3-1.26.9.tar.gz", hash = "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e"}, ] uvloop = [ {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, @@ -2319,13 +2259,79 @@ uvloop = [ {file = "uvloop-0.16.0.tar.gz", hash = "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"}, ] virtualenv = [ - {file = "virtualenv-20.10.0-py2.py3-none-any.whl", hash = "sha256:4b02e52a624336eece99c96e3ab7111f469c24ba226a53ec474e8e787b365814"}, - {file = "virtualenv-20.10.0.tar.gz", hash = "sha256:576d05b46eace16a9c348085f7d0dc8ef28713a2cabaa1cf0aea41e8f12c9218"}, + {file = "virtualenv-20.14.0-py2.py3-none-any.whl", hash = "sha256:1e8588f35e8b42c6ec6841a13c5e88239de1e6e4e4cedfd3916b306dc826ec66"}, + {file = "virtualenv-20.14.0.tar.gz", hash = "sha256:8e5b402037287126e81ccde9432b95a8be5b19d36584f64957060a3488c11ca8"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] +wrapt = [ + {file = "wrapt-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:5a9a1889cc01ed2ed5f34574c90745fab1dd06ec2eee663e8ebeefe363e8efd7"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:9a3ff5fb015f6feb78340143584d9f8a0b91b6293d6b5cf4295b3e95d179b88c"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4b847029e2d5e11fd536c9ac3136ddc3f54bc9488a75ef7d040a3900406a91eb"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9a5a544861b21e0e7575b6023adebe7a8c6321127bb1d238eb40d99803a0e8bd"}, + {file = "wrapt-1.14.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:88236b90dda77f0394f878324cfbae05ae6fde8a84d548cfe73a75278d760291"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f0408e2dbad9e82b4c960274214af533f856a199c9274bd4aff55d4634dedc33"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9d8c68c4145041b4eeae96239802cfdfd9ef927754a5be3f50505f09f309d8c6"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:22626dca56fd7f55a0733e604f1027277eb0f4f3d95ff28f15d27ac25a45f71b"}, + {file = "wrapt-1.14.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:65bf3eb34721bf18b5a021a1ad7aa05947a1767d1aa272b725728014475ea7d5"}, + {file = "wrapt-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09d16ae7a13cff43660155383a2372b4aa09109c7127aa3f24c3cf99b891c330"}, + {file = "wrapt-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:debaf04f813ada978d7d16c7dfa16f3c9c2ec9adf4656efdc4defdf841fc2f0c"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748df39ed634851350efa87690c2237a678ed794fe9ede3f0d79f071ee042561"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1807054aa7b61ad8d8103b3b30c9764de2e9d0c0978e9d3fc337e4e74bf25faa"}, + {file = "wrapt-1.14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763a73ab377390e2af26042f685a26787c402390f682443727b847e9496e4a2a"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8529b07b49b2d89d6917cfa157d3ea1dfb4d319d51e23030664a827fe5fd2131"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:68aeefac31c1f73949662ba8affaf9950b9938b712fb9d428fa2a07e40ee57f8"}, + {file = "wrapt-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59d7d92cee84a547d91267f0fea381c363121d70fe90b12cd88241bd9b0e1763"}, + {file = "wrapt-1.14.0-cp310-cp310-win32.whl", hash = "sha256:3a88254881e8a8c4784ecc9cb2249ff757fd94b911d5df9a5984961b96113fff"}, + {file = "wrapt-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a242871b3d8eecc56d350e5e03ea1854de47b17f040446da0e47dc3e0b9ad4d"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a65bffd24409454b889af33b6c49d0d9bcd1a219b972fba975ac935f17bdf627"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9d9fcd06c952efa4b6b95f3d788a819b7f33d11bea377be6b8980c95e7d10775"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:db6a0ddc1282ceb9032e41853e659c9b638789be38e5b8ad7498caac00231c23"}, + {file = "wrapt-1.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:14e7e2c5f5fca67e9a6d5f753d21f138398cad2b1159913ec9e9a67745f09ba3"}, + {file = "wrapt-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:6d9810d4f697d58fd66039ab959e6d37e63ab377008ef1d63904df25956c7db0"}, + {file = "wrapt-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:d808a5a5411982a09fef6b49aac62986274ab050e9d3e9817ad65b2791ed1425"}, + {file = "wrapt-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b77159d9862374da213f741af0c361720200ab7ad21b9f12556e0eb95912cd48"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36a76a7527df8583112b24adc01748cd51a2d14e905b337a6fefa8b96fc708fb"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0057b5435a65b933cbf5d859cd4956624df37b8bf0917c71756e4b3d9958b9e"}, + {file = "wrapt-1.14.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0a4ca02752ced5f37498827e49c414d694ad7cf451ee850e3ff160f2bee9d3"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8c6be72eac3c14baa473620e04f74186c5d8f45d80f8f2b4eda6e1d18af808e8"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:21b1106bff6ece8cb203ef45b4f5778d7226c941c83aaaa1e1f0f4f32cc148cd"}, + {file = "wrapt-1.14.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:493da1f8b1bb8a623c16552fb4a1e164c0200447eb83d3f68b44315ead3f9036"}, + {file = "wrapt-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:89ba3d548ee1e6291a20f3c7380c92f71e358ce8b9e48161401e087e0bc740f8"}, + {file = "wrapt-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:729d5e96566f44fccac6c4447ec2332636b4fe273f03da128fff8d5559782b06"}, + {file = "wrapt-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:891c353e95bb11abb548ca95c8b98050f3620a7378332eb90d6acdef35b401d4"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23f96134a3aa24cc50614920cc087e22f87439053d886e474638c68c8d15dc80"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6807bcee549a8cb2f38f73f469703a1d8d5d990815c3004f21ddb68a567385ce"}, + {file = "wrapt-1.14.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6915682f9a9bc4cf2908e83caf5895a685da1fbd20b6d485dafb8e218a338279"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f2f3bc7cd9c9fcd39143f11342eb5963317bd54ecc98e3650ca22704b69d9653"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3a71dbd792cc7a3d772ef8cd08d3048593f13d6f40a11f3427c000cf0a5b36a0"}, + {file = "wrapt-1.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5a0898a640559dec00f3614ffb11d97a2666ee9a2a6bad1259c9facd01a1d4d9"}, + {file = "wrapt-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:167e4793dc987f77fd476862d32fa404d42b71f6a85d3b38cbce711dba5e6b68"}, + {file = "wrapt-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d066ffc5ed0be00cd0352c95800a519cf9e4b5dd34a028d301bdc7177c72daf3"}, + {file = "wrapt-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9bdfa74d369256e4218000a629978590fd7cb6cf6893251dad13d051090436d"}, + {file = "wrapt-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2498762814dd7dd2a1d0248eda2afbc3dd9c11537bc8200a4b21789b6df6cd38"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f24ca7953f2643d59a9c87d6e272d8adddd4a53bb62b9208f36db408d7aafc7"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b835b86bd5a1bdbe257d610eecab07bf685b1af2a7563093e0e69180c1d4af1"}, + {file = "wrapt-1.14.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b21650fa6907e523869e0396c5bd591cc326e5c1dd594dcdccac089561cacfb8"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:354d9fc6b1e44750e2a67b4b108841f5f5ea08853453ecbf44c81fdc2e0d50bd"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1f83e9c21cd5275991076b2ba1cd35418af3504667affb4745b48937e214bafe"}, + {file = "wrapt-1.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61e1a064906ccba038aa3c4a5a82f6199749efbbb3cef0804ae5c37f550eded0"}, + {file = "wrapt-1.14.0-cp38-cp38-win32.whl", hash = "sha256:28c659878f684365d53cf59dc9a1929ea2eecd7ac65da762be8b1ba193f7e84f"}, + {file = "wrapt-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:b0ed6ad6c9640671689c2dbe6244680fe8b897c08fd1fab2228429b66c518e5e"}, + {file = "wrapt-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b3f7e671fb19734c872566e57ce7fc235fa953d7c181bb4ef138e17d607dc8a1"}, + {file = "wrapt-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87fa943e8bbe40c8c1ba4086971a6fefbf75e9991217c55ed1bcb2f1985bd3d4"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4775a574e9d84e0212f5b18886cace049a42e13e12009bb0491562a48bb2b758"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d57677238a0c5411c76097b8b93bdebb02eb845814c90f0b01727527a179e4d"}, + {file = "wrapt-1.14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00108411e0f34c52ce16f81f1d308a571df7784932cc7491d1e94be2ee93374b"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d332eecf307fca852d02b63f35a7872de32d5ba8b4ec32da82f45df986b39ff6"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:01f799def9b96a8ec1ef6b9c1bbaf2bbc859b87545efbecc4a78faea13d0e3a0"}, + {file = "wrapt-1.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47045ed35481e857918ae78b54891fac0c1d197f22c95778e66302668309336c"}, + {file = "wrapt-1.14.0-cp39-cp39-win32.whl", hash = "sha256:2eca15d6b947cfff51ed76b2d60fd172c6ecd418ddab1c5126032d27f74bc350"}, + {file = "wrapt-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb36fbb48b22985d13a6b496ea5fb9bb2a076fea943831643836c9f6febbcfdc"}, + {file = "wrapt-1.14.0.tar.gz", hash = "sha256:8323a43bd9c91f62bb7d4be74cc9ff10090e7ef820e27bfe8815c57e68261311"}, +] yarl = [ {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"}, {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b"}, @@ -2401,6 +2407,6 @@ yarl = [ {file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"}, ] zipp = [ - {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, - {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, + {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, + {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, ] diff --git a/pyproject.toml b/pyproject.toml index 160f5380..ba67b272 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.8" -magic-filter = "^1.0.5" +magic-filter = "^1.0.6" aiohttp = "^3.8.1" pydantic = "^1.9.0" aiofiles = "^0.8.0" @@ -46,30 +46,29 @@ uvloop = { version = "^0.16.0", markers = "sys_platform == 'darwin' or sys_platf # i18n Babel = { version = "^2.9.1", optional = true } # Proxy -aiohttp-socks = {version = "^0.7.1", optional = true} +aiohttp-socks = { version = "^0.7.1", optional = true } # Redis -aioredis = {version = "^2.0.1", optional = true} +redis = { version = "^4.2.2", optional = true } # Docs Sphinx = { version = "^4.2.0", optional = true } sphinx-intl = { version = "^2.0.1", optional = true } sphinx-autobuild = { version = "^2021.3.14", optional = true } -sphinx-copybutton = {version = "^0.5.0", optional = true} -furo = {version = "^2022.2.14", optional = true} +sphinx-copybutton = { version = "^0.5.0", optional = true } +furo = { version = "^2022.4.7", optional = true } sphinx-prompt = { version = "^1.5.0", optional = true } Sphinx-Substitution-Extensions = { version = "^2020.9.30", optional = true } -towncrier = {version = "^21.9.0", optional = true} +towncrier = { version = "^21.9.0", optional = true } pygments = { version = "^2.4", optional = true } -pymdown-extensions = {version = "^9.2", optional = true} +pymdown-extensions = { version = "^9.3", optional = true } markdown-include = { version = "^0.6", optional = true } -Pygments = {version = "^2.11.2", optional = true} +Pygments = { version = "^2.11.2", optional = true } [tool.poetry.dev-dependencies] -ipython = "^8.0.1" +ipython = "^8.1.1" black = "^22.1.0" isort = "^5.10.1" flake8 = "^4.0.1" -flake8-html = "^0.4.1" -mypy = "^0.931" +mypy = "^0.942" pytest = "^7.0.1" pytest-html = "^3.1.1" pytest-asyncio = "^0.18.1" @@ -90,7 +89,7 @@ sentry-sdk = "^1.5.5" [tool.poetry.extras] fast = ["uvloop"] -redis = ["aioredis"] +redis = ["redis"] proxy = ["aiohttp-socks"] i18n = ["Babel"] docs = [ @@ -110,7 +109,7 @@ docs = [ [tool.black] line-length = 99 -target-version = ['py37', 'py38'] +target-version = ['py38', 'py39', 'py310'] exclude = ''' ( \.eggs diff --git a/tests/conftest.py b/tests/conftest.py index 698ee5cf..e2afa7a9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,7 @@ from pathlib import Path import pytest from _pytest.config import UsageError -from aioredis.connection import parse_url as parse_redis_url +from redis.asyncio.connection import parse_url as parse_redis_url from aiogram import Bot, Dispatcher from aiogram.dispatcher.fsm.storage.memory import ( diff --git a/tests/test_api/test_client/test_session/test_base_session.py b/tests/test_api/test_client/test_session/test_base_session.py index a6c5f700..88a5e626 100644 --- a/tests/test_api/test_client/test_session/test_base_session.py +++ b/tests/test_api/test_client/test_session/test_base_session.py @@ -215,11 +215,11 @@ class TestBaseSession: return await make_request(bot, method) session = CustomSession() - assert not session.middlewares + assert not session.middleware._middlewares session.middleware(my_middleware) - assert my_middleware in session.middlewares - assert len(session.middlewares) == 1 + assert my_middleware in session.middleware + assert len(session.middleware) == 1 async def test_use_middleware(self, bot: MockedBot): flag_before = False diff --git a/tests/test_api/test_client/test_session/test_middlewares/test_manager.py b/tests/test_api/test_client/test_session/test_middlewares/test_manager.py new file mode 100644 index 00000000..1bc2a6a3 --- /dev/null +++ b/tests/test_api/test_client/test_session/test_middlewares/test_manager.py @@ -0,0 +1,45 @@ +from aiogram import Bot +from aiogram.client.session.middlewares.base import ( + BaseRequestMiddleware, + NextRequestMiddlewareType, +) +from aiogram.client.session.middlewares.manager import RequestMiddlewareManager +from aiogram.methods import Response, TelegramMethod +from aiogram.types import TelegramObject + + +class TestMiddlewareManager: + async def test_register(self): + manager = RequestMiddlewareManager() + + @manager + async def middleware(handler, event, data): + await handler(event, data) + + assert middleware in manager._middlewares + manager.unregister(middleware) + assert middleware not in manager._middlewares + + async def test_wrap_middlewares(self): + manager = RequestMiddlewareManager() + + class MyMiddleware(BaseRequestMiddleware): + async def __call__( + self, + make_request: NextRequestMiddlewareType, + bot: Bot, + method: TelegramMethod[TelegramObject], + ) -> Response[TelegramObject]: + return await make_request(bot, method) + + manager.register(MyMiddleware()) + + @manager() + @manager + async def middleware(make_request, bot, method): + return await make_request(bot, method) + + async def target_call(bot, method, timeout: int = None): + return timeout + + assert await manager.wrap_middlewares(target_call, timeout=42)(None, None) == 42 diff --git a/tests/test_api/test_types/test_message.py b/tests/test_api/test_types/test_message.py index 93341eb2..b2b66b77 100644 --- a/tests/test_api/test_types/test_message.py +++ b/tests/test_api/test_types/test_message.py @@ -641,13 +641,15 @@ class TestMessage: assert method.message_id == message.message_id @pytest.mark.parametrize( - "text,entities,correct", + "text,entities,mode,expected_value", [ - ["test", [MessageEntity(type="bold", offset=0, length=4)], True], - ["", [], False], + ["test", [MessageEntity(type="bold", offset=0, length=4)], "html", "test"], + ["test", [MessageEntity(type="bold", offset=0, length=4)], "md", "*test*"], + ["", [], "html", ""], + ["", [], "md", ""], ], ) - def test_html_text(self, text, entities, correct): + def test_html_text(self, text, entities, mode, expected_value): message = Message( message_id=42, chat=Chat(id=42, type="private"), @@ -655,11 +657,4 @@ class TestMessage: text=text, entities=entities, ) - if correct: - assert message.html_text - assert message.md_text - else: - with pytest.raises(TypeError): - assert message.html_text - with pytest.raises(TypeError): - assert message.md_text + assert getattr(message, f"{mode}_text") == expected_value diff --git a/tests/test_dispatcher/test_deprecated.py b/tests/test_dispatcher/test_deprecated.py index d2609079..853e5902 100644 --- a/tests/test_dispatcher/test_deprecated.py +++ b/tests/test_dispatcher/test_deprecated.py @@ -5,27 +5,38 @@ from aiogram.dispatcher.router import Router from tests.deprecated import check_deprecated OBSERVERS = { - "callback_query", - "channel_post", - "chosen_inline_result", - "edited_channel_post", - "edited_message", - "errors", - "inline_query", "message", + "edited_message", + "channel_post", + "edited_channel_post", + "inline_query", + "chosen_inline_result", + "callback_query", + "shipping_query", + "pre_checkout_query", "poll", "poll_answer", - "pre_checkout_query", - "shipping_query", + "my_chat_member", + "chat_member", + "chat_join_request", + "errors", } -DEPRECATED_OBSERVERS = {observer + "_handler" for observer in OBSERVERS} - -@pytest.mark.parametrize("observer_name", DEPRECATED_OBSERVERS) +@pytest.mark.parametrize("observer_name", OBSERVERS) def test_deprecated_handlers_name(observer_name: str): router = Router() with check_deprecated("3.2", exception=AttributeError): - observer = getattr(router, observer_name) + observer = getattr(router, f"{observer_name}_handler") assert isinstance(observer, TelegramEventObserver) + + +@pytest.mark.parametrize("observer_name", OBSERVERS) +def test_deprecated_register_handlers(observer_name: str): + router = Router() + + with check_deprecated("3.2", exception=AttributeError): + register = getattr(router, f"register_{observer_name}") + register(lambda event: True) + assert callable(register) diff --git a/tests/test_dispatcher/test_dispatcher.py b/tests/test_dispatcher/test_dispatcher.py index 1150f073..89d027b1 100644 --- a/tests/test_dispatcher/test_dispatcher.py +++ b/tests/test_dispatcher/test_dispatcher.py @@ -74,7 +74,22 @@ class TestDispatcher: assert dp.update.handlers assert dp.update.handlers[0].callback == dp._listen_update - assert dp.update.outer_middlewares + assert dp.update.outer_middleware + + def test_data_bind(self): + dp = Dispatcher() + assert dp.get("foo") is None + assert dp.get("foo", 42) == 42 + + dp["foo"] = 1 + assert dp._data["foo"] == 1 + assert dp["foo"] == 1 + + del dp["foo"] + assert "foo" not in dp._data + + def test_storage_property(self, dispatcher: Dispatcher): + assert dispatcher.storage is dispatcher.fsm.storage def test_parent_router(self, dispatcher: Dispatcher): with pytest.raises(RuntimeError): diff --git a/tests/test_dispatcher/test_event/test_middleware.py b/tests/test_dispatcher/test_event/test_middleware.py new file mode 100644 index 00000000..ffbe634d --- /dev/null +++ b/tests/test_dispatcher/test_event/test_middleware.py @@ -0,0 +1,42 @@ +from functools import partial + +from aiogram.dispatcher.middlewares.manager import MiddlewareManager + + +class TestMiddlewareManager: + async def test_register(self): + manager = MiddlewareManager() + + @manager + async def middleware(handler, event, data): + await handler(event, data) + + assert middleware in manager._middlewares + manager.unregister(middleware) + assert middleware not in manager._middlewares + + async def test_wrap_middlewares(self): + manager = MiddlewareManager() + + async def target(*args, **kwargs): + kwargs["target"] = True + kwargs["stack"].append(-1) + return kwargs + + async def middleware1(handler, event, data): + data["mw1"] = True + data["stack"].append(1) + return await handler(event, data) + + async def middleware2(handler, event, data): + data["mw2"] = True + data["stack"].append(2) + return await handler(event, data) + + wrapped = manager.wrap_middlewares([middleware1, middleware2], target) + + assert isinstance(wrapped, partial) + assert wrapped.func is middleware1 + + result = await wrapped(None, {"stack": []}) + assert result == {"mw1": True, "mw2": True, "target": True, "stack": [1, 2, -1]} diff --git a/tests/test_dispatcher/test_event/test_telegram.py b/tests/test_dispatcher/test_event/test_telegram.py index a30eb3a9..3a569010 100644 --- a/tests/test_dispatcher/test_event/test_telegram.py +++ b/tests/test_dispatcher/test_event/test_telegram.py @@ -297,10 +297,9 @@ class TestTelegramEventObserver: def test_register_middleware(self, middleware_type): event_observer = TelegramEventObserver(Router(), "test") - middlewares = getattr(event_observer, f"{middleware_type}s") - decorator = getattr(event_observer, middleware_type) + middlewares = getattr(event_observer, middleware_type) - @decorator + @middlewares async def my_middleware1(handler, event, data): pass @@ -308,7 +307,7 @@ class TestTelegramEventObserver: assert my_middleware1.__name__ == "my_middleware1" assert my_middleware1 in middlewares - @decorator() + @middlewares() async def my_middleware2(handler, event, data): pass @@ -319,13 +318,13 @@ class TestTelegramEventObserver: async def my_middleware3(handler, event, data): pass - decorator(my_middleware3) + middlewares(my_middleware3) assert my_middleware3 is not None assert my_middleware3.__name__ == "my_middleware3" assert my_middleware3 in middlewares - assert middlewares == [my_middleware1, my_middleware2, my_middleware3] + assert list(middlewares) == [my_middleware1, my_middleware2, my_middleware3] def test_register_global_filters(self): router = Router(use_builtin_filters=False) diff --git a/tests/test_dispatcher/test_filters/test_callback_data.py b/tests/test_dispatcher/test_filters/test_callback_data.py index cd7bc53e..9376cd33 100644 --- a/tests/test_dispatcher/test_filters/test_callback_data.py +++ b/tests/test_dispatcher/test_filters/test_callback_data.py @@ -30,7 +30,7 @@ class MyCallback(CallbackData, prefix="test"): class TestCallbackData: def test_init_subclass_prefix_required(self): - assert MyCallback.prefix == "test" + assert MyCallback.__prefix__ == "test" with pytest.raises(ValueError, match="prefix required.+"): @@ -38,12 +38,12 @@ class TestCallbackData: pass def test_init_subclass_sep_validation(self): - assert MyCallback.sep == ":" + assert MyCallback.__separator__ == ":" class MyCallback2(CallbackData, prefix="test2", sep="@"): pass - assert MyCallback2.sep == "@" + assert MyCallback2.__separator__ == "@" with pytest.raises(ValueError, match="Separator symbol '@' .+ 'sp@m'"): diff --git a/tests/test_dispatcher/test_filters/test_command.py b/tests/test_dispatcher/test_filters/test_command.py index d7a0ef55..38faaa7d 100644 --- a/tests/test_dispatcher/test_filters/test_command.py +++ b/tests/test_dispatcher/test_filters/test_command.py @@ -92,6 +92,18 @@ class TestCommandFilter: command = Command(commands=["test"]) assert bool(await command(message=message, bot=bot)) is result + async def test_command_magic_result(self, bot: MockedBot): + message = Message( + message_id=0, + text="/test 42", + chat=Chat(id=42, type="private"), + date=datetime.datetime.now(), + ) + command = Command(commands=["test"], command_magic=(F.args.as_("args"))) + result = await command(message=message, bot=bot) + assert "args" in result + assert result["args"] == "42" + class TestCommandObject: @pytest.mark.parametrize( diff --git a/tests/test_dispatcher/test_filters/test_exception.py b/tests/test_dispatcher/test_filters/test_exception.py index c1ffb6d8..1fcf7015 100644 --- a/tests/test_dispatcher/test_filters/test_exception.py +++ b/tests/test_dispatcher/test_filters/test_exception.py @@ -2,7 +2,7 @@ import re import pytest -from aiogram import Dispatcher, F +from aiogram import Dispatcher from aiogram.dispatcher.filters import ExceptionMessageFilter, ExceptionTypeFilter from aiogram.types import Update diff --git a/tests/test_dispatcher/test_filters/test_magic_data.py b/tests/test_dispatcher/test_filters/test_magic_data.py index 4a23f99a..5b74c182 100644 --- a/tests/test_dispatcher/test_filters/test_magic_data.py +++ b/tests/test_dispatcher/test_filters/test_magic_data.py @@ -22,9 +22,9 @@ class TestMagicDataFilter: assert value.spam is True return value - f = MagicData(magic_data=F.func(check)) + f = MagicData(magic_data=F.func(check).as_("test")) result = await f(Update(update_id=123), "foo", "bar", spam=True) assert called - assert isinstance(result, bool) - assert result + assert isinstance(result, dict) + assert result["test"] diff --git a/tests/test_utils/test_i18n.py b/tests/test_utils/test_i18n.py index 31843080..a4381c45 100644 --- a/tests/test_utils/test_i18n.py +++ b/tests/test_utils/test_i18n.py @@ -111,8 +111,8 @@ class TestSimpleI18nMiddleware: middleware = SimpleI18nMiddleware(i18n=i18n) middleware.setup(router=dp) - assert middleware not in dp.update.outer_middlewares - assert middleware in dp.message.outer_middlewares + assert middleware not in dp.update.outer_middleware + assert middleware in dp.message.outer_middleware async def test_get_unknown_locale(self, i18n: I18n): dp = Dispatcher() diff --git a/tests/test_utils/test_link.py b/tests/test_utils/test_link.py index 4dbfe8a2..8d74f0c6 100644 --- a/tests/test_utils/test_link.py +++ b/tests/test_utils/test_link.py @@ -2,7 +2,7 @@ from typing import Any, Dict import pytest -from aiogram.utils.link import create_telegram_link, create_tg_link +from aiogram.utils.link import BRANCH, create_telegram_link, create_tg_link, docs_url class TestLink: @@ -22,3 +22,12 @@ class TestLink: ) def test_create_telegram_link(self, base: str, params: Dict[str, Any], result: str): assert create_telegram_link(base, **params) == result + + def test_fragment(self): + assert ( + docs_url("test.html", fragment_="test") + == f"https://docs.aiogram.dev/en/{BRANCH}/test.html#test" + ) + + def test_docs(self): + assert docs_url("test.html") == f"https://docs.aiogram.dev/en/{BRANCH}/test.html" diff --git a/tests/test_utils/test_text_decorations.py b/tests/test_utils/test_text_decorations.py index da171575..f87bbfe0 100644 --- a/tests/test_utils/test_text_decorations.py +++ b/tests/test_utils/test_text_decorations.py @@ -47,6 +47,11 @@ class TestTextDecoration: 'test', ], [html_decoration, MessageEntity(type="url", offset=0, length=5), "test"], + [ + html_decoration, + MessageEntity(type="spoiler", offset=0, length=5), + 'test', + ], [ html_decoration, MessageEntity(type="text_link", offset=0, length=5, url="https://aiogram.dev"), @@ -76,6 +81,7 @@ class TestTextDecoration: [markdown_decoration, MessageEntity(type="bot_command", offset=0, length=5), "test"], [markdown_decoration, MessageEntity(type="email", offset=0, length=5), "test"], [markdown_decoration, MessageEntity(type="phone_number", offset=0, length=5), "test"], + [markdown_decoration, MessageEntity(type="spoiler", offset=0, length=5), "|test|"], [ markdown_decoration, MessageEntity(