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/].
"""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 ._botcommand import BotCommand
from ._user import User
@ -160,144 +307,3 @@ from ._botcommandscope import (
)
from ._bot import Bot
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/].
# pylint: disable=missing-module-docstring
__version__ = '13.11'
from telegram import constants
__version__ = '13.11'
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
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__ = [
'BOT_API_VERSION',
@ -66,6 +63,9 @@ __all__ = [
'UpdateType',
]
from enum import Enum, IntEnum
from typing import List
class _StringEnum(str, Enum):
"""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
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an classes that represent Telegram errors."""
__all__ = (
'BadRequest',
'ChatMigrated',
'Conflict',
'InvalidToken',
'NetworkError',
'PassportDecryptionError',
'RetryAfter',
'TelegramError',
'TimedOut',
)
from typing import Tuple, Union

View file

@ -18,36 +18,6 @@
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""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__ = (
'BasePersistence',
'CallbackContext',
@ -85,3 +55,33 @@ __all__ = (
'Updater',
'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 re

View file

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

View file

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

View file

@ -21,6 +21,8 @@
.. versionadded:: 14.0
"""
__all__ = ['PTBDeprecationWarning', 'PTBRuntimeWarning', 'PTBUserWarning']
class PTBUserWarning(UserWarning):
"""
@ -42,7 +44,7 @@ class PTBRuntimeWarning(PTBUserWarning, RuntimeWarning):
__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
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}"
for attr in cls.__slots__:
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):
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
# along with this program. If not, see [http://www.gnu.org/licenses/].
import importlib
import importlib.util
import os
from glob import iglob
from pathlib import Path
import inspect
@ -31,18 +30,13 @@ included = { # These modules/classes intentionally have __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:
# windows uses backslashes:
if os.name == 'nt':
split_path = path.split('\\')
else:
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.
if '__' in str(path): # Exclude __init__, __main__, etc
continue
mod_name = str(path)[:-3].replace(os.sep, '.')
module = importlib.import_module(mod_name) # import module to get classes in it.
for name, cls in inspect.getmembers(module, inspect.isclass):
if cls.__module__ != module.__name__ or any( # exclude 'imported' modules