From 8086a120c2b3b7eb4b9d03e52f745eebc0ce16e8 Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sat, 23 Jun 2018 17:39:24 +0300 Subject: [PATCH] Try to use contextvars (partial) --- aiogram/bot/bot.py | 14 ++++++++++++++ aiogram/dispatcher/__init__.py | 13 ++++++++++++- aiogram/types/base.py | 4 ++-- aiogram/types/message.py | 4 +++- aiogram/types/update.py | 14 ++++++++++++++ aiogram/utils/executor.py | 6 ++++++ setup.py | 6 +++--- 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index fefdef9f..f58e5842 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import typing +from contextvars import ContextVar from .base import BaseBot, api from .. import types @@ -30,6 +33,14 @@ class Bot(BaseBot): if hasattr(self, '_me'): delattr(self, '_me') + @classmethod + def current(cls) -> Bot: + """ + Return active bot instance from the current context or None + :return: Bot or None + """ + return bot.get() + async def download_file_by_id(self, file_id: base.String, destination=None, timeout: base.Integer = 30, chunk_size: base.Integer = 65536, seek: base.Boolean = True): @@ -1863,3 +1874,6 @@ class Bot(BaseBot): result = await self.request(api.Methods.GET_GAME_HIGH_SCORES, payload) return [types.GameHighScore(**gamehighscore) for gamehighscore in result] + + +bot: ContextVar[Bot] = ContextVar('bot_instance', default=None) diff --git a/aiogram/dispatcher/__init__.py b/aiogram/dispatcher/__init__.py index 3cea91d8..0ca75663 100644 --- a/aiogram/dispatcher/__init__.py +++ b/aiogram/dispatcher/__init__.py @@ -4,7 +4,9 @@ import itertools import logging import time import typing +from contextvars import ContextVar +from aiogram import types from .filters import CommandsFilter, ContentTypeFilter, ExceptionsFilter, RegexpFilter, \ USER_STATE, generate_default_filters from .handler import CancelHandler, Handler, SkipHandler @@ -15,7 +17,7 @@ from .webhook import BaseResponse from ..bot import Bot from ..types.message import ContentType from ..utils import context -from ..utils.exceptions import NetworkError, TelegramAPIError, Throttled +from ..utils.exceptions import TelegramAPIError, Throttled log = logging.getLogger(__name__) @@ -89,6 +91,10 @@ class Dispatcher: def get(self, key, default=None): return self.bot.data.get(key, default) + @classmethod + def current(cls): + return dispatcher.get() + async def skip_updates(self): """ You can skip old incoming updates from queue. @@ -127,6 +133,8 @@ class Dispatcher: """ self.last_update_id = update.update_id context.set_value(UPDATE_OBJECT, update) + + types.Update.set_current(update) try: if update.message: state = await self.storage.get_state(chat=update.message.chat.id, @@ -1054,3 +1062,6 @@ class Dispatcher: if run_task: return self.async_task(callback) return callback + + +dispatcher: ContextVar[Dispatcher] = ContextVar('dispatcher_instance', default=None) diff --git a/aiogram/types/base.py b/aiogram/types/base.py index 166a9848..4451fc36 100644 --- a/aiogram/types/base.py +++ b/aiogram/types/base.py @@ -137,8 +137,8 @@ class TelegramObject(metaclass=MetaTelegramObject): @property def bot(self): - from ..dispatcher import ctx - return ctx.get_bot() + from ..bot.bot import Bot + return Bot.current() def to_python(self) -> typing.Dict: """ diff --git a/aiogram/types/message.py b/aiogram/types/message.py index 61f6188f..6ed0a7f9 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import datetime import functools import typing @@ -38,7 +40,7 @@ class Message(base.TelegramObject): forward_from_message_id: base.Integer = fields.Field() forward_signature: base.String = fields.Field() forward_date: base.Integer = fields.Field() - reply_to_message: 'Message' = fields.Field(base='Message') + reply_to_message: Message = fields.Field(base='Message') edit_date: base.Integer = fields.Field() media_group_id: base.String = fields.Field() author_signature: base.String = fields.Field() diff --git a/aiogram/types/update.py b/aiogram/types/update.py index 7f9cf11a..879a0b89 100644 --- a/aiogram/types/update.py +++ b/aiogram/types/update.py @@ -1,3 +1,7 @@ +from __future__ import annotations + +from contextvars import ContextVar + from . import base from . import fields from .callback_query import CallbackQuery @@ -8,6 +12,8 @@ from .pre_checkout_query import PreCheckoutQuery from .shipping_query import ShippingQuery from ..utils import helper +current_update: ContextVar[Update] = ContextVar('current_update_object', default=None) + class Update(base.TelegramObject): """ @@ -27,6 +33,14 @@ class Update(base.TelegramObject): shipping_query: ShippingQuery = fields.Field(base=ShippingQuery) pre_checkout_query: PreCheckoutQuery = fields.Field(base=PreCheckoutQuery) + @classmethod + def current(cls): + return current_update.get() + + @classmethod + def set_current(cls, update: Update): + return current_update.set(update) + def __hash__(self): return self.update_id diff --git a/aiogram/utils/executor.py b/aiogram/utils/executor.py index e114e534..57cb9a65 100644 --- a/aiogram/utils/executor.py +++ b/aiogram/utils/executor.py @@ -102,6 +102,11 @@ class Executor: self._freeze = False + from aiogram.bot.bot import bot as ctx_bot + from aiogram.dispatcher import dispatcher as ctx_dp + ctx_bot.set(dispatcher.bot) + ctx_dp.set(dispatcher) + @property def frozen(self): return self._freeze @@ -198,6 +203,7 @@ class Executor: for callback in self._on_startup_webhook: app.on_startup.append(functools.partial(_wrap_callback, callback)) + # for callback in self._on_shutdown_webhook: # app.on_shutdown.append(functools.partial(_wrap_callback, callback)) diff --git a/setup.py b/setup.py index 9b583400..630325e0 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ except ImportError: # pip >= 10.0.0 WORK_DIR = pathlib.Path(__file__).parent # Check python version -MINIMAL_PY_VERSION = (3, 6) +MINIMAL_PY_VERSION = (3, 7) if sys.version_info < MINIMAL_PY_VERSION: raise RuntimeError('aiogram works only with Python {}+'.format('.'.join(map(str, MINIMAL_PY_VERSION)))) @@ -65,7 +65,7 @@ setup( url='https://github.com/aiogram/aiogram', license='MIT', author='Alex Root Junior', - requires_python='>=3.6', + requires_python='>=3.7', author_email='aiogram@illemius.xyz', description='Is a pretty simple and fully asynchronous library for Telegram Bot API', long_description=get_description(), @@ -76,7 +76,7 @@ setup( 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Libraries :: Application Frameworks', ], install_requires=get_requirements()