def __init__( self, token: str, base_url: str = None, base_file_url: str = None, request: 'Request' = None, private_key: bytes = None, private_key_password: bytes = None, defaults: 'Defaults' = None, arbitrary_callback_data: Union[bool, int] = False, ): super().__init__( token=token, base_url=base_url, base_file_url=base_file_url, request=request, private_key=private_key, private_key_password=private_key_password, defaults=defaults, ) # set up callback_data if not isinstance(arbitrary_callback_data, bool): maxsize = cast(int, arbitrary_callback_data) self.arbitrary_callback_data = True else: maxsize = 1024 self.arbitrary_callback_data = arbitrary_callback_data self.callback_data_cache: CallbackDataCache = CallbackDataCache( bot=self, maxsize=maxsize)
def test_init_and_access__persistent_data(self, bot): keyboard_data = _KeyboardData('123', 456, {'button': 678}) persistent_data = ([keyboard_data.to_tuple()], {'id': '123'}) cdc = CallbackDataCache(bot, persistent_data=persistent_data) assert cdc.maxsize == 1024 assert dict(cdc._callback_queries) == {'id': '123'} assert list(cdc._keyboard_data.keys()) == ['123'] assert cdc._keyboard_data['123'].keyboard_uuid == '123' assert cdc._keyboard_data['123'].access_time == 456 assert cdc._keyboard_data['123'].button_data == {'button': 678} assert cdc.persistence_data == persistent_data
def test_process_keyboard_full(self, bot): cdc = CallbackDataCache(bot, maxsize=1) changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') non_changing_button = InlineKeyboardButton('non-changing', url='https://ptb.org') reply_markup = InlineKeyboardMarkup.from_row( [non_changing_button, changing_button_1, changing_button_2]) out1 = cdc.process_keyboard(reply_markup) assert len(cdc.persistence_data[0]) == 1 out2 = cdc.process_keyboard(reply_markup) assert len(cdc.persistence_data[0]) == 1 keyboard_1, button_1 = cdc.extract_uuids( out1.inline_keyboard[0][1].callback_data) keyboard_2, button_2 = cdc.extract_uuids( out2.inline_keyboard[0][2].callback_data) assert cdc.persistence_data[0][0][0] != keyboard_1 assert cdc.persistence_data[0][0][0] == keyboard_2
def test_init_maxsize(self, maxsize, bot): assert CallbackDataCache(bot).maxsize == 1024 cdc = CallbackDataCache(bot, maxsize=maxsize) assert cdc.maxsize == maxsize assert cdc.bot is bot
def callback_data_cache(bot): return CallbackDataCache(bot)
def __init__( self, bot: 'Bot', update_queue: Queue, workers: int = 4, exception_event: Event = None, job_queue: 'JobQueue' = None, persistence: BasePersistence = None, use_context: bool = True, context_types: ContextTypes[CCT, UD, CD, BD] = None, ): self.bot = bot self.update_queue = update_queue self.job_queue = job_queue self.workers = workers self.use_context = use_context self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes()) if not use_context: warnings.warn( 'Old Handler API is deprecated - see https://git.io/fxJuV for details', TelegramDeprecationWarning, stacklevel=3, ) if self.workers < 1: warnings.warn( 'Asynchronous callbacks can not be processed without at least one worker thread.' ) self.user_data: DefaultDict[int, UD] = defaultdict( self.context_types.user_data) self.chat_data: DefaultDict[int, CD] = defaultdict( self.context_types.chat_data) self.bot_data = self.context_types.bot_data() self.persistence: Optional[BasePersistence] = None self._update_persistence_lock = Lock() if persistence: if not isinstance(persistence, BasePersistence): raise TypeError( "persistence must be based on telegram.ext.BasePersistence" ) self.persistence = persistence self.persistence.set_bot(self.bot) if self.persistence.store_user_data: self.user_data = self.persistence.get_user_data() if not isinstance(self.user_data, defaultdict): raise ValueError("user_data must be of type defaultdict") if self.persistence.store_chat_data: self.chat_data = self.persistence.get_chat_data() if not isinstance(self.chat_data, defaultdict): raise ValueError("chat_data must be of type defaultdict") if self.persistence.store_bot_data: self.bot_data = self.persistence.get_bot_data() if not isinstance(self.bot_data, self.context_types.bot_data): raise ValueError( f"bot_data must be of type {self.context_types.bot_data.__name__}" ) if self.persistence.store_callback_data: self.bot = cast(telegram.ext.extbot.ExtBot, self.bot) persistent_data = self.persistence.get_callback_data() if persistent_data is not None: if not isinstance(persistent_data, tuple) and len(persistent_data) != 2: raise ValueError('callback_data must be a 2-tuple') self.bot.callback_data_cache = CallbackDataCache( self.bot, self.bot.callback_data_cache.maxsize, persistent_data=persistent_data, ) else: self.persistence = None self.handlers: Dict[int, List[Handler]] = {} """Dict[:obj:`int`, List[:class:`telegram.ext.Handler`]]: Holds the handlers per group.""" self.groups: List[int] = [] """List[:obj:`int`]: A list with all groups.""" self.error_handlers: Dict[Callable, Union[bool, DefaultValue]] = {} """Dict[:obj:`callable`, :obj:`bool`]: A dict, where the keys are error handlers and the values indicate whether they are to be run asynchronously.""" self.running = False """:obj:`bool`: Indicates if this dispatcher is running.""" self.__stop_event = Event() self.__exception_event = exception_event or Event() self.__async_queue: Queue = Queue() self.__async_threads: Set[Thread] = set() # For backward compatibility, we allow a "singleton" mode for the dispatcher. When there's # only one instance of Dispatcher, it will be possible to use the `run_async` decorator. with self.__singleton_lock: if self.__singleton_semaphore.acquire(blocking=False): # pylint: disable=R1732 self._set_singleton(self) else: self._set_singleton(None)