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 typing import TYPE_CHECKING, List, Optional, Tuple, Type, TypeVar
from telegram.utils.types import JSONDict from telegram.utils.types import JSONDict
from telegram.utils.deprecate import set_new_attribute_deprecated
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot from telegram import Bot
@ -38,11 +39,19 @@ class TelegramObject:
_id_attrs: Tuple[object, ...] = () _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: def __str__(self) -> str:
return str(self.to_dict()) return str(self.to_dict())
def __getitem__(self, item: str) -> object: 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 @staticmethod
def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]: def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
@ -102,11 +111,16 @@ class TelegramObject:
""" """
data = {} 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('_'): if key == 'bot' or key.startswith('_'):
continue continue
value = self.__dict__[key] value = getattr(self, key, None)
if value is not None: if value is not None:
if hasattr(value, 'to_dict'): if hasattr(value, 'to_dict'):
data[key] = 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__( def __init__(
self, self,
token: str, token: str,
@ -184,6 +196,7 @@ class Bot(TelegramObject):
self._bot: Optional[User] = None self._bot: Optional[User] = None
self._commands: Optional[List[BotCommand]] = None self._commands: Optional[List[BotCommand]] = None
self._request = request or Request() self._request = request or Request()
self.private_key = None
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
if private_key: if private_key:
@ -196,6 +209,12 @@ class Bot(TelegramObject):
private_key, password=private_key_password, backend=default_backend() 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( def _insert_defaults(
self, data: Dict[str, object], timeout: ODVInput[float] self, data: Dict[str, object], timeout: ODVInput[float]
) -> Optional[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): def __init__(self, command: str, description: str, **_kwargs: Any):
self.command = command self.command = command
self.description = description 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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 SENDER: ClassVar[str] = constants.CHAT_SENDER
""":const:`telegram.constants.CHAT_SENDER` """:const:`telegram.constants.CHAT_SENDER`

View file

@ -20,11 +20,13 @@
"""This module contains an object that represents a Telegram ChatAction.""" """This module contains an object that represents a Telegram ChatAction."""
from typing import ClassVar from typing import ClassVar
from telegram import constants from telegram import constants
from telegram.utils.deprecate import set_new_attribute_deprecated
class ChatAction: class ChatAction:
"""Helper class to provide constants for different chat actions.""" """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 FIND_LOCATION: ClassVar[str] = constants.CHATACTION_FIND_LOCATION
""":const:`telegram.constants.CHATACTION_FIND_LOCATION`""" """:const:`telegram.constants.CHATACTION_FIND_LOCATION`"""
RECORD_AUDIO: ClassVar[str] = constants.CHATACTION_RECORD_AUDIO RECORD_AUDIO: ClassVar[str] = constants.CHATACTION_RECORD_AUDIO
@ -65,3 +67,6 @@ class ChatAction:
""":const:`telegram.constants.CHATACTION_UPLOAD_VIDEO`""" """:const:`telegram.constants.CHATACTION_UPLOAD_VIDEO`"""
UPLOAD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO_NOTE UPLOAD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO_NOTE
""":const:`telegram.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__( def __init__(
self, self,
invite_link: str, invite_link: str,

View file

@ -47,6 +47,8 @@ class ChatLocation(TelegramObject):
""" """
__slots__ = ('location', '_id_attrs', 'address')
def __init__( def __init__(
self, self,
location: Location, 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 ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR
""":const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`""" """:const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`"""
CREATOR: ClassVar[str] = constants.CHATMEMBER_CREATOR 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__( def __init__(
self, self,
chat: Chat, 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__( def __init__(
self, self,
can_send_messages: bool = None, 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__( def __init__(
self, self,
result_id: str, 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): def __init__(self, value: int, emoji: str, **_kwargs: Any):
self.value = value self.value = value
self.emoji = emoji self.emoji = emoji

View file

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

View file

@ -18,10 +18,13 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains the BasePersistence class.""" """This module contains the BasePersistence class."""
import warnings import warnings
from sys import version_info as py_ver
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from copy import copy from copy import copy
from typing import DefaultDict, Dict, Optional, Tuple, cast, ClassVar from typing import DefaultDict, Dict, Optional, Tuple, cast, ClassVar
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram import Bot from telegram import Bot
from telegram.utils.types import ConversationDict from telegram.utils.types import ConversationDict
@ -75,6 +78,18 @@ class BasePersistence(ABC):
persistence class. 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__( def __new__(
cls, *args: object, **kwargs: object # pylint: disable=W0613 cls, *args: object, **kwargs: object # pylint: disable=W0613
) -> 'BasePersistence': ) -> 'BasePersistence':
@ -104,12 +119,13 @@ class BasePersistence(ABC):
def update_bot_data_replace_bot(data: Dict) -> None: def update_bot_data_replace_bot(data: Dict) -> None:
return update_bot_data(instance.replace_bot(data)) return update_bot_data(instance.replace_bot(data))
instance.get_user_data = get_user_data_insert_bot # We want to ignore TGDeprecation warnings so we use obj.__setattr__. Adds to __dict__
instance.get_chat_data = get_chat_data_insert_bot object.__setattr__(instance, 'get_user_data', get_user_data_insert_bot)
instance.get_bot_data = get_bot_data_insert_bot object.__setattr__(instance, 'get_chat_data', get_chat_data_insert_bot)
instance.update_user_data = update_user_data_replace_bot object.__setattr__(instance, 'get_bot_data', get_bot_data_insert_bot)
instance.update_chat_data = update_chat_data_replace_bot object.__setattr__(instance, 'update_user_data', update_user_data_replace_bot)
instance.update_bot_data = update_bot_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 return instance
def __init__( def __init__(
@ -123,6 +139,16 @@ class BasePersistence(ABC):
self.store_bot_data = store_bot_data self.store_bot_data = store_bot_data
self.bot: Bot = None # type: ignore[assignment] 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: def set_bot(self, bot: Bot) -> None:
"""Set the Bot to be used by this persistence instance. """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'): def __init__(self, dispatcher: 'Dispatcher'):
""" """
Args: Args:
@ -229,12 +243,13 @@ class CallbackContext:
return self return self
def update(self, data: Dict[str, object]) -> None: def update(self, data: Dict[str, object]) -> None:
"""Updates ``self.__dict__`` with the passed data. """Updates ``self.__slots__`` with the passed data.
Args: Args:
data (Dict[:obj:`str`, :obj:`object`]): The data. data (Dict[:obj:`str`, :obj:`object`]): The data.
""" """
self.__dict__.update(data) for key, value in data.items():
setattr(self, key, value)
@property @property
def bot(self) -> 'Bot': def bot(self) -> 'Bot':

View file

@ -120,6 +120,8 @@ class CallbackQueryHandler(Handler[Update]):
""" """
__slots__ = ('pattern', 'pass_groups', 'pass_groupdict')
def __init__( def __init__(
self, self,
callback: Callable[[Update, 'CallbackContext'], RT], 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 MY_CHAT_MEMBER: ClassVar[int] = -1
""":obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
CHAT_MEMBER: ClassVar[int] = 0 CHAT_MEMBER: ClassVar[int] = 0

View file

@ -99,6 +99,8 @@ class ChosenInlineResultHandler(Handler[Update]):
""" """
__slots__ = ('pattern',)
def __init__( def __init__(
self, self,
callback: Callable[[Update, 'CallbackContext'], RT], 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. run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
""" """
__slots__ = ('command', 'filters', 'pass_args')
def __init__( def __init__(
self, self,
command: SLT[str], 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__( def __init__(
self, self,
prefix: SLT[str], prefix: SLT[str],

View file

@ -45,6 +45,9 @@ CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
class _ConversationTimeoutContext: class _ConversationTimeoutContext:
# '__dict__' is not included since this a private class
__slots__ = ('conversation_key', 'update', 'dispatcher', 'callback_context')
def __init__( def __init__(
self, self,
conversation_key: Tuple[int, ...], 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 END: ClassVar[int] = -1
""":obj:`int`: Used as a constant to return when a conversation is ended.""" """:obj:`int`: Used as a constant to return when a conversation is ended."""
TIMEOUT: ClassVar[int] = -2 TIMEOUT: ClassVar[int] = -2

View file

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

View file

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

View file

@ -26,14 +26,14 @@ from functools import wraps
from queue import Empty, Queue from queue import Empty, Queue
from threading import BoundedSemaphore, Event, Lock, Thread, current_thread from threading import BoundedSemaphore, Event, Lock, Thread, current_thread
from time import sleep 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 uuid import uuid4
from telegram import TelegramError, Update from telegram import TelegramError, Update
from telegram.ext import BasePersistence from telegram.ext import BasePersistence
from telegram.ext.callbackcontext import CallbackContext from telegram.ext.callbackcontext import CallbackContext
from telegram.ext.handler import Handler 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.ext.utils.promise import Promise
from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE 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. state (:obj:`object`, optional): The next state of the conversation.
""" """
__slots__ = ('state',)
def __init__(self, state: object = None) -> None: def __init__(self, state: object = None) -> None:
super().__init__() super().__init__()
self.state = state 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_lock = Lock()
__singleton_semaphore = BoundedSemaphore() __singleton_semaphore = BoundedSemaphore()
__singleton = None __singleton = None
@ -215,6 +241,17 @@ class Dispatcher:
else: else:
self._set_singleton(None) 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 @property
def exception_event(self) -> Event: # skipcq: PY-D0003 def exception_event(self) -> Event: # skipcq: PY-D0003
return self.__exception_event return self.__exception_event

View file

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

View file

@ -17,9 +17,11 @@
# You should have received a copy of the GNU Lesser Public License # You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]. # 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.""" """This module contains the base class for handlers as used by the Dispatcher."""
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic 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 import Update
from telegram.ext.utils.promise import Promise 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__( def __init__(
self, self,
callback: Callable[[UT, 'CallbackContext'], RT], callback: Callable[[UT, 'CallbackContext'], RT],
@ -106,6 +129,17 @@ class Handler(Generic[UT], ABC):
self.pass_chat_data = pass_chat_data self.pass_chat_data = pass_chat_data
self.run_async = run_async 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 @abstractmethod
def check_update(self, update: object) -> Optional[Union[bool, object]]: 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__( def __init__(
self, self,
callback: Callable[[Update, 'CallbackContext'], RT], 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.ext.callbackcontext import CallbackContext
from telegram.utils.types import JSONDict from telegram.utils.types import JSONDict
from telegram.utils.deprecate import set_new_attribute_deprecated
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot from telegram import Bot
@ -49,6 +50,8 @@ class JobQueue:
""" """
__slots__ = ('_dispatcher', 'logger', 'scheduler', '__dict__')
def __init__(self) -> None: def __init__(self) -> None:
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment] self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
self.logger = logging.getLogger(self.__class__.__name__) self.logger = logging.getLogger(self.__class__.__name__)
@ -64,6 +67,9 @@ class JobQueue:
logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter) logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter)
self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR) 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']]: def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]:
if self._dispatcher.use_context: if self._dispatcher.use_context:
return [CallbackContext.from_job(job, self._dispatcher)] 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. 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__( def __init__(
self, self,
callback: Callable[['CallbackContext'], None], callback: Callable[['CallbackContext'], None],
@ -561,6 +578,9 @@ class Job:
self.job = cast(APSJob, job) # skipcq: PTC-W0052 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: def run(self, dispatcher: 'Dispatcher') -> None:
"""Executes the callback function independently of the jobs schedule.""" """Executes the callback function independently of the jobs schedule."""
try: try:

View file

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

View file

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

View file

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

View file

@ -82,6 +82,8 @@ class PollAnswerHandler(Handler[Update]):
""" """
__slots__ = ()
def check_update(self, update: object) -> bool: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """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: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """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: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """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__( def __init__(
self, self,
pattern: Union[str, Pattern], pattern: Union[str, Pattern],

View file

@ -81,6 +81,8 @@ class ShippingQueryHandler(Handler[Update]):
""" """
__slots__ = ()
def check_update(self, update: object) -> bool: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """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__( def __init__(
self, self,
command: str, command: str,

View file

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

View file

@ -75,6 +75,8 @@ class TypeHandler(Handler[UT]):
""" """
__slots__ = ('type', 'strict')
def __init__( def __init__(
self, self,
type: Type[UT], # pylint: disable=W0622 type: Type[UT], # pylint: disable=W0622
@ -90,8 +92,8 @@ class TypeHandler(Handler[UT]):
pass_job_queue=pass_job_queue, pass_job_queue=pass_job_queue,
run_async=run_async, run_async=run_async,
) )
self.type = type self.type = type # pylint: disable=E0237
self.strict = strict self.strict = strict # pylint: disable=E0237
def check_update(self, update: object) -> bool: def check_update(self, update: object) -> bool:
"""Determines whether an update should be passed to this handlers :attr:`callback`. """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 import Bot, TelegramError
from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized
from telegram.ext import Dispatcher, JobQueue 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.helpers import get_signal_name
from telegram.utils.request import Request from telegram.utils.request import Request
from telegram.ext.utils.webhookhandler import WebhookAppClass, WebhookServer 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__( def __init__(
self, self,
@ -150,6 +167,7 @@ class Updater:
raise ValueError('`dispatcher` and `use_context` are mutually exclusive') raise ValueError('`dispatcher` and `use_context` are mutually exclusive')
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self._request = None
if dispatcher is None: if dispatcher is None:
con_pool_size = workers + 4 con_pool_size = workers + 4
@ -219,6 +237,14 @@ class Updater:
self.__lock = Lock() self.__lock = Lock()
self.__threads: List[Thread] = [] 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: def _init_thread(self, target: Callable, name: str, *args: object, **kwargs: object) -> None:
thr = Thread( thr = Thread(
target=self._thread_wrapper, target=self._thread_wrapper,

View file

@ -22,6 +22,7 @@ import logging
from threading import Event from threading import Event
from typing import Callable, List, Optional, Tuple, TypeVar, Union from typing import Callable, List, Optional, Tuple, TypeVar, Union
from telegram.utils.deprecate import set_new_attribute_deprecated
from telegram.utils.types import JSONDict from telegram.utils.types import JSONDict
RT = TypeVar('RT') 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 # TODO: Remove error_handling parameter once we drop the @run_async decorator
def __init__( def __init__(
self, self,
@ -73,6 +87,9 @@ class Promise:
self._result: Optional[RT] = None self._result: Optional[RT] = None
self._exception: Optional[Exception] = 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: def run(self) -> None:
"""Calls the :attr:`pooled_function` callable.""" """Calls the :attr:`pooled_function` callable."""
try: try:

View file

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

View file

@ -26,6 +26,8 @@ import os
from typing import IO, Optional, Tuple, Union from typing import IO, Optional, Tuple, Union
from uuid import uuid4 from uuid import uuid4
from telegram.utils.deprecate import set_new_attribute_deprecated
DEFAULT_MIME_TYPE = 'application/octet-stream' DEFAULT_MIME_TYPE = 'application/octet-stream'
logger = logging.getLogger(__name__) 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): def __init__(self, obj: Union[IO, bytes], filename: str = None, attach: bool = None):
self.filename = None self.filename = None
if isinstance(obj, bytes): if isinstance(obj, bytes):
@ -74,6 +78,9 @@ class InputFile:
if not self.filename: if not self.filename:
self.filename = self.mimetype.replace('/', '.') self.filename = self.mimetype.replace('/', '.')
def __setattr__(self, key: str, value: object) -> None:
set_new_attribute_deprecated(self, key, value)
@property @property
def field_tuple(self) -> Tuple[str, bytes, str]: # skipcq: PY-D0003 def field_tuple(self) -> Tuple[str, bytes, str]: # skipcq: PY-D0003
return self.filename, self.input_file_content, self.mimetype 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 caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None
def to_dict(self) -> JSONDict: 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__( def __init__(
self, self,
media: Union[FileInput, Animation], media: Union[FileInput, Animation],
@ -185,6 +198,8 @@ class InputMediaPhoto(InputMedia):
""" """
__slots__ = ('caption_entities', 'media', 'caption', 'parse_mode', 'type')
def __init__( def __init__(
self, self,
media: Union[FileInput, PhotoSize], 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__( def __init__(
self, self,
media: Union[FileInput, Video], 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__( def __init__(
self, self,
media: Union[FileInput, Audio], 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__( def __init__(
self, self,
media: Union[FileInput, Document], 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__( def __init__(
self, self,
longitude: float, 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__( def __init__(
self, self,
file_id: str, 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__( def __init__(
self, self,
file_id: str, file_id: str,
@ -160,6 +175,16 @@ class StickerSet(TelegramObject):
""" """
__slots__ = (
'is_animated',
'contains_masks',
'thumb',
'title',
'stickers',
'name',
'_id_attrs',
)
def __init__( def __init__(
self, self,
name: str, name: str,
@ -233,6 +258,8 @@ class MaskPosition(TelegramObject):
""" """
__slots__ = ('point', 'scale', 'x_shift', 'y_shift', '_id_attrs')
FOREHEAD: ClassVar[str] = constants.STICKER_FOREHEAD FOREHEAD: ClassVar[str] = constants.STICKER_FOREHEAD
""":const:`telegram.constants.STICKER_FOREHEAD`""" """:const:`telegram.constants.STICKER_FOREHEAD`"""
EYES: ClassVar[str] = constants.STICKER_EYES 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__( def __init__(
self, self,
location: Location, 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__( def __init__(
self, self,
file_id: str, 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__( def __init__(
self, self,
file_id: str, 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__( def __init__(
self, self,
file_id: str, 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): def __init__(self, force_reply: bool = True, selective: bool = False, **_kwargs: Any):
# Required # Required
self.force_reply = bool(force_reply) self.force_reply = bool(force_reply)

View file

@ -23,3 +23,5 @@ from telegram import TelegramObject
class CallbackGame(TelegramObject): class CallbackGame(TelegramObject):
"""A placeholder, currently holds no information. Use BotFather to set up your game.""" """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__( def __init__(
self, self,
title: str, 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): def __init__(self, position: int, user: User, score: int):
self.position = position self.position = position
self.user = user 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__( def __init__(
self, self,
text: str, 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): def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **_kwargs: Any):
# Required # Required
self.inline_keyboard = inline_keyboard 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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): def __init__(self, type: str, id: str, **_kwargs: Any):
# Required # Required
self.type = str(type) 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 id: str, # pylint: disable=W0622

View file

@ -45,6 +45,8 @@ class InlineQueryResultGame(InlineQueryResult):
""" """
__slots__ = ('reply_markup', 'game_short_name')
def __init__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
id: str, # pylint: disable=W0622 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__( def __init__(
self, self,
phone_number: str, 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__( def __init__(
self, self,
title: str, 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 # fmt: on
def __init__( def __init__(

View file

@ -30,3 +30,5 @@ class InputMessageContent(TelegramObject):
:class:`telegram.InputVenueMessageContent` for more details. :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__( def __init__(
self, self,
message_text: str, 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__( def __init__(
self, self,
latitude: float, latitude: float,

View file

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

View file

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

View file

@ -77,8 +77,6 @@ if TYPE_CHECKING:
LabeledPrice, LabeledPrice,
) )
_UNDEFINED = object()
class Message(TelegramObject): class Message(TelegramObject):
# fmt: off # fmt: off
@ -333,8 +331,67 @@ class Message(TelegramObject):
""" """
# fmt: on # fmt: on
__slots__ = (
_effective_attachment = _UNDEFINED '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]] = [ ATTACHMENT_TYPES: ClassVar[List[str]] = [
'audio', 'audio',
@ -497,6 +554,8 @@ class Message(TelegramObject):
self.reply_markup = reply_markup self.reply_markup = reply_markup
self.bot = bot self.bot = bot
self._effective_attachment = DEFAULT_NONE
self._id_attrs = (self.message_id, self.chat) self._id_attrs = (self.message_id, self.chat)
@property @property
@ -613,7 +672,7 @@ class Message(TelegramObject):
:obj:`None` if no attachment was sent. :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 return self._effective_attachment # type: ignore
for i in Message.ATTACHMENT_TYPES: for i in Message.ATTACHMENT_TYPES:
@ -626,10 +685,7 @@ class Message(TelegramObject):
return self._effective_attachment # type: ignore return self._effective_attachment # type: ignore
def __getitem__(self, item: str) -> Any: # pylint: disable=R1710 def __getitem__(self, item: str) -> Any: # pylint: disable=R1710
if item in self.__dict__.keys(): return self.chat.id if item == 'chat_id' else super().__getitem__(item)
return self.__dict__[item]
if item == 'chat_id':
return self.chat.id
def to_dict(self) -> JSONDict: def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`.""" """See :meth:`telegram.TelegramObject.to_dict`."""

View file

@ -44,6 +44,8 @@ class MessageAutoDeleteTimerChanged(TelegramObject):
""" """
__slots__ = ('message_auto_delete_time', '_id_attrs')
def __init__( def __init__(
self, self,
message_auto_delete_time: int, 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__( def __init__(
self, self,
type: str, # pylint: disable=W0622 type: str, # pylint: disable=W0622

View file

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

View file

@ -21,11 +21,14 @@
from typing import ClassVar from typing import ClassVar
from telegram import constants from telegram import constants
from telegram.utils.deprecate import set_new_attribute_deprecated
class ParseMode: class ParseMode:
"""This object represents a Telegram Message Parse Modes.""" """This object represents a Telegram Message Parse Modes."""
__slots__ = ('__dict__',)
MARKDOWN: ClassVar[str] = constants.PARSEMODE_MARKDOWN MARKDOWN: ClassVar[str] = constants.PARSEMODE_MARKDOWN
""":const:`telegram.constants.PARSEMODE_MARKDOWN`\n """:const:`telegram.constants.PARSEMODE_MARKDOWN`\n
@ -37,3 +40,6 @@ class ParseMode:
""":const:`telegram.constants.PARSEMODE_MARKDOWN_V2`""" """:const:`telegram.constants.PARSEMODE_MARKDOWN_V2`"""
HTML: ClassVar[str] = constants.PARSEMODE_HTML HTML: ClassVar[str] = constants.PARSEMODE_HTML
""":const:`telegram.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): class TelegramDecryptionError(TelegramError):
"""Something went wrong with decryption.""" """Something went wrong with decryption."""
__slots__ = ('_msg',)
def __init__(self, message: Union[str, Exception]): def __init__(self, message: Union[str, Exception]):
super().__init__(f"TelegramDecryptionError: {message}") super().__init__(f"TelegramDecryptionError: {message}")
self._msg = str(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): def __init__(self, data: str, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any):
# Required # Required
self.data = data self.data = data
@ -212,6 +224,8 @@ class Credentials(TelegramObject):
nonce (:obj:`str`): Bot-specified nonce nonce (:obj:`str`): Bot-specified nonce
""" """
__slots__ = ('bot', 'nonce', 'secure_data')
def __init__(self, secure_data: 'SecureData', nonce: str, bot: 'Bot' = None, **_kwargs: Any): def __init__(self, secure_data: 'SecureData', nonce: str, bot: 'Bot' = None, **_kwargs: Any):
# Required # Required
self.secure_data = secure_data self.secure_data = secure_data
@ -260,6 +274,21 @@ class SecureData(TelegramObject):
temporary registration. 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__( def __init__(
self, self,
personal_details: 'SecureValue' = None, personal_details: 'SecureValue' = None,
@ -345,6 +374,8 @@ class SecureValue(TelegramObject):
""" """
__slots__ = ('data', 'front_side', 'reverse_side', 'selfie', 'files', 'translation', 'bot')
def __init__( def __init__(
self, self,
data: 'DataCredentials' = None, data: 'DataCredentials' = None,
@ -395,6 +426,8 @@ class SecureValue(TelegramObject):
class _CredentialsBase(TelegramObject): class _CredentialsBase(TelegramObject):
"""Base class for DataCredentials and FileCredentials.""" """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): def __init__(self, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any):
self.hash = hash self.hash = hash
self.secret = secret self.secret = secret
@ -420,6 +453,8 @@ class DataCredentials(_CredentialsBase):
secret (:obj:`str`): Secret of encrypted data secret (:obj:`str`): Secret of encrypted data
""" """
__slots__ = ()
def __init__(self, data_hash: str, secret: str, **_kwargs: Any): def __init__(self, data_hash: str, secret: str, **_kwargs: Any):
super().__init__(data_hash, secret, **_kwargs) super().__init__(data_hash, secret, **_kwargs)
@ -447,6 +482,8 @@ class FileCredentials(_CredentialsBase):
secret (:obj:`str`): Secret of encrypted file secret (:obj:`str`): Secret of encrypted file
""" """
__slots__ = ()
def __init__(self, file_hash: str, secret: str, **_kwargs: Any): def __init__(self, file_hash: str, secret: str, **_kwargs: Any):
super().__init__(file_hash, secret, **_kwargs) super().__init__(file_hash, secret, **_kwargs)

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