Use __all__ Consistently (#2805)

This commit is contained in:
Harshil 2021-12-05 12:42:14 +04:00 committed by Hinrich Mahler
parent de85eec674
commit 89d5310504
12 changed files with 330 additions and 197 deletions

View file

@ -18,6 +18,153 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""A library that provides a Python interface to the Telegram Bot API""" """A library that provides a Python interface to the Telegram Bot API"""
__author__ = 'devs@python-telegram-bot.org'
__all__ = ( # Keep this alphabetically ordered
'Animation',
'Audio',
'Bot',
'bot_api_version',
'BotCommand',
'BotCommandScope',
'BotCommandScopeAllChatAdministrators',
'BotCommandScopeAllGroupChats',
'BotCommandScopeAllPrivateChats',
'BotCommandScopeChat',
'BotCommandScopeChatAdministrators',
'BotCommandScopeChatMember',
'BotCommandScopeDefault',
'CallbackGame',
'CallbackQuery',
'Chat',
'ChatInviteLink',
'ChatJoinRequest',
'ChatLocation',
'ChatMember',
'ChatMemberOwner',
'ChatMemberAdministrator',
'ChatMemberMember',
'ChatMemberRestricted',
'ChatMemberLeft',
'ChatMemberBanned',
'ChatMemberUpdated',
'ChatPermissions',
'ChatPhoto',
'ChosenInlineResult',
'constants',
'Contact',
'Credentials',
'DataCredentials',
'Dice',
'Document',
'EncryptedCredentials',
'EncryptedPassportElement',
'error',
'File',
'FileCredentials',
'ForceReply',
'Game',
'GameHighScore',
'helpers',
'IdDocumentData',
'InlineKeyboardButton',
'InlineKeyboardMarkup',
'InlineQuery',
'InlineQueryResult',
'InlineQueryResultArticle',
'InlineQueryResultAudio',
'InlineQueryResultCachedAudio',
'InlineQueryResultCachedDocument',
'InlineQueryResultCachedGif',
'InlineQueryResultCachedMpeg4Gif',
'InlineQueryResultCachedPhoto',
'InlineQueryResultCachedSticker',
'InlineQueryResultCachedVideo',
'InlineQueryResultCachedVoice',
'InlineQueryResultContact',
'InlineQueryResultDocument',
'InlineQueryResultGame',
'InlineQueryResultGif',
'InlineQueryResultLocation',
'InlineQueryResultMpeg4Gif',
'InlineQueryResultPhoto',
'InlineQueryResultVenue',
'InlineQueryResultVideo',
'InlineQueryResultVoice',
'InputContactMessageContent',
'InputFile',
'InputInvoiceMessageContent',
'InputLocationMessageContent',
'InputMedia',
'InputMediaAnimation',
'InputMediaAudio',
'InputMediaDocument',
'InputMediaPhoto',
'InputMediaVideo',
'InputMessageContent',
'InputTextMessageContent',
'InputVenueMessageContent',
'Invoice',
'KeyboardButton',
'KeyboardButtonPollType',
'LabeledPrice',
'Location',
'LoginUrl',
'MaskPosition',
'Message',
'MessageAutoDeleteTimerChanged',
'MessageEntity',
'MessageId',
'OrderInfo',
'PassportData',
'PassportElementError',
'PassportElementErrorDataField',
'PassportElementErrorFile',
'PassportElementErrorFiles',
'PassportElementErrorFrontSide',
'PassportElementErrorReverseSide',
'PassportElementErrorSelfie',
'PassportElementErrorTranslationFile',
'PassportElementErrorTranslationFiles',
'PassportElementErrorUnspecified',
'PassportFile',
'PersonalDetails',
'PhotoSize',
'Poll',
'PollAnswer',
'PollOption',
'PreCheckoutQuery',
'ProximityAlertTriggered',
'ReplyKeyboardMarkup',
'ReplyKeyboardRemove',
'ReplyMarkup',
'request',
'ResidentialAddress',
'SecureData',
'SecureValue',
'ShippingAddress',
'ShippingOption',
'ShippingQuery',
'Sticker',
'StickerSet',
'SuccessfulPayment',
'TelegramObject',
'Update',
'User',
'UserProfilePhotos',
'Venue',
'Video',
'VideoNote',
'Voice',
'VoiceChatStarted',
'VoiceChatEnded',
'VoiceChatScheduled',
'VoiceChatParticipantsInvited',
'warnings',
'WebhookInfo',
)
from ._telegramobject import TelegramObject from ._telegramobject import TelegramObject
from ._botcommand import BotCommand from ._botcommand import BotCommand
from ._user import User from ._user import User
@ -160,144 +307,3 @@ from ._botcommandscope import (
) )
from ._bot import Bot from ._bot import Bot
from ._version import __version__, bot_api_version # noqa: F401 from ._version import __version__, bot_api_version # noqa: F401
__author__ = 'devs@python-telegram-bot.org'
__all__ = ( # Keep this alphabetically ordered
'Animation',
'Audio',
'Bot',
'bot_api_version',
'BotCommand',
'BotCommandScope',
'BotCommandScopeAllChatAdministrators',
'BotCommandScopeAllGroupChats',
'BotCommandScopeAllPrivateChats',
'BotCommandScopeChat',
'BotCommandScopeChatAdministrators',
'BotCommandScopeChatMember',
'BotCommandScopeDefault',
'CallbackGame',
'CallbackQuery',
'Chat',
'ChatInviteLink',
'ChatJoinRequest',
'ChatLocation',
'ChatMember',
'ChatMemberOwner',
'ChatMemberAdministrator',
'ChatMemberMember',
'ChatMemberRestricted',
'ChatMemberLeft',
'ChatMemberBanned',
'ChatMemberUpdated',
'ChatPermissions',
'ChatPhoto',
'ChosenInlineResult',
'Contact',
'Credentials',
'DataCredentials',
'Dice',
'Document',
'EncryptedCredentials',
'EncryptedPassportElement',
'File',
'FileCredentials',
'ForceReply',
'Game',
'GameHighScore',
'IdDocumentData',
'InlineKeyboardButton',
'InlineKeyboardMarkup',
'InlineQuery',
'InlineQueryResult',
'InlineQueryResultArticle',
'InlineQueryResultAudio',
'InlineQueryResultCachedAudio',
'InlineQueryResultCachedDocument',
'InlineQueryResultCachedGif',
'InlineQueryResultCachedMpeg4Gif',
'InlineQueryResultCachedPhoto',
'InlineQueryResultCachedSticker',
'InlineQueryResultCachedVideo',
'InlineQueryResultCachedVoice',
'InlineQueryResultContact',
'InlineQueryResultDocument',
'InlineQueryResultGame',
'InlineQueryResultGif',
'InlineQueryResultLocation',
'InlineQueryResultMpeg4Gif',
'InlineQueryResultPhoto',
'InlineQueryResultVenue',
'InlineQueryResultVideo',
'InlineQueryResultVoice',
'InputContactMessageContent',
'InputFile',
'InputInvoiceMessageContent',
'InputLocationMessageContent',
'InputMedia',
'InputMediaAnimation',
'InputMediaAudio',
'InputMediaDocument',
'InputMediaPhoto',
'InputMediaVideo',
'InputMessageContent',
'InputTextMessageContent',
'InputVenueMessageContent',
'Invoice',
'KeyboardButton',
'KeyboardButtonPollType',
'LabeledPrice',
'Location',
'LoginUrl',
'MaskPosition',
'Message',
'MessageAutoDeleteTimerChanged',
'MessageEntity',
'MessageId',
'OrderInfo',
'PassportData',
'PassportElementError',
'PassportElementErrorDataField',
'PassportElementErrorFile',
'PassportElementErrorFiles',
'PassportElementErrorFrontSide',
'PassportElementErrorReverseSide',
'PassportElementErrorSelfie',
'PassportElementErrorTranslationFile',
'PassportElementErrorTranslationFiles',
'PassportElementErrorUnspecified',
'PassportFile',
'PersonalDetails',
'PhotoSize',
'Poll',
'PollAnswer',
'PollOption',
'PreCheckoutQuery',
'ProximityAlertTriggered',
'ReplyKeyboardMarkup',
'ReplyKeyboardRemove',
'ReplyMarkup',
'ResidentialAddress',
'SecureData',
'SecureValue',
'ShippingAddress',
'ShippingOption',
'ShippingQuery',
'Sticker',
'StickerSet',
'SuccessfulPayment',
'TelegramObject',
'Update',
'User',
'UserProfilePhotos',
'Venue',
'Video',
'VideoNote',
'Voice',
'VoiceChatStarted',
'VoiceChatEnded',
'VoiceChatScheduled',
'VoiceChatParticipantsInvited',
'WebhookInfo',
)

View file

@ -18,7 +18,8 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
# pylint: disable=missing-module-docstring # pylint: disable=missing-module-docstring
__version__ = '13.11'
from telegram import constants from telegram import constants
__version__ = '13.11'
bot_api_version = constants.BOT_API_VERSION # pylint: disable=invalid-name bot_api_version = constants.BOT_API_VERSION # pylint: disable=invalid-name

View file

@ -33,9 +33,6 @@ Attributes:
The following constants are related to specific classes or topics and are grouped into enums. If The following constants are related to specific classes or topics and are grouped into enums. If
they are related to a specific class, then they are also available as attributes of those classes. they are related to a specific class, then they are also available as attributes of those classes.
""" """
from enum import Enum, IntEnum
from typing import List
__all__ = [ __all__ = [
'BOT_API_VERSION', 'BOT_API_VERSION',
@ -66,6 +63,9 @@ __all__ = [
'UpdateType', 'UpdateType',
] ]
from enum import Enum, IntEnum
from typing import List
class _StringEnum(str, Enum): class _StringEnum(str, Enum):
"""Helper class for string enums where the value is not important to be displayed on """Helper class for string enums where the value is not important to be displayed on

View file

@ -17,6 +17,19 @@
# 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 an classes that represent Telegram errors.""" """This module contains an classes that represent Telegram errors."""
__all__ = (
'BadRequest',
'ChatMigrated',
'Conflict',
'InvalidToken',
'NetworkError',
'PassportDecryptionError',
'RetryAfter',
'TelegramError',
'TimedOut',
)
from typing import Tuple, Union from typing import Tuple, Union

View file

@ -18,36 +18,6 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""Extensions over the Telegram Bot API to facilitate bot making""" """Extensions over the Telegram Bot API to facilitate bot making"""
from ._extbot import ExtBot
from ._basepersistence import BasePersistence, PersistenceInput
from ._picklepersistence import PicklePersistence
from ._dictpersistence import DictPersistence
from ._handler import Handler
from ._callbackcontext import CallbackContext
from ._contexttypes import ContextTypes
from ._dispatcher import Dispatcher, DispatcherHandlerStop
from ._jobqueue import JobQueue, Job
from ._updater import Updater
from ._callbackqueryhandler import CallbackQueryHandler
from ._choseninlineresulthandler import ChosenInlineResultHandler
from ._inlinequeryhandler import InlineQueryHandler
from . import filters
from ._messagehandler import MessageHandler
from ._commandhandler import CommandHandler, PrefixHandler
from ._stringcommandhandler import StringCommandHandler
from ._stringregexhandler import StringRegexHandler
from ._typehandler import TypeHandler
from ._conversationhandler import ConversationHandler
from ._precheckoutqueryhandler import PreCheckoutQueryHandler
from ._shippingqueryhandler import ShippingQueryHandler
from ._pollanswerhandler import PollAnswerHandler
from ._pollhandler import PollHandler
from ._chatmemberhandler import ChatMemberHandler
from ._chatjoinrequesthandler import ChatJoinRequestHandler
from ._defaults import Defaults
from ._callbackdatacache import CallbackDataCache, InvalidCallbackData
from ._builders import DispatcherBuilder, UpdaterBuilder
__all__ = ( __all__ = (
'BasePersistence', 'BasePersistence',
'CallbackContext', 'CallbackContext',
@ -85,3 +55,33 @@ __all__ = (
'Updater', 'Updater',
'UpdaterBuilder', 'UpdaterBuilder',
) )
from ._extbot import ExtBot
from ._basepersistence import BasePersistence, PersistenceInput
from ._picklepersistence import PicklePersistence
from ._dictpersistence import DictPersistence
from ._handler import Handler
from ._callbackcontext import CallbackContext
from ._contexttypes import ContextTypes
from ._dispatcher import Dispatcher, DispatcherHandlerStop
from ._jobqueue import JobQueue, Job
from ._updater import Updater
from ._callbackqueryhandler import CallbackQueryHandler
from ._choseninlineresulthandler import ChosenInlineResultHandler
from ._inlinequeryhandler import InlineQueryHandler
from . import filters
from ._messagehandler import MessageHandler
from ._commandhandler import CommandHandler, PrefixHandler
from ._stringcommandhandler import StringCommandHandler
from ._stringregexhandler import StringRegexHandler
from ._typehandler import TypeHandler
from ._conversationhandler import ConversationHandler
from ._precheckoutqueryhandler import PreCheckoutQueryHandler
from ._shippingqueryhandler import ShippingQueryHandler
from ._pollanswerhandler import PollAnswerHandler
from ._pollhandler import PollHandler
from ._chatmemberhandler import ChatMemberHandler
from ._chatjoinrequesthandler import ChatJoinRequestHandler
from ._defaults import Defaults
from ._callbackdatacache import CallbackDataCache, InvalidCallbackData
from ._builders import DispatcherBuilder, UpdaterBuilder

View file

@ -36,6 +36,58 @@ This module contains filters for use with :class:`telegram.ext.MessageHandler`,
""" """
__all__ = (
'ALL',
'ANIMATION',
'ATTACHMENT',
'AUDIO',
'BaseFilter',
'CAPTION',
'CHAT',
'COMMAND',
'CONTACT',
'Caption',
'CaptionEntity',
'CaptionRegex',
'Chat',
'ChatType',
'Command',
'DOCUMENT',
'Dice',
'Document',
'Entity',
'FORWARDED',
'ForwardedFrom',
'GAME',
'HAS_PROTECTED_CONTENT',
'INVOICE',
'IS_AUTOMATIC_FORWARD',
'LOCATION',
'Language',
'MessageFilter',
'PASSPORT_DATA',
'PHOTO',
'POLL',
'REPLY',
'Regex',
'STICKER',
'SUCCESSFUL_PAYMENT',
'SenderChat',
'StatusUpdate',
'TEXT',
'Text',
'USER',
'UpdateFilter',
'UpdateType',
'User',
'VENUE',
'VIA_BOT',
'VIDEO',
'VIDEO_NOTE',
'VOICE',
'ViaBot',
)
import mimetypes import mimetypes
import re import re

View file

@ -23,6 +23,14 @@
module ``telegram.utils.helpers``. module ``telegram.utils.helpers``.
""" """
__all__ = (
'create_deep_linked_url',
'effective_message_type',
'escape_markdown',
'mention_html',
'mention_markdown',
)
import re import re
from html import escape from html import escape

View file

@ -19,6 +19,9 @@
"""This module contains the Request class which handles the communication with the Telegram """This module contains the Request class which handles the communication with the Telegram
servers. servers.
""" """
__all__ = ('Request',)
import logging import logging
import os import os
import socket import socket

View file

@ -21,6 +21,8 @@
.. versionadded:: 14.0 .. versionadded:: 14.0
""" """
__all__ = ['PTBDeprecationWarning', 'PTBRuntimeWarning', 'PTBUserWarning']
class PTBUserWarning(UserWarning): class PTBUserWarning(UserWarning):
""" """
@ -42,7 +44,7 @@ class PTBRuntimeWarning(PTBUserWarning, RuntimeWarning):
__slots__ = () __slots__ = ()
# https://www.python.org/dev/peps/pep-0565/ recommends to use a custom warning class derived from # https://www.python.org/dev/peps/pep-0565/ recommends using a custom warning class derived from
# DeprecationWarning. We also subclass from TGUserWarning so users can easily 'switch off' warnings # DeprecationWarning. We also subclass from TGUserWarning so users can easily 'switch off' warnings
class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning): class PTBDeprecationWarning(PTBUserWarning, DeprecationWarning):
""" """

View file

@ -112,18 +112,9 @@ class TestFilters:
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), f"same slot in {name}" assert len(mro_slots(inst)) == len(set(mro_slots(inst))), f"same slot in {name}"
assert len(mro_slots(inst)) == len(set(mro_slots(inst))), f"same slot in {name}"
for attr in cls.__slots__: for attr in cls.__slots__:
assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}' for {name}" assert getattr(inst, attr, 'err') != 'err', f"got extra slot '{attr}' for {name}"
class CustomFilter(filters.MessageFilter):
def filter(self, message: Message):
pass
with pytest.warns(None):
CustomFilter().custom = 'allowed' # Test setting custom attr to custom filters
def test_filters_all(self, update): def test_filters_all(self, update):
assert filters.ALL.check_update(update) assert filters.ALL.check_update(update)

63
tests/test_modules.py Normal file
View file

@ -0,0 +1,63 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2021
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This tests whether our submodules have __all__ or not.
Additionally also tests if all public submodules are included in __all__ for __init__'s.
"""
import importlib
import os
from pathlib import Path
def test_public_submodules_dunder_all():
modules_to_search = list(Path('telegram').rglob('*.py'))
for mod_path in modules_to_search:
path = str(mod_path)
folder = mod_path.parent
if 'vendor' in path: # skip anything vendor related
continue
if mod_path.name == '__init__.py' and '_' not in path[:-11]: # init of public submodules
mod = load_module(mod_path)
assert hasattr(mod, '__all__'), f"{folder}'s __init__ does not have an __all__!"
pub_mods = get_public_submodules_in_folder(folder)
cond = all(pub_mod in mod.__all__ for pub_mod in pub_mods)
assert cond, f"{path}'s __all__ should contain all public submodules ({pub_mods})!"
continue
if '_' in path: # skip private modules
continue
mod = load_module(mod_path)
assert hasattr(mod, '__all__'), f"{mod_path.name} does not have an __all__!"
def load_module(path: Path):
if path.name == "__init__.py":
mod_name = str(path.parent).replace(os.sep, '.') # telegram(.ext) format
else:
mod_name = f"{path.parent}.{path.stem}".replace(os.sep, '.') # telegram(.ext).(...) format
return importlib.import_module(mod_name)
def get_public_submodules_in_folder(path: Path):
return [i.stem for i in path.glob('[!_]*.py')]

View file

@ -17,9 +17,8 @@
# 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/].
import importlib import importlib
import importlib.util
import os import os
from glob import iglob from pathlib import Path
import inspect import inspect
@ -31,18 +30,13 @@ included = { # These modules/classes intentionally have __dict__.
def test_class_has_slots_and_no_dict(): def test_class_has_slots_and_no_dict():
tg_paths = [p for p in iglob("telegram/**/*.py", recursive=True) if 'vendor' not in p] tg_paths = [p for p in Path('telegram').rglob("*.py") if 'vendor' not in str(p)]
for path in tg_paths: for path in tg_paths:
# windows uses backslashes: if '__' in str(path): # Exclude __init__, __main__, etc
if os.name == 'nt': continue
split_path = path.split('\\') mod_name = str(path)[:-3].replace(os.sep, '.')
else: module = importlib.import_module(mod_name) # import module to get classes in it.
split_path = path.split('/')
mod_name = f"telegram{'.ext.' if split_path[1] == 'ext' else '.'}{split_path[-1][:-3]}"
spec = importlib.util.spec_from_file_location(mod_name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # Exec module to get classes in it.
for name, cls in inspect.getmembers(module, inspect.isclass): for name, cls in inspect.getmembers(module, inspect.isclass):
if cls.__module__ != module.__name__ or any( # exclude 'imported' modules if cls.__module__ != module.__name__ or any( # exclude 'imported' modules