Add __slots__ (#2345)

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
Co-authored-by: Hinrich Mahler <hinrich.mahler@freenet.de>
This commit is contained in:
Harshil 2021-05-29 19:48:16 +05:30 committed by GitHub
parent cc43aef64b
commit 92ff6a8e2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
251 changed files with 2908 additions and 99 deletions

View file

@ -26,6 +26,7 @@ import warnings
from typing import TYPE_CHECKING, List, Optional, Tuple, Type, TypeVar
from telegram.utils.types import JSONDict
from telegram.utils.deprecate import set_new_attribute_deprecated
if TYPE_CHECKING:
from telegram import Bot
@ -38,11 +39,19 @@ class TelegramObject:
_id_attrs: Tuple[object, ...] = ()
# Adding slots reduces memory usage & allows for faster attribute access.
# Only instance variables should be added to __slots__.
# We add __dict__ here for backward compatibility & also to avoid repetition for subclasses.
__slots__ = ('__dict__',)
def __str__(self) -> str:
return str(self.to_dict())
def __getitem__(self, item: str) -> object:
return self.__dict__[item]
return getattr(self, item, None)
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
@staticmethod
def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
@ -102,11 +111,16 @@ class TelegramObject:
"""
data = {}
for key in iter(self.__dict__):
# We want to get all attributes for the class, using self.__slots__ only includes the
# attributes used by that class itself, and not its superclass(es). Hence we get its MRO
# and then get their attributes. The `[:-2]` slice excludes the `object` class & the
# TelegramObject class itself.
attrs = {attr for cls in self.__class__.__mro__[:-2] for attr in cls.__slots__}
for key in attrs:
if key == 'bot' or key.startswith('_'):
continue
value = self.__dict__[key]
value = getattr(self, key, None)
if value is not None:
if hasattr(value, 'to_dict'):
data[key] = value.to_dict()

View file

@ -158,6 +158,18 @@ class Bot(TelegramObject):
"""
__slots__ = (
'token',
'base_url',
'base_file_url',
'private_key',
'defaults',
'_bot',
'_commands',
'_request',
'logger',
)
def __init__(
self,
token: str,
@ -184,6 +196,7 @@ class Bot(TelegramObject):
self._bot: Optional[User] = None
self._commands: Optional[List[BotCommand]] = None
self._request = request or Request()
self.private_key = None
self.logger = logging.getLogger(__name__)
if private_key:
@ -196,6 +209,12 @@ class Bot(TelegramObject):
private_key, password=private_key_password, backend=default_backend()
)
def __setattr__(self, key: str, value: object) -> None:
if issubclass(self.__class__, Bot) and self.__class__ is not Bot:
object.__setattr__(self, key, value)
return
super().__setattr__(key, value)
def _insert_defaults(
self, data: Dict[str, object], timeout: ODVInput[float]
) -> Optional[float]:

View file

@ -41,6 +41,8 @@ class BotCommand(TelegramObject):
"""
__slots__ = ('description', '_id_attrs', 'command')
def __init__(self, command: str, description: str, **_kwargs: Any):
self.command = command
self.description = description

View file

@ -85,6 +85,18 @@ class CallbackQuery(TelegramObject):
"""
__slots__ = (
'bot',
'game_short_name',
'message',
'chat_instance',
'id',
'from_user',
'inline_message_id',
'data',
'_id_attrs',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -143,6 +143,30 @@ class Chat(TelegramObject):
"""
__slots__ = (
'bio',
'id',
'type',
'last_name',
'bot',
'sticker_set_name',
'slow_mode_delay',
'location',
'first_name',
'permissions',
'invite_link',
'pinned_message',
'description',
'can_set_sticker_set',
'username',
'title',
'photo',
'linked_chat_id',
'all_members_are_administrators',
'message_auto_delete_time',
'_id_attrs',
)
SENDER: ClassVar[str] = constants.CHAT_SENDER
""":const:`telegram.constants.CHAT_SENDER`

View file

@ -20,11 +20,13 @@
"""This module contains an object that represents a Telegram ChatAction."""
from typing import ClassVar
from telegram import constants
from telegram.utils.deprecate import set_new_attribute_deprecated
class ChatAction:
"""Helper class to provide constants for different chat actions."""
__slots__ = ('__dict__',) # Adding __dict__ here since it doesn't subclass TGObject
FIND_LOCATION: ClassVar[str] = constants.CHATACTION_FIND_LOCATION
""":const:`telegram.constants.CHATACTION_FIND_LOCATION`"""
RECORD_AUDIO: ClassVar[str] = constants.CHATACTION_RECORD_AUDIO
@ -65,3 +67,6 @@ class ChatAction:
""":const:`telegram.constants.CHATACTION_UPLOAD_VIDEO`"""
UPLOAD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO_NOTE
""":const:`telegram.constants.CHATACTION_UPLOAD_VIDEO_NOTE`"""
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)

View file

@ -60,6 +60,16 @@ class ChatInviteLink(TelegramObject):
"""
__slots__ = (
'invite_link',
'creator',
'is_primary',
'is_revoked',
'expire_date',
'member_limit',
'_id_attrs',
)
def __init__(
self,
invite_link: str,

View file

@ -47,6 +47,8 @@ class ChatLocation(TelegramObject):
"""
__slots__ = ('location', '_id_attrs', 'address')
def __init__(
self,
location: Location,

View file

@ -138,6 +138,32 @@ class ChatMember(TelegramObject):
"""
__slots__ = (
'is_member',
'can_restrict_members',
'can_delete_messages',
'custom_title',
'can_be_edited',
'can_post_messages',
'can_send_messages',
'can_edit_messages',
'can_send_media_messages',
'is_anonymous',
'can_add_web_page_previews',
'can_send_other_messages',
'can_invite_users',
'can_send_polls',
'user',
'can_promote_members',
'status',
'can_change_info',
'can_pin_messages',
'can_manage_chat',
'can_manage_voice_chats',
'until_date',
'_id_attrs',
)
ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR
""":const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`"""
CREATOR: ClassVar[str] = constants.CHATMEMBER_CREATOR

View file

@ -62,6 +62,16 @@ class ChatMemberUpdated(TelegramObject):
"""
__slots__ = (
'chat',
'from_user',
'date',
'old_chat_member',
'new_chat_member',
'invite_link',
'_id_attrs',
)
def __init__(
self,
chat: Chat,

View file

@ -78,6 +78,18 @@ class ChatPermissions(TelegramObject):
"""
__slots__ = (
'can_send_other_messages',
'can_invite_users',
'can_send_polls',
'_id_attrs',
'can_send_messages',
'can_send_media_messages',
'can_change_info',
'can_pin_messages',
'can_add_web_page_previews',
)
def __init__(
self,
can_send_messages: bool = None,

View file

@ -61,6 +61,8 @@ class ChosenInlineResult(TelegramObject):
"""
__slots__ = ('location', 'result_id', 'from_user', 'inline_message_id', '_id_attrs', 'query')
def __init__(
self,
result_id: str,

View file

@ -64,6 +64,8 @@ class Dice(TelegramObject):
"""
__slots__ = ('emoji', 'value', '_id_attrs')
def __init__(self, value: int, emoji: str, **_kwargs: Any):
self.value = value
self.emoji = emoji

View file

@ -41,6 +41,9 @@ def _lstrip_str(in_s: str, lstr: str) -> str:
class TelegramError(Exception):
"""Base class for Telegram errors."""
# Apparently the base class Exception already has __dict__ in it, so its not included here
__slots__ = ('message',)
def __init__(self, message: str):
super().__init__()
@ -62,10 +65,14 @@ class TelegramError(Exception):
class Unauthorized(TelegramError):
"""Raised when the bot has not enough rights to perform the requested action."""
__slots__ = ()
class InvalidToken(TelegramError):
"""Raised when the token is invalid."""
__slots__ = ()
def __init__(self) -> None:
super().__init__('Invalid token')
@ -76,14 +83,20 @@ class InvalidToken(TelegramError):
class NetworkError(TelegramError):
"""Base class for exceptions due to networking errors."""
__slots__ = ()
class BadRequest(NetworkError):
"""Raised when Telegram could not process the request correctly."""
__slots__ = ()
class TimedOut(NetworkError):
"""Raised when a request took too long to finish."""
__slots__ = ()
def __init__(self) -> None:
super().__init__('Timed out')
@ -100,6 +113,8 @@ class ChatMigrated(TelegramError):
"""
__slots__ = ('new_chat_id',)
def __init__(self, new_chat_id: int):
super().__init__(f'Group migrated to supergroup. New chat id: {new_chat_id}')
self.new_chat_id = new_chat_id
@ -117,6 +132,8 @@ class RetryAfter(TelegramError):
"""
__slots__ = ('retry_after',)
def __init__(self, retry_after: int):
super().__init__(f'Flood control exceeded. Retry in {float(retry_after)} seconds')
self.retry_after = float(retry_after)
@ -128,5 +145,7 @@ class RetryAfter(TelegramError):
class Conflict(TelegramError):
"""Raised when a long poll or webhook conflicts with another one."""
__slots__ = ()
def __reduce__(self) -> Tuple[type, Tuple[str]]:
return self.__class__, (self.message,)

View file

@ -18,10 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the BasePersistence class."""
import warnings
from sys import version_info as py_ver
from abc import ABC, abstractmethod
from copy import copy
from typing import DefaultDict, Dict, Optional, Tuple, cast, ClassVar
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram import Bot
from telegram.utils.types import ConversationDict
@ -75,6 +78,18 @@ class BasePersistence(ABC):
persistence class.
"""
# Apparently Py 3.7 and below have '__dict__' in ABC
if py_ver < (3, 7):
__slots__ = ('store_user_data', 'store_chat_data', 'store_bot_data', 'bot')
else:
__slots__ = (
'store_user_data', # type: ignore[assignment]
'store_chat_data',
'store_bot_data',
'bot',
'__dict__',
)
def __new__(
cls, *args: object, **kwargs: object # pylint: disable=W0613
) -> 'BasePersistence':
@ -104,12 +119,13 @@ class BasePersistence(ABC):
def update_bot_data_replace_bot(data: Dict) -> None:
return update_bot_data(instance.replace_bot(data))
instance.get_user_data = get_user_data_insert_bot
instance.get_chat_data = get_chat_data_insert_bot
instance.get_bot_data = get_bot_data_insert_bot
instance.update_user_data = update_user_data_replace_bot
instance.update_chat_data = update_chat_data_replace_bot
instance.update_bot_data = update_bot_data_replace_bot
# We want to ignore TGDeprecation warnings so we use obj.__setattr__. Adds to __dict__
object.__setattr__(instance, 'get_user_data', get_user_data_insert_bot)
object.__setattr__(instance, 'get_chat_data', get_chat_data_insert_bot)
object.__setattr__(instance, 'get_bot_data', get_bot_data_insert_bot)
object.__setattr__(instance, 'update_user_data', update_user_data_replace_bot)
object.__setattr__(instance, 'update_chat_data', update_chat_data_replace_bot)
object.__setattr__(instance, 'update_bot_data', update_bot_data_replace_bot)
return instance
def __init__(
@ -123,6 +139,16 @@ class BasePersistence(ABC):
self.store_bot_data = store_bot_data
self.bot: Bot = None # type: ignore[assignment]
def __setattr__(self, key: str, value: object) -> None:
# Allow user defined subclasses to have custom attributes.
if issubclass(self.__class__, BasePersistence) and self.__class__.__name__ not in {
'DictPersistence',
'PicklePersistence',
}:
object.__setattr__(self, key, value)
return
set_new_attribute_deprecated(self, key, value)
def set_bot(self, bot: Bot) -> None:
"""Set the Bot to be used by this persistence instance.

View file

@ -73,6 +73,20 @@ class CallbackContext:
"""
__slots__ = (
'_dispatcher',
'_bot_data',
'_chat_data',
'_user_data',
'args',
'matches',
'error',
'job',
'async_args',
'async_kwargs',
'__dict__',
)
def __init__(self, dispatcher: 'Dispatcher'):
"""
Args:
@ -229,12 +243,13 @@ class CallbackContext:
return self
def update(self, data: Dict[str, object]) -> None:
"""Updates ``self.__dict__`` with the passed data.
"""Updates ``self.__slots__`` with the passed data.
Args:
data (Dict[:obj:`str`, :obj:`object`]): The data.
"""
self.__dict__.update(data)
for key, value in data.items():
setattr(self, key, value)
@property
def bot(self) -> 'Bot':

View file

@ -120,6 +120,8 @@ class CallbackQueryHandler(Handler[Update]):
"""
__slots__ = ('pattern', 'pass_groups', 'pass_groupdict')
def __init__(
self,
callback: Callable[[Update, 'CallbackContext'], RT],

View file

@ -96,6 +96,7 @@ class ChatMemberHandler(Handler[Update]):
"""
__slots__ = ('chat_member_types',)
MY_CHAT_MEMBER: ClassVar[int] = -1
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
CHAT_MEMBER: ClassVar[int] = 0

View file

@ -99,6 +99,8 @@ class ChosenInlineResultHandler(Handler[Update]):
"""
__slots__ = ('pattern',)
def __init__(
self,
callback: Callable[[Update, 'CallbackContext'], RT],

View file

@ -129,6 +129,8 @@ class CommandHandler(Handler[Update]):
run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
"""
__slots__ = ('command', 'filters', 'pass_args')
def __init__(
self,
command: SLT[str],
@ -350,6 +352,9 @@ class PrefixHandler(CommandHandler):
"""
# 'prefix' is a class property, & 'command' is included in the superclass, so they're left out.
__slots__ = ('_prefix', '_command', '_commands')
def __init__(
self,
prefix: SLT[str],

View file

@ -45,6 +45,9 @@ CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
class _ConversationTimeoutContext:
# '__dict__' is not included since this a private class
__slots__ = ('conversation_key', 'update', 'dispatcher', 'callback_context')
def __init__(
self,
conversation_key: Tuple[int, ...],
@ -182,6 +185,26 @@ class ConversationHandler(Handler[Update]):
"""
__slots__ = (
'_entry_points',
'_states',
'_fallbacks',
'_allow_reentry',
'_per_user',
'_per_chat',
'_per_message',
'_conversation_timeout',
'_name',
'persistent',
'_persistence',
'_map_to_parent',
'timeout_jobs',
'_timeout_jobs_lock',
'_conversations',
'_conversations_lock',
'logger',
)
END: ClassVar[int] = -1
""":obj:`int`: Used as a constant to return when a conversation is ended."""
TIMEOUT: ClassVar[int] = -2

View file

@ -22,6 +22,7 @@ from typing import NoReturn, Optional, Dict, Any
import pytz
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram.utils.helpers import DEFAULT_NONE
from telegram.utils.types import ODVInput
@ -56,6 +57,19 @@ class Defaults:
:meth:`Dispatcher.add_error_handler`. Defaults to :obj:`False`.
"""
__slots__ = (
'_timeout',
'_tzinfo',
'_disable_web_page_preview',
'_run_async',
'_quote',
'_disable_notification',
'_allow_sending_without_reply',
'_parse_mode',
'_api_defaults',
'__dict__',
)
def __init__(
self,
parse_mode: str = None,
@ -91,8 +105,11 @@ class Defaults:
if value not in [None, DEFAULT_NONE]:
self._api_defaults[kwarg] = value
# Special casing, as None is a valid default value
if self.timeout != DEFAULT_NONE:
self._api_defaults['timeout'] = self.timeout
if self._timeout != DEFAULT_NONE:
self._api_defaults['timeout'] = self._timeout
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
@property
def api_defaults(self) -> Dict[str, Any]: # skip-cq: PY-D0003
@ -243,7 +260,7 @@ class Defaults:
def __eq__(self, other: object) -> bool:
if isinstance(other, Defaults):
return self.__dict__ == other.__dict__
return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__)
return False
def __ne__(self, other: object) -> bool:

View file

@ -79,6 +79,17 @@ class DictPersistence(BasePersistence):
persistence class.
"""
__slots__ = (
'_user_data',
'_chat_data',
'_bot_data',
'_conversations',
'_user_data_json',
'_chat_data_json',
'_bot_data_json',
'_conversations_json',
)
def __init__(
self,
store_user_data: bool = True,

View file

@ -26,14 +26,14 @@ from functools import wraps
from queue import Empty, Queue
from threading import BoundedSemaphore, Event, Lock, Thread, current_thread
from time import sleep
from typing import TYPE_CHECKING, Callable, DefaultDict, Dict, List, Optional, Set, Union
from typing import TYPE_CHECKING, Callable, DefaultDict, Dict, List, Optional, Union, Set
from uuid import uuid4
from telegram import TelegramError, Update
from telegram.ext import BasePersistence
from telegram.ext.callbackcontext import CallbackContext
from telegram.ext.handler import Handler
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated
from telegram.ext.utils.promise import Promise
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
@ -98,6 +98,8 @@ class DispatcherHandlerStop(Exception):
state (:obj:`object`, optional): The next state of the conversation.
"""
__slots__ = ('state',)
def __init__(self, state: object = None) -> None:
super().__init__()
self.state = state
@ -134,6 +136,30 @@ class Dispatcher:
"""
# Allowing '__weakref__' creation here since we need it for the singleton
__slots__ = (
'workers',
'persistence',
'use_context',
'update_queue',
'job_queue',
'user_data',
'chat_data',
'bot_data',
'_update_persistence_lock',
'handlers',
'groups',
'error_handlers',
'running',
'__stop_event',
'__exception_event',
'__async_queue',
'__async_threads',
'bot',
'__dict__',
'__weakref__',
)
__singleton_lock = Lock()
__singleton_semaphore = BoundedSemaphore()
__singleton = None
@ -215,6 +241,17 @@ class Dispatcher:
else:
self._set_singleton(None)
def __setattr__(self, key: str, value: object) -> None:
# Mangled names don't automatically apply in __setattr__ (see
# https://docs.python.org/3/tutorial/classes.html#private-variables), so we have to make
# it mangled so they don't raise TelegramDeprecationWarning unnecessarily
if key.startswith('__'):
key = f"_{self.__class__.__name__}{key}"
if issubclass(self.__class__, Dispatcher) and self.__class__ is not Dispatcher:
object.__setattr__(self, key, value)
return
set_new_attribute_deprecated(self, key, value)
@property
def exception_event(self) -> Event: # skipcq: PY-D0003
return self.__exception_event

View file

@ -23,6 +23,7 @@ import re
import warnings
from abc import ABC, abstractmethod
from sys import version_info as py_ver
from threading import Lock
from typing import (
Dict,
@ -50,7 +51,7 @@ __all__ = [
'XORFilter',
]
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated
from telegram.utils.types import SLT
DataDict = Dict[str, list]
@ -112,8 +113,17 @@ class BaseFilter(ABC):
(depends on the handler).
"""
_name = None
data_filter = False
if py_ver < (3, 7):
__slots__ = ('_name', '_data_filter')
else:
__slots__ = ('_name', '_data_filter', '__dict__') # type: ignore[assignment]
def __new__(cls, *args: object, **kwargs: object) -> 'BaseFilter': # pylint: disable=W0613
instance = super().__new__(cls)
instance._name = None
instance._data_filter = False
return instance
@abstractmethod
def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]:
@ -131,13 +141,33 @@ class BaseFilter(ABC):
def __invert__(self) -> 'BaseFilter':
return InvertedFilter(self)
def __setattr__(self, key: str, value: object) -> None:
# Allow setting custom attributes w/o warning for user defined custom filters.
# To differentiate between a custom and a PTB filter, we use this hacky but
# simple way of checking the module name where the class is defined from.
if (
issubclass(self.__class__, (UpdateFilter, MessageFilter))
and self.__class__.__module__ != __name__
): # __name__ is telegram.ext.filters
object.__setattr__(self, key, value)
return
set_new_attribute_deprecated(self, key, value)
@property
def data_filter(self) -> bool:
return self._data_filter
@data_filter.setter
def data_filter(self, value: bool) -> None:
self._data_filter = value
@property
def name(self) -> Optional[str]:
return self._name
@name.setter
def name(self, name: Optional[str]) -> None:
self._name = name
self._name = name # pylint: disable=E0237
def __repr__(self) -> str:
# We do this here instead of in a __init__ so filter don't have to call __init__ or super()
@ -146,7 +176,7 @@ class BaseFilter(ABC):
return self.name
class MessageFilter(BaseFilter, ABC):
class MessageFilter(BaseFilter):
"""Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed
to :meth:`filter` is ``update.effective_message``.
@ -162,6 +192,8 @@ class MessageFilter(BaseFilter, ABC):
"""
__slots__ = ()
def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]:
return self.filter(update.effective_message)
@ -178,7 +210,7 @@ class MessageFilter(BaseFilter, ABC):
"""
class UpdateFilter(BaseFilter, ABC):
class UpdateFilter(BaseFilter):
"""Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object
passed to :meth:`filter` is ``update``, which allows to create filters like
:attr:`Filters.update.edited_message`.
@ -195,6 +227,8 @@ class UpdateFilter(BaseFilter, ABC):
"""
__slots__ = ()
def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]:
return self.filter(update)
@ -219,6 +253,8 @@ class InvertedFilter(UpdateFilter):
"""
__slots__ = ('f',)
def __init__(self, f: BaseFilter):
self.f = f
@ -244,6 +280,8 @@ class MergedFilter(UpdateFilter):
"""
__slots__ = ('base_filter', 'and_filter', 'or_filter')
def __init__(
self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None
):
@ -328,6 +366,8 @@ class XORFilter(UpdateFilter):
"""
__slots__ = ('base_filter', 'xor_filter', 'merged_filter')
def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter):
self.base_filter = base_filter
self.xor_filter = xor_filter
@ -346,11 +386,15 @@ class XORFilter(UpdateFilter):
class _DiceEmoji(MessageFilter):
__slots__ = ('emoji',)
def __init__(self, emoji: str = None, name: str = None):
self.name = f'Filters.dice.{name}' if name else 'Filters.dice'
self.emoji = emoji
class _DiceValues(MessageFilter):
__slots__ = ('values', 'emoji')
def __init__(
self,
values: SLT[int],
@ -393,7 +437,13 @@ class Filters:
"""
__slots__ = ('__dict__',)
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
class _All(MessageFilter):
__slots__ = ()
name = 'Filters.all'
def filter(self, message: Message) -> bool:
@ -403,9 +453,12 @@ class Filters:
"""All Messages."""
class _Text(MessageFilter):
__slots__ = ()
name = 'Filters.text'
class _TextStrings(MessageFilter):
__slots__ = ('strings',)
def __init__(self, strings: Union[List[str], Tuple[str]]):
self.strings = strings
self.name = f'Filters.text({strings})'
@ -454,9 +507,12 @@ class Filters:
"""
class _Caption(MessageFilter):
__slots__ = ()
name = 'Filters.caption'
class _CaptionStrings(MessageFilter):
__slots__ = ('strings',)
def __init__(self, strings: Union[List[str], Tuple[str]]):
self.strings = strings
self.name = f'Filters.caption({strings})'
@ -489,9 +545,12 @@ class Filters:
"""
class _Command(MessageFilter):
__slots__ = ()
name = 'Filters.command'
class _CommandOnlyStart(MessageFilter):
__slots__ = ('only_start',)
def __init__(self, only_start: bool):
self.only_start = only_start
self.name = f'Filters.command({only_start})'
@ -564,6 +623,7 @@ class Filters:
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
"""
__slots__ = ('pattern',)
data_filter = True
def __init__(self, pattern: Union[str, Pattern]):
@ -599,6 +659,7 @@ class Filters:
pattern (:obj:`str` | :obj:`Pattern`): The regex pattern.
"""
__slots__ = ('pattern',)
data_filter = True
def __init__(self, pattern: Union[str, Pattern]):
@ -617,6 +678,7 @@ class Filters:
return {}
class _Reply(MessageFilter):
__slots__ = ()
name = 'Filters.reply'
def filter(self, message: Message) -> bool:
@ -626,6 +688,7 @@ class Filters:
"""Messages that are a reply to another message."""
class _Audio(MessageFilter):
__slots__ = ()
name = 'Filters.audio'
def filter(self, message: Message) -> bool:
@ -635,6 +698,7 @@ class Filters:
"""Messages that contain :class:`telegram.Audio`."""
class _Document(MessageFilter):
__slots__ = ()
name = 'Filters.document'
class category(MessageFilter):
@ -651,7 +715,14 @@ class Filters:
of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'.
"""
__slots__ = ('_category',)
def __init__(self, category: Optional[str]):
"""Initialize the category you want to filter
Args:
category (str, optional): category of the media you want to filter
"""
self._category = category
self.name = f"Filters.document.category('{self._category}')"
@ -680,6 +751,8 @@ class Filters:
``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format.
"""
__slots__ = ('mimetype',)
def __init__(self, mimetype: Optional[str]):
self.mimetype = mimetype
self.name = f"Filters.document.mime_type('{self.mimetype}')"
@ -732,6 +805,8 @@ class Filters:
filters files without a dot in the filename.
"""
__slots__ = ('_file_extension', 'is_case_sensitive')
def __init__(self, file_extension: Optional[str], case_sensitive: bool = False):
"""Initialize the extension you want to filter.
@ -850,6 +925,7 @@ officedocument.wordprocessingml.document")``.
"""
class _Animation(MessageFilter):
__slots__ = ()
name = 'Filters.animation'
def filter(self, message: Message) -> bool:
@ -859,6 +935,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Animation`."""
class _Photo(MessageFilter):
__slots__ = ()
name = 'Filters.photo'
def filter(self, message: Message) -> bool:
@ -868,6 +945,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.PhotoSize`."""
class _Sticker(MessageFilter):
__slots__ = ()
name = 'Filters.sticker'
def filter(self, message: Message) -> bool:
@ -877,6 +955,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Sticker`."""
class _Video(MessageFilter):
__slots__ = ()
name = 'Filters.video'
def filter(self, message: Message) -> bool:
@ -886,6 +965,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Video`."""
class _Voice(MessageFilter):
__slots__ = ()
name = 'Filters.voice'
def filter(self, message: Message) -> bool:
@ -895,6 +975,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Voice`."""
class _VideoNote(MessageFilter):
__slots__ = ()
name = 'Filters.video_note'
def filter(self, message: Message) -> bool:
@ -904,6 +985,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.VideoNote`."""
class _Contact(MessageFilter):
__slots__ = ()
name = 'Filters.contact'
def filter(self, message: Message) -> bool:
@ -913,6 +995,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Contact`."""
class _Location(MessageFilter):
__slots__ = ()
name = 'Filters.location'
def filter(self, message: Message) -> bool:
@ -922,6 +1005,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Location`."""
class _Venue(MessageFilter):
__slots__ = ()
name = 'Filters.venue'
def filter(self, message: Message) -> bool:
@ -939,7 +1023,10 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ()
class _NewChatMembers(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.new_chat_members'
def filter(self, message: Message) -> bool:
@ -949,6 +1036,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.new_chat_members`."""
class _LeftChatMember(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.left_chat_member'
def filter(self, message: Message) -> bool:
@ -958,6 +1046,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.left_chat_member`."""
class _NewChatTitle(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.new_chat_title'
def filter(self, message: Message) -> bool:
@ -967,6 +1056,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.new_chat_title`."""
class _NewChatPhoto(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.new_chat_photo'
def filter(self, message: Message) -> bool:
@ -976,6 +1066,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.new_chat_photo`."""
class _DeleteChatPhoto(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.delete_chat_photo'
def filter(self, message: Message) -> bool:
@ -985,6 +1076,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.delete_chat_photo`."""
class _ChatCreated(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.chat_created'
def filter(self, message: Message) -> bool:
@ -1000,6 +1092,7 @@ officedocument.wordprocessingml.document")``.
:attr: `telegram.Message.channel_chat_created`."""
class _MessageAutoDeleteTimerChanged(MessageFilter):
__slots__ = ()
name = 'MessageAutoDeleteTimerChanged'
def filter(self, message: Message) -> bool:
@ -1009,6 +1102,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`message_auto_delete_timer_changed`"""
class _Migrate(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.migrate'
def filter(self, message: Message) -> bool:
@ -1019,6 +1113,7 @@ officedocument.wordprocessingml.document")``.
:attr:`telegram.Message.migrate_to_chat_id`."""
class _PinnedMessage(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.pinned_message'
def filter(self, message: Message) -> bool:
@ -1028,6 +1123,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.pinned_message`."""
class _ConnectedWebsite(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.connected_website'
def filter(self, message: Message) -> bool:
@ -1037,6 +1133,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.connected_website`."""
class _ProximityAlertTriggered(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.proximity_alert_triggered'
def filter(self, message: Message) -> bool:
@ -1046,6 +1143,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.proximity_alert_triggered`."""
class _VoiceChatScheduled(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.voice_chat_scheduled'
def filter(self, message: Message) -> bool:
@ -1055,6 +1153,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.voice_chat_scheduled`."""
class _VoiceChatStarted(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.voice_chat_started'
def filter(self, message: Message) -> bool:
@ -1064,6 +1163,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.voice_chat_started`."""
class _VoiceChatEnded(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.voice_chat_ended'
def filter(self, message: Message) -> bool:
@ -1073,6 +1173,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :attr:`telegram.Message.voice_chat_ended`."""
class _VoiceChatParticipantsInvited(MessageFilter):
__slots__ = ()
name = 'Filters.status_update.voice_chat_participants_invited'
def filter(self, message: Message) -> bool:
@ -1157,6 +1258,7 @@ officedocument.wordprocessingml.document")``.
"""
class _Forwarded(MessageFilter):
__slots__ = ()
name = 'Filters.forwarded'
def filter(self, message: Message) -> bool:
@ -1166,6 +1268,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that are forwarded."""
class _Game(MessageFilter):
__slots__ = ()
name = 'Filters.game'
def filter(self, message: Message) -> bool:
@ -1188,6 +1291,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ('entity_type',)
def __init__(self, entity_type: str):
self.entity_type = entity_type
self.name = f'Filters.entity({self.entity_type})'
@ -1210,6 +1315,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ('entity_type',)
def __init__(self, entity_type: str):
self.entity_type = entity_type
self.name = f'Filters.caption_entity({self.entity_type})'
@ -1219,6 +1326,7 @@ officedocument.wordprocessingml.document")``.
return any(entity.type == self.entity_type for entity in message.caption_entities)
class _Private(MessageFilter):
__slots__ = ()
name = 'Filters.private'
def filter(self, message: Message) -> bool:
@ -1239,6 +1347,7 @@ officedocument.wordprocessingml.document")``.
"""
class _Group(MessageFilter):
__slots__ = ()
name = 'Filters.group'
def filter(self, message: Message) -> bool:
@ -1259,9 +1368,11 @@ officedocument.wordprocessingml.document")``.
"""
class _ChatType(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type'
class _Channel(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type.channel'
def filter(self, message: Message) -> bool:
@ -1270,6 +1381,7 @@ officedocument.wordprocessingml.document")``.
channel = _Channel()
class _Group(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type.group'
def filter(self, message: Message) -> bool:
@ -1278,6 +1390,7 @@ officedocument.wordprocessingml.document")``.
group = _Group()
class _SuperGroup(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type.supergroup'
def filter(self, message: Message) -> bool:
@ -1286,6 +1399,7 @@ officedocument.wordprocessingml.document")``.
supergroup = _SuperGroup()
class _Groups(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type.groups'
def filter(self, message: Message) -> bool:
@ -1294,6 +1408,7 @@ officedocument.wordprocessingml.document")``.
groups = _Groups()
class _Private(MessageFilter):
__slots__ = ()
name = 'Filters.chat_type.private'
def filter(self, message: Message) -> bool:
@ -1321,6 +1436,15 @@ officedocument.wordprocessingml.document")``.
"""
class _ChatUserBaseFilter(MessageFilter, ABC):
__slots__ = (
'chat_id_name',
'username_name',
'allow_empty',
'__lock',
'_chat_ids',
'_usernames',
)
def __init__(
self,
chat_id: SLT[int] = None,
@ -1497,6 +1621,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ()
def __init__(
self,
user_id: SLT[int] = None,
@ -1596,6 +1722,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ()
def __init__(
self,
bot_id: SLT[int] = None,
@ -1695,6 +1823,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ()
def get_chat_or_user(self, message: Message) -> Optional[Chat]:
return message.chat
@ -1786,6 +1916,8 @@ officedocument.wordprocessingml.document")``.
is specified in :attr:`chat_ids` and :attr:`usernames`.
"""
__slots__ = ()
def get_chat_or_user(self, message: Message) -> Union[User, Chat, None]:
return message.forward_from or message.forward_from_chat
@ -1891,6 +2023,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ()
def get_chat_or_user(self, message: Message) -> Optional[Chat]:
return message.sender_chat
@ -1937,12 +2071,16 @@ officedocument.wordprocessingml.document")``.
return super().remove_chat_ids(chat_id)
class _SuperGroup(MessageFilter):
__slots__ = ()
def filter(self, message: Message) -> bool:
if message.sender_chat:
return message.sender_chat.type == Chat.SUPERGROUP
return False
class _Channel(MessageFilter):
__slots__ = ()
def filter(self, message: Message) -> bool:
if message.sender_chat:
return message.sender_chat.type == Chat.CHANNEL
@ -1952,6 +2090,7 @@ officedocument.wordprocessingml.document")``.
channel = _Channel()
class _Invoice(MessageFilter):
__slots__ = ()
name = 'Filters.invoice'
def filter(self, message: Message) -> bool:
@ -1961,6 +2100,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain :class:`telegram.Invoice`."""
class _SuccessfulPayment(MessageFilter):
__slots__ = ()
name = 'Filters.successful_payment'
def filter(self, message: Message) -> bool:
@ -1970,6 +2110,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that confirm a :class:`telegram.SuccessfulPayment`."""
class _PassportData(MessageFilter):
__slots__ = ()
name = 'Filters.passport_data'
def filter(self, message: Message) -> bool:
@ -1979,6 +2120,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain a :class:`telegram.PassportData`"""
class _Poll(MessageFilter):
__slots__ = ()
name = 'Filters.poll'
def filter(self, message: Message) -> bool:
@ -1988,6 +2130,7 @@ officedocument.wordprocessingml.document")``.
"""Messages that contain a :class:`telegram.Poll`."""
class _Dice(_DiceEmoji):
__slots__ = ()
dice = _DiceEmoji('🎲', 'dice')
darts = _DiceEmoji('🎯', 'darts')
basketball = _DiceEmoji('🏀', 'basketball')
@ -2051,6 +2194,8 @@ officedocument.wordprocessingml.document")``.
"""
__slots__ = ('lang',)
def __init__(self, lang: SLT[str]):
if isinstance(lang, str):
lang = cast(str, lang)
@ -2068,6 +2213,8 @@ officedocument.wordprocessingml.document")``.
)
class _Attachment(MessageFilter):
__slots__ = ()
name = 'Filters.attachment'
def filter(self, message: Message) -> bool:
@ -2080,9 +2227,11 @@ officedocument.wordprocessingml.document")``.
.. versionadded:: 13.6"""
class _UpdateType(UpdateFilter):
__slots__ = ()
name = 'Filters.update'
class _Message(UpdateFilter):
__slots__ = ()
name = 'Filters.update.message'
def filter(self, update: Update) -> bool:
@ -2091,6 +2240,7 @@ officedocument.wordprocessingml.document")``.
message = _Message()
class _EditedMessage(UpdateFilter):
__slots__ = ()
name = 'Filters.update.edited_message'
def filter(self, update: Update) -> bool:
@ -2099,6 +2249,7 @@ officedocument.wordprocessingml.document")``.
edited_message = _EditedMessage()
class _Messages(UpdateFilter):
__slots__ = ()
name = 'Filters.update.messages'
def filter(self, update: Update) -> bool:
@ -2107,6 +2258,7 @@ officedocument.wordprocessingml.document")``.
messages = _Messages()
class _ChannelPost(UpdateFilter):
__slots__ = ()
name = 'Filters.update.channel_post'
def filter(self, update: Update) -> bool:
@ -2115,6 +2267,7 @@ officedocument.wordprocessingml.document")``.
channel_post = _ChannelPost()
class _EditedChannelPost(UpdateFilter):
__slots__ = ()
name = 'Filters.update.edited_channel_post'
def filter(self, update: Update) -> bool:
@ -2123,6 +2276,7 @@ officedocument.wordprocessingml.document")``.
edited_channel_post = _EditedChannelPost()
class _ChannelPosts(UpdateFilter):
__slots__ = ()
name = 'Filters.update.channel_posts'
def filter(self, update: Update) -> bool:

View file

@ -17,9 +17,11 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the base class for handlers as used by the Dispatcher."""
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic
from sys import version_info as py_ver
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram import Update
from telegram.ext.utils.promise import Promise
@ -90,6 +92,27 @@ class Handler(Generic[UT], ABC):
"""
# Apparently Py 3.7 and below have '__dict__' in ABC
if py_ver < (3, 7):
__slots__ = (
'callback',
'pass_update_queue',
'pass_job_queue',
'pass_user_data',
'pass_chat_data',
'run_async',
)
else:
__slots__ = (
'callback', # type: ignore[assignment]
'pass_update_queue',
'pass_job_queue',
'pass_user_data',
'pass_chat_data',
'run_async',
'__dict__',
)
def __init__(
self,
callback: Callable[[UT, 'CallbackContext'], RT],
@ -106,6 +129,17 @@ class Handler(Generic[UT], ABC):
self.pass_chat_data = pass_chat_data
self.run_async = run_async
def __setattr__(self, key: str, value: object) -> None:
# See comment on BaseFilter to know why this was done.
if key.startswith('__'):
key = f"_{self.__class__.__name__}{key}"
if issubclass(self.__class__, Handler) and not self.__class__.__module__.startswith(
'telegram.ext.'
):
object.__setattr__(self, key, value)
return
set_new_attribute_deprecated(self, key, value)
@abstractmethod
def check_update(self, update: object) -> Optional[Union[bool, object]]:
"""

View file

@ -129,6 +129,8 @@ class InlineQueryHandler(Handler[Update]):
"""
__slots__ = ('pattern', 'chat_types', 'pass_groups', 'pass_groupdict')
def __init__(
self,
callback: Callable[[Update, 'CallbackContext'], RT],

View file

@ -31,6 +31,7 @@ from apscheduler.job import Job as APSJob
from telegram.ext.callbackcontext import CallbackContext
from telegram.utils.types import JSONDict
from telegram.utils.deprecate import set_new_attribute_deprecated
if TYPE_CHECKING:
from telegram import Bot
@ -49,6 +50,8 @@ class JobQueue:
"""
__slots__ = ('_dispatcher', 'logger', 'scheduler', '__dict__')
def __init__(self) -> None:
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
self.logger = logging.getLogger(self.__class__.__name__)
@ -64,6 +67,9 @@ class JobQueue:
logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter)
self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR)
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]:
if self._dispatcher.use_context:
return [CallbackContext.from_job(job, self._dispatcher)]
@ -542,6 +548,17 @@ class Job:
job (:class:`apscheduler.job.Job`): Optional. The APS Job this job is a wrapper for.
"""
__slots__ = (
'callback',
'context',
'name',
'job_queue',
'_removed',
'_enabled',
'job',
'__dict__',
)
def __init__(
self,
callback: Callable[['CallbackContext'], None],
@ -561,6 +578,9 @@ class Job:
self.job = cast(APSJob, job) # skipcq: PTC-W0052
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
def run(self, dispatcher: 'Dispatcher') -> None:
"""Executes the callback function independently of the jobs schedule."""
try:

View file

@ -120,6 +120,8 @@ class MessageHandler(Handler[Update]):
"""
__slots__ = ('filters',)
def __init__(
self,
filters: BaseFilter,

View file

@ -40,6 +40,8 @@ curtime = time.perf_counter
class DelayQueueError(RuntimeError):
"""Indicates processing errors."""
__slots__ = ()
class DelayQueue(threading.Thread):
"""

View file

@ -73,6 +73,16 @@ class PicklePersistence(BasePersistence):
Default is :obj:`False`.
"""
__slots__ = (
'filename',
'single_file',
'on_flush',
'user_data',
'chat_data',
'bot_data',
'conversations',
)
def __init__(
self,
filename: str,

View file

@ -82,6 +82,8 @@ class PollAnswerHandler(Handler[Update]):
"""
__slots__ = ()
def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`.

View file

@ -82,6 +82,8 @@ class PollHandler(Handler[Update]):
"""
__slots__ = ()
def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`.

View file

@ -82,6 +82,8 @@ class PreCheckoutQueryHandler(Handler[Update]):
"""
__slots__ = ()
def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`.

View file

@ -108,6 +108,8 @@ class RegexHandler(MessageHandler):
"""
__slots__ = ('pass_groups', 'pass_groupdict')
def __init__(
self,
pattern: Union[str, Pattern],

View file

@ -81,6 +81,8 @@ class ShippingQueryHandler(Handler[Update]):
"""
__slots__ = ()
def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`.

View file

@ -85,6 +85,8 @@ class StringCommandHandler(Handler[str]):
"""
__slots__ = ('command', 'pass_args')
def __init__(
self,
command: str,

View file

@ -91,6 +91,8 @@ class StringRegexHandler(Handler[str]):
"""
__slots__ = ('pass_groups', 'pass_groupdict', 'pattern')
def __init__(
self,
pattern: Union[str, Pattern],

View file

@ -75,6 +75,8 @@ class TypeHandler(Handler[UT]):
"""
__slots__ = ('type', 'strict')
def __init__(
self,
type: Type[UT], # pylint: disable=W0622
@ -90,8 +92,8 @@ class TypeHandler(Handler[UT]):
pass_job_queue=pass_job_queue,
run_async=run_async,
)
self.type = type
self.strict = strict
self.type = type # pylint: disable=E0237
self.strict = strict # pylint: disable=E0237
def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`.

View file

@ -30,7 +30,7 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Un
from telegram import Bot, TelegramError
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized
from telegram.ext import Dispatcher, JobQueue
from telegram.utils.deprecate import TelegramDeprecationWarning
from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated
from telegram.utils.helpers import get_signal_name
from telegram.utils.request import Request
from telegram.ext.utils.webhookhandler import WebhookAppClass, WebhookServer
@ -105,7 +105,24 @@ class Updater:
"""
_request = None
__slots__ = (
'persistence',
'dispatcher',
'user_sig_handler',
'bot',
'logger',
'update_queue',
'job_queue',
'__exception_event',
'last_update_id',
'running',
'_request',
'is_idle',
'httpd',
'__lock',
'__threads',
'__dict__',
)
def __init__(
self,
@ -150,6 +167,7 @@ class Updater:
raise ValueError('`dispatcher` and `use_context` are mutually exclusive')
self.logger = logging.getLogger(__name__)
self._request = None
if dispatcher is None:
con_pool_size = workers + 4
@ -219,6 +237,14 @@ class Updater:
self.__lock = Lock()
self.__threads: List[Thread] = []
def __setattr__(self, key: str, value: object) -> None:
if key.startswith('__'):
key = f"_{self.__class__.__name__}{key}"
if issubclass(self.__class__, Updater) and self.__class__ is not Updater:
object.__setattr__(self, key, value)
return
set_new_attribute_deprecated(self, key, value)
def _init_thread(self, target: Callable, name: str, *args: object, **kwargs: object) -> None:
thr = Thread(
target=self._thread_wrapper,

View file

@ -22,6 +22,7 @@ import logging
from threading import Event
from typing import Callable, List, Optional, Tuple, TypeVar, Union
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram.utils.types import JSONDict
RT = TypeVar('RT')
@ -54,6 +55,19 @@ class Promise:
"""
__slots__ = (
'pooled_function',
'args',
'kwargs',
'update',
'error_handling',
'done',
'_done_callback',
'_result',
'_exception',
'__dict__',
)
# TODO: Remove error_handling parameter once we drop the @run_async decorator
def __init__(
self,
@ -73,6 +87,9 @@ class Promise:
self._result: Optional[RT] = None
self._exception: Optional[Exception] = None
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
def run(self) -> None:
"""Calls the :attr:`pooled_function` callable."""
try:

View file

@ -30,6 +30,7 @@ from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from telegram import Update
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram.utils.types import JSONDict
if TYPE_CHECKING:
@ -42,6 +43,18 @@ except ImportError:
class WebhookServer:
__slots__ = (
'http_server',
'listen',
'port',
'loop',
'logger',
'is_running',
'server_lock',
'shutdown_lock',
'__dict__',
)
def __init__(
self, listen: str, port: int, webhook_app: 'WebhookAppClass', ssl_ctx: SSLContext
):
@ -54,6 +67,9 @@ class WebhookServer:
self.server_lock = Lock()
self.shutdown_lock = Lock()
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
def serve_forever(self, ready: Event = None) -> None:
with self.server_lock:
IOLoop().make_current()

View file

@ -65,6 +65,20 @@ class Animation(TelegramObject):
"""
__slots__ = (
'bot',
'width',
'file_id',
'file_size',
'file_name',
'thumb',
'duration',
'mime_type',
'height',
'file_unique_id',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -69,6 +69,20 @@ class Audio(TelegramObject):
"""
__slots__ = (
'file_id',
'bot',
'file_size',
'file_name',
'thumb',
'title',
'duration',
'performer',
'mime_type',
'file_unique_id',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -65,6 +65,15 @@ class ChatPhoto(TelegramObject):
"""
__slots__ = (
'big_file_unique_id',
'bot',
'small_file_id',
'small_file_unique_id',
'big_file_id',
'_id_attrs',
)
def __init__(
self,
small_file_id: str,

View file

@ -46,6 +46,8 @@ class Contact(TelegramObject):
"""
__slots__ = ('vcard', 'user_id', 'first_name', 'last_name', 'phone_number', '_id_attrs')
def __init__(
self,
phone_number: str,

View file

@ -60,6 +60,17 @@ class Document(TelegramObject):
"""
__slots__ = (
'bot',
'file_id',
'file_size',
'file_name',
'thumb',
'mime_type',
'file_unique_id',
'_id_attrs',
)
_id_keys = ('file_id',)
def __init__(

View file

@ -67,6 +67,16 @@ class File(TelegramObject):
"""
__slots__ = (
'bot',
'file_id',
'file_size',
'file_unique_id',
'file_path',
'_credentials',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -26,6 +26,8 @@ import os
from typing import IO, Optional, Tuple, Union
from uuid import uuid4
from telegram.utils.deprecate import set_new_attribute_deprecated
DEFAULT_MIME_TYPE = 'application/octet-stream'
logger = logging.getLogger(__name__)
@ -50,6 +52,8 @@ class InputFile:
"""
__slots__ = ('filename', 'attach', 'input_file_content', 'mimetype', '__dict__')
def __init__(self, obj: Union[IO, bytes], filename: str = None, attach: bool = None):
self.filename = None
if isinstance(obj, bytes):
@ -74,6 +78,9 @@ class InputFile:
if not self.filename:
self.filename = self.mimetype.replace('/', '.')
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
@property
def field_tuple(self) -> Tuple[str, bytes, str]: # skipcq: PY-D0003
return self.filename, self.input_file_content, self.mimetype

View file

@ -43,6 +43,7 @@ class InputMedia(TelegramObject):
"""
__slots__ = ()
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None
def to_dict(self) -> JSONDict:
@ -113,6 +114,18 @@ class InputMediaAnimation(InputMedia):
"""
__slots__ = (
'caption_entities',
'width',
'media',
'thumb',
'caption',
'duration',
'parse_mode',
'height',
'type',
)
def __init__(
self,
media: Union[FileInput, Animation],
@ -185,6 +198,8 @@ class InputMediaPhoto(InputMedia):
"""
__slots__ = ('caption_entities', 'media', 'caption', 'parse_mode', 'type')
def __init__(
self,
media: Union[FileInput, PhotoSize],
@ -265,6 +280,19 @@ class InputMediaVideo(InputMedia):
"""
__slots__ = (
'caption_entities',
'width',
'media',
'thumb',
'supports_streaming',
'caption',
'duration',
'parse_mode',
'height',
'type',
)
def __init__(
self,
media: Union[FileInput, Video],
@ -364,6 +392,18 @@ class InputMediaAudio(InputMedia):
"""
__slots__ = (
'caption_entities',
'media',
'thumb',
'caption',
'title',
'duration',
'type',
'parse_mode',
'performer',
)
def __init__(
self,
media: Union[FileInput, Audio],
@ -452,6 +492,16 @@ class InputMediaDocument(InputMedia):
"""
__slots__ = (
'caption_entities',
'media',
'thumb',
'caption',
'parse_mode',
'type',
'disable_content_type_detection',
)
def __init__(
self,
media: Union[FileInput, Document],

View file

@ -56,6 +56,16 @@ class Location(TelegramObject):
"""
__slots__ = (
'longitude',
'horizontal_accuracy',
'proximity_alert_radius',
'live_period',
'latitude',
'heading',
'_id_attrs',
)
def __init__(
self,
longitude: float,

View file

@ -58,6 +58,8 @@ class PhotoSize(TelegramObject):
"""
__slots__ = ('bot', 'width', 'file_id', 'file_size', 'height', 'file_unique_id', '_id_attrs')
def __init__(
self,
file_id: str,

View file

@ -73,6 +73,21 @@ class Sticker(TelegramObject):
"""
__slots__ = (
'bot',
'width',
'file_id',
'is_animated',
'file_size',
'thumb',
'set_name',
'mask_position',
'height',
'file_unique_id',
'emoji',
'_id_attrs',
)
def __init__(
self,
file_id: str,
@ -160,6 +175,16 @@ class StickerSet(TelegramObject):
"""
__slots__ = (
'is_animated',
'contains_masks',
'thumb',
'title',
'stickers',
'name',
'_id_attrs',
)
def __init__(
self,
name: str,
@ -233,6 +258,8 @@ class MaskPosition(TelegramObject):
"""
__slots__ = ('point', 'scale', 'x_shift', 'y_shift', '_id_attrs')
FOREHEAD: ClassVar[str] = constants.STICKER_FOREHEAD
""":const:`telegram.constants.STICKER_FOREHEAD`"""
EYES: ClassVar[str] = constants.STICKER_EYES

View file

@ -60,6 +60,17 @@ class Venue(TelegramObject):
"""
__slots__ = (
'google_place_type',
'location',
'title',
'address',
'foursquare_type',
'foursquare_id',
'google_place_id',
'_id_attrs',
)
def __init__(
self,
location: Location,

View file

@ -66,6 +66,20 @@ class Video(TelegramObject):
"""
__slots__ = (
'bot',
'width',
'file_id',
'file_size',
'file_name',
'thumb',
'duration',
'mime_type',
'height',
'file_unique_id',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -61,6 +61,17 @@ class VideoNote(TelegramObject):
"""
__slots__ = (
'bot',
'length',
'file_id',
'file_size',
'thumb',
'duration',
'file_unique_id',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -58,6 +58,16 @@ class Voice(TelegramObject):
"""
__slots__ = (
'bot',
'file_id',
'file_size',
'duration',
'mime_type',
'file_unique_id',
'_id_attrs',
)
def __init__(
self,
file_id: str,

View file

@ -50,6 +50,8 @@ class ForceReply(ReplyMarkup):
"""
__slots__ = ('selective', 'force_reply', '_id_attrs')
def __init__(self, force_reply: bool = True, selective: bool = False, **_kwargs: Any):
# Required
self.force_reply = bool(force_reply)

View file

@ -23,3 +23,5 @@ from telegram import TelegramObject
class CallbackGame(TelegramObject):
"""A placeholder, currently holds no information. Use BotFather to set up your game."""
__slots__ = ()

View file

@ -67,6 +67,16 @@ class Game(TelegramObject):
"""
__slots__ = (
'title',
'photo',
'description',
'text_entities',
'text',
'animation',
'_id_attrs',
)
def __init__(
self,
title: str,

View file

@ -45,6 +45,8 @@ class GameHighScore(TelegramObject):
"""
__slots__ = ('position', 'user', 'score', '_id_attrs')
def __init__(self, position: int, user: User, score: int):
self.position = position
self.user = user

View file

@ -83,6 +83,18 @@ class InlineKeyboardButton(TelegramObject):
"""
__slots__ = (
'callback_game',
'url',
'switch_inline_query_current_chat',
'callback_data',
'pay',
'switch_inline_query',
'text',
'_id_attrs',
'login_url',
)
def __init__(
self,
text: str,

View file

@ -45,6 +45,8 @@ class InlineKeyboardMarkup(ReplyMarkup):
"""
__slots__ = ('inline_keyboard', '_id_attrs')
def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **_kwargs: Any):
# Required
self.inline_keyboard = inline_keyboard

View file

@ -71,6 +71,8 @@ class InlineQuery(TelegramObject):
"""
__slots__ = ('bot', 'location', 'chat_type', 'id', 'offset', 'from_user', 'query', '_id_attrs')
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -46,6 +46,8 @@ class InlineQueryResult(TelegramObject):
"""
__slots__ = ('type', 'id', '_id_attrs')
def __init__(self, type: str, id: str, **_kwargs: Any):
# Required
self.type = str(type)

View file

@ -63,6 +63,18 @@ class InlineQueryResultArticle(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'thumb_width',
'thumb_height',
'hide_url',
'url',
'title',
'description',
'input_message_content',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -74,6 +74,18 @@ class InlineQueryResultAudio(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'title',
'parse_mode',
'audio_url',
'performer',
'input_message_content',
'audio_duration',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -68,6 +68,15 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'parse_mode',
'audio_file_id',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -75,6 +75,17 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'document_file_id',
'caption',
'title',
'description',
'parse_mode',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -73,6 +73,16 @@ class InlineQueryResultCachedGif(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'title',
'input_message_content',
'parse_mode',
'gif_file_id',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -73,6 +73,16 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'mpeg4_file_id',
'caption',
'title',
'parse_mode',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -76,6 +76,17 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'title',
'description',
'parse_mode',
'photo_file_id',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -52,6 +52,8 @@ class InlineQueryResultCachedSticker(InlineQueryResult):
"""
__slots__ = ('reply_markup', 'input_message_content', 'sticker_file_id')
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -75,6 +75,17 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'title',
'description',
'parse_mode',
'input_message_content',
'video_file_id',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -70,6 +70,16 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'caption',
'title',
'parse_mode',
'voice_file_id',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -66,6 +66,18 @@ class InlineQueryResultContact(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'thumb_width',
'thumb_height',
'vcard',
'first_name',
'last_name',
'phone_number',
'input_message_content',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -85,6 +85,21 @@ class InlineQueryResultDocument(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'document_url',
'thumb_width',
'thumb_height',
'caption',
'title',
'description',
'parse_mode',
'mime_type',
'thumb_url',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -45,6 +45,8 @@ class InlineQueryResultGame(InlineQueryResult):
"""
__slots__ = ('reply_markup', 'game_short_name')
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -86,6 +86,21 @@ class InlineQueryResultGif(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'gif_height',
'thumb_mime_type',
'caption_entities',
'gif_width',
'title',
'caption',
'parse_mode',
'gif_duration',
'input_message_content',
'gif_url',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -79,6 +79,21 @@ class InlineQueryResultLocation(InlineQueryResult):
"""
__slots__ = (
'longitude',
'reply_markup',
'thumb_width',
'thumb_height',
'heading',
'title',
'live_period',
'proximity_alert_radius',
'input_message_content',
'latitude',
'horizontal_accuracy',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -85,6 +85,21 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'thumb_mime_type',
'caption_entities',
'mpeg4_duration',
'mpeg4_width',
'title',
'caption',
'parse_mode',
'input_message_content',
'mpeg4_url',
'mpeg4_height',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -82,6 +82,20 @@ class InlineQueryResultPhoto(InlineQueryResult):
"""
__slots__ = (
'photo_url',
'reply_markup',
'caption_entities',
'photo_width',
'caption',
'title',
'description',
'parse_mode',
'input_message_content',
'photo_height',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -79,6 +79,22 @@ class InlineQueryResultVenue(InlineQueryResult):
"""
__slots__ = (
'longitude',
'reply_markup',
'google_place_type',
'thumb_width',
'thumb_height',
'title',
'address',
'foursquare_id',
'foursquare_type',
'google_place_id',
'input_message_content',
'latitude',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -92,6 +92,22 @@ class InlineQueryResultVideo(InlineQueryResult):
"""
__slots__ = (
'video_url',
'reply_markup',
'caption_entities',
'caption',
'title',
'description',
'video_duration',
'parse_mode',
'mime_type',
'input_message_content',
'video_height',
'video_width',
'thumb_url',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -73,6 +73,17 @@ class InlineQueryResultVoice(InlineQueryResult):
"""
__slots__ = (
'reply_markup',
'caption_entities',
'voice_duration',
'caption',
'title',
'voice_url',
'parse_mode',
'input_message_content',
)
def __init__(
self,
id: str, # pylint: disable=W0622

View file

@ -46,6 +46,8 @@ class InputContactMessageContent(InputMessageContent):
"""
__slots__ = ('vcard', 'first_name', 'last_name', 'phone_number', '_id_attrs')
def __init__(
self,
phone_number: str,

View file

@ -123,6 +123,30 @@ class InputInvoiceMessageContent(InputMessageContent):
"""
__slots__ = (
'title',
'description',
'payload',
'provider_token',
'currency',
'prices',
'max_tip_amount',
'suggested_tip_amounts',
'provider_data',
'photo_url',
'photo_size',
'photo_width',
'photo_height',
'need_name',
'need_phone_number',
'need_email',
'need_shipping_address',
'send_phone_number_to_provider',
'send_email_to_provider',
'is_flexible',
'_id_attrs',
)
def __init__(
self,
title: str,

View file

@ -59,6 +59,8 @@ class InputLocationMessageContent(InputMessageContent):
"""
__slots__ = ('longitude', 'horizontal_accuracy', 'proximity_alert_radius', 'live_period',
'latitude', 'heading', '_id_attrs')
# fmt: on
def __init__(

View file

@ -30,3 +30,5 @@ class InputMessageContent(TelegramObject):
:class:`telegram.InputVenueMessageContent` for more details.
"""
__slots__ = ()

View file

@ -59,6 +59,8 @@ class InputTextMessageContent(InputMessageContent):
"""
__slots__ = ('disable_web_page_preview', 'parse_mode', 'entities', 'message_text', '_id_attrs')
def __init__(
self,
message_text: str,

View file

@ -60,6 +60,18 @@ class InputVenueMessageContent(InputMessageContent):
"""
__slots__ = (
'longitude',
'google_place_type',
'title',
'address',
'foursquare_id',
'foursquare_type',
'google_place_id',
'latitude',
'_id_attrs',
)
def __init__(
self,
latitude: float,

View file

@ -58,6 +58,8 @@ class KeyboardButton(TelegramObject):
"""
__slots__ = ('request_location', 'request_contact', 'request_poll', 'text', '_id_attrs')
def __init__(
self,
text: str,

View file

@ -37,6 +37,8 @@ class KeyboardButtonPollType(TelegramObject):
create a poll of any type.
"""
__slots__ = ('type', '_id_attrs')
def __init__(self, type: str = None, **_kwargs: Any): # pylint: disable=W0622
self.type = type

View file

@ -69,6 +69,8 @@ class LoginUrl(TelegramObject):
"""
__slots__ = ('bot_username', 'request_write_access', 'url', 'forward_text', '_id_attrs')
def __init__(
self,
url: str,

View file

@ -77,8 +77,6 @@ if TYPE_CHECKING:
LabeledPrice,
)
_UNDEFINED = object()
class Message(TelegramObject):
# fmt: off
@ -333,8 +331,67 @@ class Message(TelegramObject):
"""
# fmt: on
_effective_attachment = _UNDEFINED
__slots__ = (
'reply_markup',
'audio',
'contact',
'migrate_to_chat_id',
'forward_signature',
'chat',
'successful_payment',
'game',
'text',
'forward_sender_name',
'document',
'new_chat_title',
'forward_date',
'group_chat_created',
'media_group_id',
'caption',
'video',
'bot',
'entities',
'via_bot',
'new_chat_members',
'connected_website',
'animation',
'migrate_from_chat_id',
'forward_from',
'sticker',
'location',
'venue',
'edit_date',
'reply_to_message',
'passport_data',
'pinned_message',
'forward_from_chat',
'new_chat_photo',
'message_id',
'delete_chat_photo',
'from_user',
'author_signature',
'proximity_alert_triggered',
'sender_chat',
'dice',
'forward_from_message_id',
'caption_entities',
'voice',
'date',
'supergroup_chat_created',
'poll',
'left_chat_member',
'photo',
'channel_chat_created',
'invoice',
'video_note',
'_effective_attachment',
'message_auto_delete_timer_changed',
'voice_chat_ended',
'voice_chat_participants_invited',
'voice_chat_started',
'voice_chat_scheduled',
'_id_attrs',
)
ATTACHMENT_TYPES: ClassVar[List[str]] = [
'audio',
@ -497,6 +554,8 @@ class Message(TelegramObject):
self.reply_markup = reply_markup
self.bot = bot
self._effective_attachment = DEFAULT_NONE
self._id_attrs = (self.message_id, self.chat)
@property
@ -613,7 +672,7 @@ class Message(TelegramObject):
:obj:`None` if no attachment was sent.
"""
if self._effective_attachment is not _UNDEFINED:
if self._effective_attachment is not DEFAULT_NONE:
return self._effective_attachment # type: ignore
for i in Message.ATTACHMENT_TYPES:
@ -626,10 +685,7 @@ class Message(TelegramObject):
return self._effective_attachment # type: ignore
def __getitem__(self, item: str) -> Any: # pylint: disable=R1710
if item in self.__dict__.keys():
return self.__dict__[item]
if item == 'chat_id':
return self.chat.id
return self.chat.id if item == 'chat_id' else super().__getitem__(item)
def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""

View file

@ -44,6 +44,8 @@ class MessageAutoDeleteTimerChanged(TelegramObject):
"""
__slots__ = ('message_auto_delete_time', '_id_attrs')
def __init__(
self,
message_auto_delete_time: int,

View file

@ -59,6 +59,8 @@ class MessageEntity(TelegramObject):
"""
__slots__ = ('length', 'url', 'user', 'type', 'language', 'offset', '_id_attrs')
def __init__(
self,
type: str, # pylint: disable=W0622

View file

@ -32,6 +32,8 @@ class MessageId(TelegramObject):
message_id (:obj:`int`): Unique message identifier
"""
__slots__ = ('message_id', '_id_attrs')
def __init__(self, message_id: int, **_kwargs: Any):
self.message_id = int(message_id)

View file

@ -21,11 +21,14 @@
from typing import ClassVar
from telegram import constants
from telegram.utils.deprecate import set_new_attribute_deprecated
class ParseMode:
"""This object represents a Telegram Message Parse Modes."""
__slots__ = ('__dict__',)
MARKDOWN: ClassVar[str] = constants.PARSEMODE_MARKDOWN
""":const:`telegram.constants.PARSEMODE_MARKDOWN`\n
@ -37,3 +40,6 @@ class ParseMode:
""":const:`telegram.constants.PARSEMODE_MARKDOWN_V2`"""
HTML: ClassVar[str] = constants.PARSEMODE_HTML
""":const:`telegram.constants.PARSEMODE_HTML`"""
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)

View file

@ -51,6 +51,8 @@ if TYPE_CHECKING:
class TelegramDecryptionError(TelegramError):
"""Something went wrong with decryption."""
__slots__ = ('_msg',)
def __init__(self, message: Union[str, Exception]):
super().__init__(f"TelegramDecryptionError: {message}")
self._msg = str(message)
@ -143,6 +145,16 @@ class EncryptedCredentials(TelegramObject):
"""
__slots__ = (
'hash',
'secret',
'bot',
'data',
'_id_attrs',
'_decrypted_secret',
'_decrypted_data',
)
def __init__(self, data: str, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any):
# Required
self.data = data
@ -212,6 +224,8 @@ class Credentials(TelegramObject):
nonce (:obj:`str`): Bot-specified nonce
"""
__slots__ = ('bot', 'nonce', 'secure_data')
def __init__(self, secure_data: 'SecureData', nonce: str, bot: 'Bot' = None, **_kwargs: Any):
# Required
self.secure_data = secure_data
@ -260,6 +274,21 @@ class SecureData(TelegramObject):
temporary registration.
"""
__slots__ = (
'bot',
'utility_bill',
'personal_details',
'temporary_registration',
'address',
'driver_license',
'rental_agreement',
'internal_passport',
'identity_card',
'bank_statement',
'passport',
'passport_registration',
)
def __init__(
self,
personal_details: 'SecureValue' = None,
@ -345,6 +374,8 @@ class SecureValue(TelegramObject):
"""
__slots__ = ('data', 'front_side', 'reverse_side', 'selfie', 'files', 'translation', 'bot')
def __init__(
self,
data: 'DataCredentials' = None,
@ -395,6 +426,8 @@ class SecureValue(TelegramObject):
class _CredentialsBase(TelegramObject):
"""Base class for DataCredentials and FileCredentials."""
__slots__ = ('hash', 'secret', 'file_hash', 'data_hash', 'bot')
def __init__(self, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any):
self.hash = hash
self.secret = secret
@ -420,6 +453,8 @@ class DataCredentials(_CredentialsBase):
secret (:obj:`str`): Secret of encrypted data
"""
__slots__ = ()
def __init__(self, data_hash: str, secret: str, **_kwargs: Any):
super().__init__(data_hash, secret, **_kwargs)
@ -447,6 +482,8 @@ class FileCredentials(_CredentialsBase):
secret (:obj:`str`): Secret of encrypted file
"""
__slots__ = ()
def __init__(self, file_hash: str, secret: str, **_kwargs: Any):
super().__init__(file_hash, secret, **_kwargs)

Some files were not shown because too many files have changed in this diff Show more