From 1cf63c26c59c3db2c938bffe26898216283b60af Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Fri, 9 Feb 2024 12:12:13 -0500 Subject: [PATCH 01/17] Refactor and Overhaul `test_official` (#4087) --- .github/workflows/test_official.yml | 2 +- pyproject.toml | 2 + telegram/_bot.py | 12 +- telegram/ext/_extbot.py | 10 +- tests/README.rst | 11 + tests/conftest.py | 2 +- tests/test_official.py | 597 ------------------------ tests/test_official/__init__.py | 0 tests/test_official/arg_type_checker.py | 225 +++++++++ tests/test_official/exceptions.py | 187 ++++++++ tests/test_official/helpers.py | 111 +++++ tests/test_official/scraper.py | 136 ++++++ tests/test_official/test_official.py | 193 ++++++++ 13 files changed, 878 insertions(+), 610 deletions(-) delete mode 100644 tests/test_official.py create mode 100644 tests/test_official/__init__.py create mode 100644 tests/test_official/arg_type_checker.py create mode 100644 tests/test_official/exceptions.py create mode 100644 tests/test_official/helpers.py create mode 100644 tests/test_official/scraper.py create mode 100644 tests/test_official/test_official.py diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index 430f6356111..9b972694616 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -33,7 +33,7 @@ jobs: python -W ignore -m pip install -r requirements-dev.txt - name: Compare to official api run: | - pytest -v tests/test_official.py --junit-xml=.test_report_official.xml + pytest -v tests/test_official/test_official.py --junit-xml=.test_report_official.xml exit $? env: TEST_OFFICIAL: "true" diff --git a/pyproject.toml b/pyproject.toml index d796a6a9af6..233af8fecb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,8 @@ markers = [ "req", ] asyncio_mode = "auto" +log_format = "%(funcName)s - Line %(lineno)d - %(message)s" +# log_level = "DEBUG" # uncomment to see DEBUG logs # MYPY: [tool.mypy] diff --git a/telegram/_bot.py b/telegram/_bot.py index 280e47d1282..48165bd9a5f 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -6138,8 +6138,8 @@ async def get_custom_emoji_stickers( async def upload_sticker_file( self, user_id: int, - sticker: Optional[FileInput], - sticker_format: Optional[str], + sticker: FileInput, + sticker_format: str, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -6180,7 +6180,7 @@ async def upload_sticker_file( """ data: JSONDict = { "user_id": user_id, - "sticker": self._parse_file_input(sticker), # type: ignore[arg-type] + "sticker": self._parse_file_input(sticker), "sticker_format": sticker_format, } result = await self._post( @@ -6199,7 +6199,7 @@ async def add_sticker_to_set( self, user_id: int, name: str, - sticker: Optional["InputSticker"], + sticker: "InputSticker", *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -6298,8 +6298,8 @@ async def create_new_sticker_set( user_id: int, name: str, title: str, - stickers: Optional[Sequence["InputSticker"]], - sticker_format: Optional[str], + stickers: Sequence["InputSticker"], + sticker_format: str, sticker_type: Optional[str] = None, needs_repainting: Optional[bool] = None, *, diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index a92ea2fab6d..1b6e4fcdc73 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -862,7 +862,7 @@ async def add_sticker_to_set( self, user_id: int, name: str, - sticker: Optional["InputSticker"], + sticker: "InputSticker", *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1177,8 +1177,8 @@ async def create_new_sticker_set( user_id: int, name: str, title: str, - stickers: Optional[Sequence["InputSticker"]], - sticker_format: Optional[str], + stickers: Sequence["InputSticker"], + sticker_format: str, sticker_type: Optional[str] = None, needs_repainting: Optional[bool] = None, *, @@ -3673,8 +3673,8 @@ async def unpin_all_general_forum_topic_messages( async def upload_sticker_file( self, user_id: int, - sticker: Optional[FileInput], - sticker_format: Optional[str], + sticker: FileInput, + sticker_format: str, *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/tests/README.rst b/tests/README.rst index d15d745a297..753dd6a16ca 100644 --- a/tests/README.rst +++ b/tests/README.rst @@ -82,6 +82,17 @@ Use as follows: $ pytest -m dev +Debugging tests +=============== + +Writing tests can be challenging, and fixing failing tests can be even more so. To help with this, +PTB has started to adopt the use of ``logging`` in the test suite. You can insert debug logging +statements in your tests to help you understand what's going on. To enable these logs, you can set +``log_level = DEBUG`` in ``setup.cfg`` or use the ``--log-level=INFO`` flag when running the tests. +If a test is large and complicated, it is recommended to leave the debug logs for others to use as +well. + + Bots used in tests ================== diff --git a/tests/conftest.py b/tests/conftest.py index ce940bdebb8..689d816bb49 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -57,7 +57,7 @@ if sys.version_info < (3, 10): if RUN_TEST_OFFICIAL: logging.warning("Skipping test_official.py since it requires Python 3.10+") - collect_ignore.append("test_official.py") + collect_ignore_glob = ["test_official/*.py"] # This is here instead of in setup.cfg due to https://github.com/pytest-dev/pytest/issues/8343 diff --git a/tests/test_official.py b/tests/test_official.py deleted file mode 100644 index 8aaca8a6980..00000000000 --- a/tests/test_official.py +++ /dev/null @@ -1,597 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 -# Leandro Toledo de Souza -# -# 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/]. -import inspect -import re -from datetime import datetime -from types import FunctionType -from typing import Any, Callable, ForwardRef, Sequence, get_args, get_origin - -import httpx -import pytest -from bs4 import BeautifulSoup, PageElement, Tag - -import telegram -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.types import FileInput, ODVInput -from telegram.ext import Defaults -from tests.auxil.envvars import RUN_TEST_OFFICIAL - -IGNORED_OBJECTS = ("ResponseParameters", "CallbackGame") -GLOBALLY_IGNORED_PARAMETERS = { - "self", - "read_timeout", - "write_timeout", - "connect_timeout", - "pool_timeout", - "bot", - "api_kwargs", -} - -# Types for certain parameters accepted by PTB but not in the official API -ADDITIONAL_TYPES = { - "photo": ForwardRef("PhotoSize"), - "video": ForwardRef("Video"), - "video_note": ForwardRef("VideoNote"), - "audio": ForwardRef("Audio"), - "document": ForwardRef("Document"), - "animation": ForwardRef("Animation"), - "voice": ForwardRef("Voice"), - "sticker": ForwardRef("Sticker"), -} - -# Exceptions to the "Array of" types, where we accept more types than the official API -# key: parameter name, value: type which must be present in the annotation -ARRAY_OF_EXCEPTIONS = { - "results": "InlineQueryResult", # + Callable - "commands": "BotCommand", # + tuple[str, str] - "keyboard": "KeyboardButton", # + sequence[sequence[str]] - "reaction": "ReactionType", # + str - # TODO: Deprecated and will be corrected (and removed) in next major PTB version: - "file_hashes": "list[str]", -} - -# Special cases for other parameters that accept more types than the official API, and are -# too complex to compare/predict with official API: -COMPLEX_TYPES = { # (param_name, is_class (i.e appears in a class?)): reduced form of annotation - ("correct_option_id", False): int, # actual: Literal - ("file_id", False): str, # actual: Union[str, objs_with_file_id_attr] - ("invite_link", False): str, # actual: Union[str, ChatInviteLink] - ("provider_data", False): str, # actual: Union[str, obj] - ("callback_data", True): str, # actual: Union[str, obj] - ("media", True): str, # actual: Union[str, InputMedia*, FileInput] - ("data", True): str, # actual: Union[IdDocumentData, PersonalDetails, ResidentialAddress] -} - -# These are param names ignored in the param type checking in classes for the `tg.Defaults` case. -IGNORED_DEFAULTS_PARAM_NAMES = { - "quote", - "link_preview_options", -} - -# These classes' params are all ODVInput, so we ignore them in the defaults type checking. -IGNORED_DEFAULTS_CLASSES = {"LinkPreviewOptions"} - - -def _get_params_base(object_name: str, search_dict: dict[str, set[Any]]) -> set[Any]: - """Helper function for the *_params functions below. - Given an object name and a search dict, goes through the keys of the search dict and checks if - the object name matches any of the regexes (keys). The union of all the sets (values) of the - matching regexes is returned. `object_name` may be a CamelCase or snake_case name. - """ - out = set() - for regex, params in search_dict.items(): - if re.fullmatch(regex, object_name): - out.update(params) - # also check the snake_case version - snake_case_name = re.sub(r"(? set[str]: - return _get_params_base(object_name, PTB_EXTRA_PARAMS) - - -# Arguments *removed* from the official API -# Mostly due to the value being fixed anyway -PTB_IGNORED_PARAMS = { - r"InlineQueryResult\w+": {"type"}, - r"ChatMember\w+": {"status"}, - r"PassportElementError\w+": {"source"}, - "ForceReply": {"force_reply"}, - "ReplyKeyboardRemove": {"remove_keyboard"}, - r"BotCommandScope\w+": {"type"}, - r"MenuButton\w+": {"type"}, - r"InputMedia\w+": {"type"}, - "InaccessibleMessage": {"date"}, - r"MessageOrigin\w+": {"type"}, - r"ChatBoostSource\w+": {"source"}, - r"ReactionType\w+": {"type"}, -} - - -def ptb_ignored_params(object_name: str) -> set[str]: - return _get_params_base(object_name, PTB_IGNORED_PARAMS) - - -IGNORED_PARAM_REQUIREMENTS = { - # Ignore these since there's convenience params in them (eg. Venue) - # <---- - "send_location": {"latitude", "longitude"}, - "edit_message_live_location": {"latitude", "longitude"}, - "send_venue": {"latitude", "longitude", "title", "address"}, - "send_contact": {"phone_number", "first_name"}, - # ----> -} - - -def ignored_param_requirements(object_name: str) -> set[str]: - return _get_params_base(object_name, IGNORED_PARAM_REQUIREMENTS) - - -# Arguments that are optional arguments for now for backwards compatibility -BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { - # Deprecated by Bot API 7.0, kept for now for bw compat: - "KeyboardButton": {"request_user"}, - "Message": { - "forward_from", - "forward_signature", - "forward_sender_name", - "forward_date", - "forward_from_chat", - "forward_from_message_id", - "user_shared", - }, - "(send_message|edit_message_text)": { - "disable_web_page_preview", - "reply_to_message_id", - "allow_sending_without_reply", - }, - r"copy_message|send_\w+": {"allow_sending_without_reply", "reply_to_message_id"}, -} - - -def backwards_compat_kwargs(object_name: str) -> set[str]: - return _get_params_base(object_name, BACKWARDS_COMPAT_KWARGS) - - -IGNORED_PARAM_REQUIREMENTS.update(BACKWARDS_COMPAT_KWARGS) - - -def find_next_sibling_until(tag: Tag, name: str, until: Tag) -> PageElement | None: - for sibling in tag.next_siblings: - if sibling is until: - return None - if sibling.name == name: - return sibling - return None - - -def parse_table(h4: Tag) -> list[list[str]]: - """Parses the Telegram doc table and has an output of a 2D list.""" - table = find_next_sibling_until(h4, "table", h4.find_next_sibling("h4")) - if not table: - return [] - return [[td.text for td in tr.find_all("td")] for tr in table.find_all("tr")[1:]] - - -def check_method(h4: Tag) -> None: - name = h4.text # name of the method in telegram's docs. - method: FunctionType | None = getattr(telegram.Bot, name, None) # Retrieve our lib method - if not method: - raise AssertionError(f"Method {name} not found in telegram.Bot") - - table = parse_table(h4) - - # Check arguments based on source - sig = inspect.signature(method, follow_wrapped=True) - checked = [] - for tg_parameter in table: # Iterates through each row in the table - # Check if parameter is present in our method - param = sig.parameters.get( - tg_parameter[0] # parameter[0] is first element (the param name) - ) - if param is None: - raise AssertionError(f"Parameter {tg_parameter[0]} not found in {method.__name__}") - - # Check if type annotation is present and correct - if param.annotation is inspect.Parameter.empty: - raise AssertionError( - f"Param {param.name!r} of {method.__name__!r} should have a type annotation" - ) - if not check_param_type(param, tg_parameter, method): - raise AssertionError( - f"Param {param.name!r} of {method.__name__!r} should be {tg_parameter[1]} or " - "something else!" - ) - - # Now check if the parameter is required or not - if not check_required_param(tg_parameter, param, method.__name__): - raise AssertionError( - f"Param {param.name!r} of method {method.__name__!r} requirement mismatch!" - ) - - # Now we will check that we don't pass default values if the parameter is not required. - if param.default is not inspect.Parameter.empty: # If there is a default argument... - default_arg_none = check_defaults_type(param) # check if it's None - if not default_arg_none: - raise AssertionError(f"Param {param.name!r} of {method.__name__!r} should be None") - checked.append(tg_parameter[0]) - - expected_additional_args = GLOBALLY_IGNORED_PARAMETERS.copy() - expected_additional_args |= ptb_extra_params(name) - expected_additional_args |= backwards_compat_kwargs(name) - - unexpected_args = (sig.parameters.keys() ^ checked) - expected_additional_args - if unexpected_args != set(): - raise AssertionError( - f"In {method.__qualname__}, unexpected args were found: {unexpected_args}." - ) - - kw_or_positional_args = [ - p.name for p in sig.parameters.values() if p.kind != inspect.Parameter.KEYWORD_ONLY - ] - non_kw_only_args = set(kw_or_positional_args).difference(checked).difference(["self"]) - non_kw_only_args -= backwards_compat_kwargs(name) - if non_kw_only_args != set(): - raise AssertionError( - f"In {method.__qualname__}, extra args should be keyword only " - f"(compared to {name} in API)" - ) - - -def check_object(h4: Tag) -> None: - name = h4.text - obj = getattr(telegram, name) - table = parse_table(h4) - - # Check arguments based on source. Makes sure to only check __init__'s signature & nothing else - sig = inspect.signature(obj.__init__, follow_wrapped=True) - - checked = set() - fields_removed_by_ptb = ptb_ignored_params(name) - for tg_parameter in table: - field: str = tg_parameter[0] # From telegram docs - - if field in fields_removed_by_ptb: - continue - - if field == "from": - field = "from_user" - - param = sig.parameters.get(field) - if param is None: - raise AssertionError(f"Attribute {field} not found in {obj.__name__}") - # Check if type annotation is present and correct - if param.annotation is inspect.Parameter.empty: - raise AssertionError( - f"Param {param.name!r} of {obj.__name__!r} should have a type annotation" - ) - if not check_param_type(param, tg_parameter, obj): - raise AssertionError( - f"Param {param.name!r} of {obj.__name__!r} should be {tg_parameter[1]} or " - "something else!" - ) - if not check_required_param(tg_parameter, param, obj.__name__): - raise AssertionError(f"{obj.__name__!r} parameter {param.name!r} requirement mismatch") - - if param.default is not inspect.Parameter.empty: # If there is a default argument... - default_arg_none = check_defaults_type(param) # check if its None - if not default_arg_none: - raise AssertionError(f"Param {param.name!r} of {obj.__name__!r} should be `None`") - - checked.add(field) - - expected_additional_args = GLOBALLY_IGNORED_PARAMETERS.copy() - expected_additional_args |= ptb_extra_params(name) - expected_additional_args |= backwards_compat_kwargs(name) - - unexpected_args = (sig.parameters.keys() ^ checked) - expected_additional_args - if unexpected_args != set(): - raise AssertionError(f"In {name}, unexpected args were found: {unexpected_args}.") - - -def is_parameter_required_by_tg(field: str) -> bool: - if field in {"Required", "Yes"}: - return True - return field.split(".", 1)[0] != "Optional" # splits the sentence and extracts first word - - -def check_required_param( - param_desc: list[str], param: inspect.Parameter, method_or_obj_name: str -) -> bool: - """Checks if the method/class parameter is a required/optional param as per Telegram docs. - - Returns: - :obj:`bool`: The boolean returned represents whether our parameter's requirement (optional - or required) is the same as Telegram's or not. - """ - is_ours_required = param.default is inspect.Parameter.empty - telegram_requires = is_parameter_required_by_tg(param_desc[2]) - # Handle cases where we provide convenience intentionally- - if param.name in ignored_param_requirements(method_or_obj_name): - return True - return telegram_requires is is_ours_required - - -def check_defaults_type(ptb_param: inspect.Parameter) -> bool: - return DefaultValue.get_value(ptb_param.default) is None - - -def check_param_type( - ptb_param: inspect.Parameter, tg_parameter: list[str], obj: FunctionType | type -) -> bool: - """This function checks whether the type annotation of the parameter is the same as the one - specified in the official API. It also checks for some special cases where we accept more types - - Args: - ptb_param (inspect.Parameter): The parameter object from our methods/classes - tg_parameter (list[str]): The table row corresponding to the parameter from official API. - obj (object): The object (method/class) that we are checking. - - Returns: - :obj:`bool`: The boolean returned represents whether our parameter's type annotation is the - same as Telegram's or not. - """ - # PRE-PROCESSING: - # In order to evaluate the type annotation, we need to first have a mapping of the types - # specified in the official API to our types. The keys are types in the column of official API. - TYPE_MAPPING: dict[str, set[Any]] = { - "Integer or String": {int | str}, - "Integer": {int}, - "String": {str}, - r"Boolean|True": {bool}, - r"Float(?: number)?": {float}, - # Distinguishing 1D and 2D Sequences and finding the inner type is done later. - r"Array of (?:Array of )?[\w\,\s]*": {Sequence}, - r"InputFile(?: or String)?": {FileInput}, - } - - tg_param_type: str = tg_parameter[1] # Type of parameter as specified in the docs - is_class = inspect.isclass(obj) - # Let's check for a match: - mapped: set[type] = _get_params_base(tg_param_type, TYPE_MAPPING) - - # We should have a maximum of one match. - assert len(mapped) <= 1, f"More than one match found for {tg_param_type}" - - if not mapped: # no match found, it's from telegram module - # it could be a list of objects, so let's check that: - objs = _extract_words(tg_param_type) - # We want to store both string version of class and the class obj itself. e.g. "InputMedia" - # and InputMedia because some annotations might be ForwardRefs. - if len(objs) >= 2: # We have to unionize the objects - mapped_type: tuple[Any, ...] = (_unionizer(objs, False), _unionizer(objs, True)) - else: - mapped_type = ( - getattr(telegram, tg_param_type), # This will fail if it's not from telegram mod - ForwardRef(tg_param_type), - tg_param_type, # for some reason, some annotations are just a string. - ) - elif len(mapped) == 1: - mapped_type = mapped.pop() - - # Resolve nested annotations to get inner types. - if (ptb_annotation := list(get_args(ptb_param.annotation))) == []: - ptb_annotation = ptb_param.annotation # if it's not nested, just use the annotation - - if isinstance(ptb_annotation, list): - # Some cleaning: - # Remove 'Optional[...]' from the annotation if it's present. We do it this way since: 1) - # we already check if argument should be optional or not + type checkers will complain. - # 2) we want to check if our `obj` is same as API's `obj`, and since python evaluates - # `Optional[obj] != obj` we have to remove the Optional, so that we can compare the two. - if type(None) in ptb_annotation: - ptb_annotation.remove(type(None)) - - # Cleaning done... now let's put it back together. - # Join all the annotations back (i.e. Union) - ptb_annotation = _unionizer(ptb_annotation, False) - - # Last step, we need to use get_origin to get the original type, since using get_args - # above will strip that out. - wrapped = get_origin(ptb_param.annotation) - if wrapped is not None: - # collections.abc.Sequence -> typing.Sequence - if "collections.abc.Sequence" in str(wrapped): - wrapped = Sequence - ptb_annotation = wrapped[ptb_annotation] - # We have put back our annotation together after removing the NoneType! - - # CHECKING: - # Each branch may have exits in the form of return statements. If the annotation is found to be - # correct, the function will return True. If not, it will return False. - - # 1) HANDLING ARRAY TYPES: - # Now let's do the checking, starting with "Array of ..." types. - if "Array of " in tg_param_type: - assert mapped_type is Sequence - # For exceptions just check if they contain the annotation - if ptb_param.name in ARRAY_OF_EXCEPTIONS: - return ARRAY_OF_EXCEPTIONS[ptb_param.name] in str(ptb_annotation) - - pattern = r"Array of(?: Array of)? ([\w\,\s]*)" - obj_match: re.Match | None = re.search(pattern, tg_param_type) # extract obj from string - if obj_match is None: - raise AssertionError(f"Array of {tg_param_type} not found in {ptb_param.name}") - obj_str: str = obj_match.group(1) - # is obj a regular type like str? - array_of_mapped: set[type] = _get_params_base(obj_str, TYPE_MAPPING) - - if len(array_of_mapped) == 0: # no match found, it's from telegram module - # it could be a list of objects, so let's check that: - objs = _extract_words(obj_str) - # let's unionize all the objects, with and without ForwardRefs. - unionized_objs: list[type] = [_unionizer(objs, True), _unionizer(objs, False)] - else: - unionized_objs = [array_of_mapped.pop()] - - # This means it is Array of Array of [obj] - if "Array of Array of" in tg_param_type: - return any(Sequence[Sequence[o]] == ptb_annotation for o in unionized_objs) - - # This means it is Array of [obj] - return any(mapped_type[o] == ptb_annotation for o in unionized_objs) - - # 2) HANDLING DEFAULTS PARAMETERS: - # Classes whose parameters are all ODVInput should be converted and checked. - if obj.__name__ in IGNORED_DEFAULTS_CLASSES: - parsed = ODVInput[mapped_type] - return (ptb_annotation | None) == parsed # We have to add back None in our annotation - if not ( - # Defaults checking should not be done for: - # 1. Parameters that have name conflict with `Defaults.name` - is_class - and obj.__name__ in ("ReplyParameters", "Message", "ExternalReplyInfo") - and ptb_param.name in IGNORED_DEFAULTS_PARAM_NAMES - ): - # Now let's check if the parameter is a Defaults parameter, it should be - for name, _ in inspect.getmembers(Defaults, lambda x: isinstance(x, property)): - if name == ptb_param.name or "parse_mode" in ptb_param.name: - # mapped_type should not be a tuple since we need to check for equality: - # This can happen when the Defaults parameter is a class, e.g. LinkPreviewOptions - if isinstance(mapped_type, tuple): - mapped_type = mapped_type[1] # We select the ForwardRef - # Assert if it's ODVInput by checking equality: - parsed = ODVInput[mapped_type] - if (ptb_annotation | None) == parsed: # We have to add back None in our annotation - return True - return False - - # 3) HANDLING OTHER TYPES: - # Special case for send_* methods where we accept more types than the official API: - if ( - ptb_param.name in ADDITIONAL_TYPES - and not isinstance(mapped_type, tuple) - and obj.__name__.startswith("send") - ): - mapped_type = mapped_type | ADDITIONAL_TYPES[ptb_param.name] - - # 4) HANDLING DATETIMES: - if ( - re.search( - r"""([_]+|\b) # check for word boundary or underscore - date # check for "date" - [^\w]*\b # optionally check for a word after 'date' - """, - ptb_param.name, - re.VERBOSE, - ) - or "Unix time" in tg_parameter[-1] - ): - # TODO: Remove this in v22 when it becomes a datetime - datetime_exceptions = { - "file_date", - } - if ptb_param.name in datetime_exceptions: - return True - # If it's a class, we only accept datetime as the parameter - mapped_type = datetime if is_class else mapped_type | datetime - - # RESULTS: ALL OTHER BASIC TYPES- - # Some types are too complicated, so we replace them with a simpler type: - for (param_name, expected_class), exception_type in COMPLEX_TYPES.items(): - if ptb_param.name == param_name and is_class is expected_class: - ptb_annotation = exception_type - - # Final check, if the annotation is a tuple, we need to check if any of the types in the tuple - # match the mapped type. - if isinstance(mapped_type, tuple) and any(ptb_annotation == t for t in mapped_type): - return True - - # If the annotation is not a tuple, we can just check if it's equal to the mapped type. - return mapped_type == ptb_annotation - - -def _extract_words(text: str) -> set[str]: - """Extracts all words from a string, removing all punctuation and words like 'and' & 'or'.""" - return set(re.sub(r"[^\w\s]", "", text).split()) - {"and", "or"} - - -def _unionizer(annotation: Sequence[Any] | set[Any], forward_ref: bool) -> Any: - """Returns a union of all the types in the annotation. If forward_ref is True, it wraps the - annotation in a ForwardRef and then unionizes.""" - union = None - for t in annotation: - if forward_ref: - t = ForwardRef(t) # noqa: PLW2901 - elif not forward_ref and isinstance(t, str): # we have to import objects from lib - t = getattr(telegram, t) # noqa: PLW2901 - union = t if union is None else union | t - return union - - -argvalues: list[tuple[Callable[[Tag], None], Tag]] = [] -names: list[str] = [] - -if RUN_TEST_OFFICIAL: - argvalues = [] - names = [] - request = httpx.get("https://core.telegram.org/bots/api") - soup = BeautifulSoup(request.text, "html.parser") - - for thing in soup.select("h4 > a.anchor"): - # Methods and types don't have spaces in them, luckily all other sections of the docs do - # TODO: don't depend on that - if "-" not in thing["name"]: - h4: Tag | None = thing.parent - - if h4 is None: - raise AssertionError("h4 is None") - # Is it a method - if h4.text[0].lower() == h4.text[0]: - argvalues.append((check_method, h4)) - names.append(h4.text) - elif h4.text not in IGNORED_OBJECTS: # Or a type/object - argvalues.append((check_object, h4)) - names.append(h4.text) - - -@pytest.mark.skipif(not RUN_TEST_OFFICIAL, reason="test_official is not enabled") -@pytest.mark.parametrize(("method", "data"), argvalues=argvalues, ids=names) -def test_official(method, data): - method(data) diff --git a/tests/test_official/__init__.py b/tests/test_official/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/test_official/arg_type_checker.py b/tests/test_official/arg_type_checker.py new file mode 100644 index 00000000000..2ccd7808cb5 --- /dev/null +++ b/tests/test_official/arg_type_checker.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# 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 module contains functions which confirm that the parameters of our methods and classes +match the official API. It also checks if the type annotations are correct and if the parameters +are required or not.""" + +import inspect +import logging +import re +from datetime import datetime +from types import FunctionType +from typing import Any, Sequence + +from telegram._utils.defaultvalue import DefaultValue +from telegram._utils.types import FileInput, ODVInput +from telegram.ext import Defaults +from tests.test_official.exceptions import ParamTypeCheckingExceptions as PTCE +from tests.test_official.exceptions import ignored_param_requirements +from tests.test_official.helpers import ( + _extract_words, + _get_params_base, + _unionizer, + cached_type_hints, + resolve_forward_refs_in_type, + wrap_with_none, +) +from tests.test_official.scraper import TelegramParameter + +ARRAY_OF_PATTERN = r"Array of(?: Array of)? ([\w\,\s]*)" + +# In order to evaluate the type annotation, we need to first have a mapping of the types +# specified in the official API to our types. The keys are types in the column of official API. +TYPE_MAPPING: dict[str, set[Any]] = { + "Integer or String": {int | str}, + "Integer": {int}, + "String": {str}, + r"Boolean|True": {bool}, + r"Float(?: number)?": {float}, + # Distinguishing 1D and 2D Sequences and finding the inner type is done later. + ARRAY_OF_PATTERN: {Sequence}, + r"InputFile(?: or String)?": {resolve_forward_refs_in_type(FileInput)}, +} + +ALL_DEFAULTS = inspect.getmembers(Defaults, lambda x: isinstance(x, property)) + +DATETIME_REGEX = re.compile( + r"""([_]+|\b) # check for word boundary or underscore + date # check for "date" + [^\w]*\b # optionally check for a word after 'date' + """, + re.VERBOSE, +) + +log = logging.debug + + +def check_required_param( + tg_param: TelegramParameter, param: inspect.Parameter, method_or_obj_name: str +) -> bool: + """Checks if the method/class parameter is a required/optional param as per Telegram docs. + + Returns: + :obj:`bool`: The boolean returned represents whether our parameter's requirement (optional + or required) is the same as Telegram's or not. + """ + is_ours_required = param.default is inspect.Parameter.empty + # Handle cases where we provide convenience intentionally- + if param.name in ignored_param_requirements(method_or_obj_name): + return True + return tg_param.param_required is is_ours_required + + +def check_defaults_type(ptb_param: inspect.Parameter) -> bool: + return DefaultValue.get_value(ptb_param.default) is None + + +def check_param_type( + ptb_param: inspect.Parameter, + tg_parameter: TelegramParameter, + obj: FunctionType | type, +) -> tuple[bool, type]: + """This function checks whether the type annotation of the parameter is the same as the one + specified in the official API. It also checks for some special cases where we accept more types + + Args: + ptb_param: The parameter object from our methods/classes + tg_parameter: The table row corresponding to the parameter from official API. + obj: The object (method/class) that we are checking. + + Returns: + :obj:`tuple`: A tuple containing: + * :obj:`bool`: The boolean returned represents whether our parameter's type annotation + is the same as Telegram's or not. + * :obj:`type`: The expected type annotation of the parameter. + """ + # PRE-PROCESSING: + tg_param_type: str = tg_parameter.param_type + is_class = inspect.isclass(obj) + ptb_annotation = cached_type_hints(obj, is_class).get(ptb_param.name) + + # Let's check for a match: + # In order to evaluate the type annotation, we need to first have a mapping of the types + # (see TYPE_MAPPING comment defined at the top level of this module) + mapped: set[type] = _get_params_base(tg_param_type, TYPE_MAPPING) + + # We should have a maximum of one match. + assert len(mapped) <= 1, f"More than one match found for {tg_param_type}" + + # it may be a list of objects, so let's extract them using _extract_words: + mapped_type = _unionizer(_extract_words(tg_param_type)) if not mapped else mapped.pop() + # If the parameter is not required by TG, `None` should be added to `mapped_type` + mapped_type = wrap_with_none(tg_parameter, mapped_type, obj) + + log( + "At the end of PRE-PROCESSING, the values of variables are:\n" + "Parameter name: %s\n" + "ptb_annotation= %s\n" + "mapped_type= %s\n" + "tg_param_type= %s\n" + "tg_parameter.param_required= %s\n", + ptb_param.name, + ptb_annotation, + mapped_type, + tg_param_type, + tg_parameter.param_required, + ) + + # CHECKING: + # Each branch manipulates the `mapped_type` (except for 4) ) to match the `ptb_annotation`. + + # 1) HANDLING ARRAY TYPES: + # Now let's do the checking, starting with "Array of ..." types. + if "Array of " in tg_param_type: + # For exceptions just check if they contain the annotation + if ptb_param.name in PTCE.ARRAY_OF_EXCEPTIONS: + return PTCE.ARRAY_OF_EXCEPTIONS[ptb_param.name] in str(ptb_annotation), Sequence + + obj_match: re.Match | None = re.search(ARRAY_OF_PATTERN, tg_param_type) + if obj_match is None: + raise AssertionError(f"Array of {tg_param_type} not found in {ptb_param.name}") + obj_str: str = obj_match.group(1) + # is obj a regular type like str? + array_map: set[type] = _get_params_base(obj_str, TYPE_MAPPING) + + mapped_type = _unionizer(_extract_words(obj_str)) if not array_map else array_map.pop() + + if "Array of Array of" in tg_param_type: + log("Array of Array of type found in `%s`\n", tg_param_type) + mapped_type = Sequence[Sequence[mapped_type]] + else: + log("Array of type found in `%s`\n", tg_param_type) + mapped_type = Sequence[mapped_type] + + # 2) HANDLING OTHER TYPES: + # Special case for send_* methods where we accept more types than the official API: + elif ptb_param.name in PTCE.ADDITIONAL_TYPES and obj.__name__.startswith("send"): + log("Checking that `%s` has an additional argument!\n", ptb_param.name) + mapped_type = mapped_type | PTCE.ADDITIONAL_TYPES[ptb_param.name] + + # 3) HANDLING DATETIMES: + elif ( + re.search( + DATETIME_REGEX, + ptb_param.name, + ) + or "Unix time" in tg_parameter.param_description + ): + log("Checking that `%s` is a datetime!\n", ptb_param.name) + if ptb_param.name in PTCE.DATETIME_EXCEPTIONS: + return True, mapped_type + # If it's a class, we only accept datetime as the parameter + mapped_type = datetime if is_class else mapped_type | datetime + + # 4) COMPLEX TYPES: + # Some types are too complicated, so we replace our annotation with a simpler type: + elif any(ptb_param.name in key for key in PTCE.COMPLEX_TYPES): + log("Converting `%s` to a simpler type!\n", ptb_param.name) + for (param_name, is_expected_class), exception_type in PTCE.COMPLEX_TYPES.items(): + if ptb_param.name == param_name and is_class is is_expected_class: + ptb_annotation = wrap_with_none(tg_parameter, exception_type, obj) + + # 5) HANDLING DEFAULTS PARAMETERS: + # Classes whose parameters are all ODVInput should be converted and checked. + elif obj.__name__ in PTCE.IGNORED_DEFAULTS_CLASSES: + log("Checking that `%s`'s param is ODVInput:\n", obj.__name__) + mapped_type = ODVInput[mapped_type] + elif not ( + # Defaults checking should not be done for: + # 1. Parameters that have name conflict with `Defaults.name` + is_class + and obj.__name__ in ("ReplyParameters", "Message", "ExternalReplyInfo") + and ptb_param.name in PTCE.IGNORED_DEFAULTS_PARAM_NAMES + ): + # Now let's check if the parameter is a Defaults parameter, it should be + for name, _ in ALL_DEFAULTS: + if name == ptb_param.name or "parse_mode" in ptb_param.name: + log("Checking that `%s` is a Defaults parameter!\n", ptb_param.name) + mapped_type = ODVInput[mapped_type] + break + + # RESULTS:- + mapped_type = wrap_with_none(tg_parameter, mapped_type, obj) + mapped_type = resolve_forward_refs_in_type(mapped_type) + log( + "At RESULTS, we are comparing:\nptb_annotation= %s\nmapped_type= %s\n", + ptb_annotation, + mapped_type, + ) + return mapped_type == ptb_annotation, mapped_type diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py new file mode 100644 index 00000000000..e554b0888ad --- /dev/null +++ b/tests/test_official/exceptions.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# 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 module contains exceptions to our API compared to the official API.""" + + +from telegram import Animation, Audio, Document, PhotoSize, Sticker, Video, VideoNote, Voice +from tests.test_official.helpers import _get_params_base + +IGNORED_OBJECTS = ("ResponseParameters",) +GLOBALLY_IGNORED_PARAMETERS = { + "self", + "read_timeout", + "write_timeout", + "connect_timeout", + "pool_timeout", + "bot", + "api_kwargs", +} + + +class ParamTypeCheckingExceptions: + # Types for certain parameters accepted by PTB but not in the official API + ADDITIONAL_TYPES = { + "photo": PhotoSize, + "video": Video, + "video_note": VideoNote, + "audio": Audio, + "document": Document, + "animation": Animation, + "voice": Voice, + "sticker": Sticker, + } + + # Exceptions to the "Array of" types, where we accept more types than the official API + # key: parameter name, value: type which must be present in the annotation + ARRAY_OF_EXCEPTIONS = { + "results": "InlineQueryResult", # + Callable + "commands": "BotCommand", # + tuple[str, str] + "keyboard": "KeyboardButton", # + sequence[sequence[str]] + "reaction": "ReactionType", # + str + # TODO: Deprecated and will be corrected (and removed) in next major PTB version: + "file_hashes": "List[str]", + } + + # Special cases for other parameters that accept more types than the official API, and are + # too complex to compare/predict with official API: + COMPLEX_TYPES = ( + { # (param_name, is_class (i.e appears in a class?)): reduced form of annotation + ("correct_option_id", False): int, # actual: Literal + ("file_id", False): str, # actual: Union[str, objs_with_file_id_attr] + ("invite_link", False): str, # actual: Union[str, ChatInviteLink] + ("provider_data", False): str, # actual: Union[str, obj] + ("callback_data", True): str, # actual: Union[str, obj] + ("media", True): str, # actual: Union[str, InputMedia*, FileInput] + ( + "data", + True, + ): str, # actual: Union[IdDocumentData, PersonalDetails, ResidentialAddress] + } + ) + + # param names ignored in the param type checking in classes for the `tg.Defaults` case. + IGNORED_DEFAULTS_PARAM_NAMES = { + "quote", + "link_preview_options", + } + + # These classes' params are all ODVInput, so we ignore them in the defaults type checking. + IGNORED_DEFAULTS_CLASSES = {"LinkPreviewOptions"} + + # TODO: Remove this in v22 when it becomes a datetime (also remove from arg_type_checker.py) + DATETIME_EXCEPTIONS = { + "file_date", + } + + +# Arguments *added* to the official API +PTB_EXTRA_PARAMS = { + "send_contact": {"contact"}, + "send_location": {"location"}, + "edit_message_live_location": {"location"}, + "send_venue": {"venue"}, + "answer_inline_query": {"current_offset"}, + "send_media_group": {"caption", "parse_mode", "caption_entities"}, + "send_(animation|audio|document|photo|video(_note)?|voice)": {"filename"}, + "InlineQueryResult": {"id", "type"}, # attributes common to all subclasses + "ChatMember": {"user", "status"}, # attributes common to all subclasses + "BotCommandScope": {"type"}, # attributes common to all subclasses + "MenuButton": {"type"}, # attributes common to all subclasses + "PassportFile": {"credentials"}, + "EncryptedPassportElement": {"credentials"}, + "PassportElementError": {"source", "type", "message"}, + "InputMedia": {"caption", "caption_entities", "media", "media_type", "parse_mode"}, + "InputMedia(Animation|Audio|Document|Photo|Video|VideoNote|Voice)": {"filename"}, + "InputFile": {"attach", "filename", "obj"}, + "MaybeInaccessibleMessage": {"date", "message_id", "chat"}, # attributes common to all subcls + "ChatBoostSource": {"source"}, # attributes common to all subclasses + "MessageOrigin": {"type", "date"}, # attributes common to all subclasses + "ReactionType": {"type"}, # attributes common to all subclasses + "InputTextMessageContent": {"disable_web_page_preview"}, # convenience arg, here for bw compat +} + + +def ptb_extra_params(object_name: str) -> set[str]: + return _get_params_base(object_name, PTB_EXTRA_PARAMS) + + +# Arguments *removed* from the official API +# Mostly due to the value being fixed anyway +PTB_IGNORED_PARAMS = { + r"InlineQueryResult\w+": {"type"}, + r"ChatMember\w+": {"status"}, + r"PassportElementError\w+": {"source"}, + "ForceReply": {"force_reply"}, + "ReplyKeyboardRemove": {"remove_keyboard"}, + r"BotCommandScope\w+": {"type"}, + r"MenuButton\w+": {"type"}, + r"InputMedia\w+": {"type"}, + "InaccessibleMessage": {"date"}, + r"MessageOrigin\w+": {"type"}, + r"ChatBoostSource\w+": {"source"}, + r"ReactionType\w+": {"type"}, +} + + +def ptb_ignored_params(object_name: str) -> set[str]: + return _get_params_base(object_name, PTB_IGNORED_PARAMS) + + +IGNORED_PARAM_REQUIREMENTS = { + # Ignore these since there's convenience params in them (eg. Venue) + # <---- + "send_location": {"latitude", "longitude"}, + "edit_message_live_location": {"latitude", "longitude"}, + "send_venue": {"latitude", "longitude", "title", "address"}, + "send_contact": {"phone_number", "first_name"}, + # ----> +} + + +def ignored_param_requirements(object_name: str) -> set[str]: + return _get_params_base(object_name, IGNORED_PARAM_REQUIREMENTS) + + +# Arguments that are optional arguments for now for backwards compatibility +BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { + # Deprecated by Bot API 7.0, kept for now for bw compat: + "KeyboardButton": {"request_user"}, + "Message": { + "forward_from", + "forward_signature", + "forward_sender_name", + "forward_date", + "forward_from_chat", + "forward_from_message_id", + "user_shared", + }, + "(send_message|edit_message_text)": { + "disable_web_page_preview", + "reply_to_message_id", + "allow_sending_without_reply", + }, + r"copy_message|send_\w+": {"allow_sending_without_reply", "reply_to_message_id"}, +} + + +def backwards_compat_kwargs(object_name: str) -> set[str]: + return _get_params_base(object_name, BACKWARDS_COMPAT_KWARGS) + + +IGNORED_PARAM_REQUIREMENTS.update(BACKWARDS_COMPAT_KWARGS) diff --git a/tests/test_official/helpers.py b/tests/test_official/helpers.py new file mode 100644 index 00000000000..6851bf85fa2 --- /dev/null +++ b/tests/test_official/helpers.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# 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 module contains helper functions for the official API tests used in the other modules.""" + +import functools +import re +from typing import TYPE_CHECKING, Any, Sequence, _eval_type, get_type_hints + +from bs4 import PageElement, Tag + +import telegram +import telegram._utils.defaultvalue +import telegram._utils.types + +if TYPE_CHECKING: + from tests.test_official.scraper import TelegramParameter + + +tg_objects = vars(telegram) +tg_objects.update(vars(telegram._utils.types)) +tg_objects.update(vars(telegram._utils.defaultvalue)) + + +def _get_params_base(object_name: str, search_dict: dict[str, set[Any]]) -> set[Any]: + """Helper function for the *_params functions below. + Given an object name and a search dict, goes through the keys of the search dict and checks if + the object name matches any of the regexes (keys). The union of all the sets (values) of the + matching regexes is returned. `object_name` may be a CamelCase or snake_case name. + """ + out = set() + for regex, params in search_dict.items(): + if re.fullmatch(regex, object_name): + out.update(params) + # also check the snake_case version + snake_case_name = re.sub(r"(? set[str]: + """Extracts all words from a string, removing all punctuation and words like 'and' & 'or'.""" + return set(re.sub(r"[^\w\s]", "", text).split()) - {"and", "or"} + + +def _unionizer(annotation: Sequence[Any] | set[Any]) -> Any: + """Returns a union of all the types in the annotation. Also imports objects from lib.""" + union = None + for t in annotation: + if isinstance(t, str): # we have to import objects from lib + t = getattr(telegram, t) # noqa: PLW2901 + union = t if union is None else union | t + return union + + +def find_next_sibling_until(tag: Tag, name: str, until: Tag) -> PageElement | None: + for sibling in tag.next_siblings: + if sibling is until: + return None + if sibling.name == name: + return sibling + return None + + +def is_pascal_case(s): + "PascalCase. Starts with a capital letter and has no spaces. Useful for identifying classes." + return bool(re.match(r"^[A-Z][a-zA-Z\d]*$", s)) + + +def is_parameter_required_by_tg(field: str) -> bool: + if field in {"Required", "Yes"}: + return True + return field.split(".", 1)[0] != "Optional" # splits the sentence and extracts first word + + +def wrap_with_none(tg_parameter: "TelegramParameter", mapped_type: Any, obj: object) -> type: + """Adds `None` to type annotation if the parameter isn't required. Respects ignored params.""" + # have to import here to avoid circular imports + from tests.test_official.exceptions import ignored_param_requirements + + if tg_parameter.param_name in ignored_param_requirements(obj.__name__): + return mapped_type | type(None) + return mapped_type | type(None) if not tg_parameter.param_required else mapped_type + + +@functools.cache +def cached_type_hints(obj: Any, is_class: bool) -> dict[str, Any]: + """Returns type hints of a class, method, or function, with forward refs evaluated.""" + return get_type_hints(obj.__init__ if is_class else obj, localns=tg_objects) + + +@functools.cache +def resolve_forward_refs_in_type(obj: type) -> type: + """Resolves forward references in a type hint.""" + return _eval_type(obj, localns=tg_objects, globalns=None) diff --git a/tests/test_official/scraper.py b/tests/test_official/scraper.py new file mode 100644 index 00000000000..1da83a87a90 --- /dev/null +++ b/tests/test_official/scraper.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# 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 module contains functions which are used to scrape the official Bot API documentation.""" + +import asyncio +from dataclasses import dataclass +from typing import Literal, overload + +import httpx +from bs4 import BeautifulSoup, Tag + +from tests.test_official.exceptions import IGNORED_OBJECTS +from tests.test_official.helpers import ( + find_next_sibling_until, + is_parameter_required_by_tg, + is_pascal_case, +) + + +@dataclass(slots=True, frozen=True) +class TelegramParameter: + """Represents the scraped Telegram parameter. Contains all relevant attributes needed for + comparison. Relevant for both TelegramMethod and TelegramClass.""" + + param_name: str + param_type: str + param_required: bool + param_description: str + + +@dataclass(slots=True, frozen=True) +class TelegramClass: + """Represents the scraped Telegram class. Contains all relevant attributes needed for + comparison.""" + + class_name: str + class_parameters: list[TelegramParameter] + # class_description: str + + +@dataclass(slots=True, frozen=True) +class TelegramMethod: + """Represents the scraped Telegram method. Contains all relevant attributes needed for + comparison.""" + + method_name: str + method_parameters: list[TelegramParameter] + # method_description: str + + +@dataclass(slots=True, frozen=False) +class Scraper: + request: httpx.Response | None = None + soup: BeautifulSoup | None = None + + async def make_request(self) -> None: + async with httpx.AsyncClient() as client: + self.request = await client.get("https://core.telegram.org/bots/api", timeout=10) + self.soup = BeautifulSoup(self.request.text, "html.parser") + + @overload + def parse_docs( + self, doc_type: Literal["method"] + ) -> tuple[list[TelegramMethod], list[str]]: ... + + @overload + def parse_docs(self, doc_type: Literal["class"]) -> tuple[list[TelegramClass], list[str]]: ... + + def parse_docs(self, doc_type): + argvalues = [] + names: list[str] = [] + if self.request is None: + asyncio.run(self.make_request()) + + for unparsed in self.soup.select("h4 > a.anchor"): + if "-" not in unparsed["name"]: + h4: Tag | None = unparsed.parent + name = h4.text + if h4 is None: + raise AssertionError("h4 is None") + if doc_type == "method" and name[0].lower() == name[0]: + params = parse_table_for_params(h4) + obj = TelegramMethod(method_name=name, method_parameters=params) + argvalues.append(obj) + names.append(name) + elif doc_type == "class" and is_pascal_case(name) and name not in IGNORED_OBJECTS: + params = parse_table_for_params(h4) + obj = TelegramClass(class_name=name, class_parameters=params) + argvalues.append(obj) + names.append(name) + + return argvalues, names + + def collect_methods(self) -> tuple[list[TelegramMethod], list[str]]: + return self.parse_docs("method") + + def collect_classes(self) -> tuple[list[TelegramClass], list[str]]: + return self.parse_docs("class") + + +def parse_table_for_params(h4: Tag) -> list[TelegramParameter]: + """Parses the Telegram doc table and outputs a list of TelegramParameter objects.""" + table = find_next_sibling_until(h4, "table", h4.find_next_sibling("h4")) + if not table: + return [] + + params = [] + for tr in table.find_all("tr")[1:]: + fields = [] + for td in tr.find_all("td"): + param = td.text + fields.append(param) + + param_name = fields[0] + param_type = fields[1] + param_required = is_parameter_required_by_tg(fields[2]) + param_desc = fields[-1] # since length can be 2 or 3, but desc is always the last + params.append(TelegramParameter(param_name, param_type, param_required, param_desc)) + + return params diff --git a/tests/test_official/test_official.py b/tests/test_official/test_official.py new file mode 100644 index 00000000000..5ad1d8b5686 --- /dev/null +++ b/tests/test_official/test_official.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2024 +# Leandro Toledo de Souza +# +# 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/]. +import inspect +from typing import TYPE_CHECKING + +import pytest + +import telegram +from tests.auxil.envvars import RUN_TEST_OFFICIAL +from tests.test_official.arg_type_checker import ( + check_defaults_type, + check_param_type, + check_required_param, +) +from tests.test_official.exceptions import ( + GLOBALLY_IGNORED_PARAMETERS, + backwards_compat_kwargs, + ptb_extra_params, + ptb_ignored_params, +) +from tests.test_official.scraper import Scraper, TelegramClass, TelegramMethod + +if TYPE_CHECKING: + from types import FunctionType + +# Will skip all tests in this file if the env var is False +pytestmark = pytest.mark.skipif(not RUN_TEST_OFFICIAL, reason="test_official is not enabled") + +methods, method_ids, classes, class_ids = [], [], [], [] # not needed (just for completeness) + +if RUN_TEST_OFFICIAL: + scraper = Scraper() + methods, method_ids = scraper.collect_methods() + classes, class_ids = scraper.collect_classes() + + +@pytest.mark.parametrize("tg_method", argvalues=methods, ids=method_ids) +def test_check_method(tg_method: TelegramMethod) -> None: + """This function checks for the following things compared to the official API docs: + + - Method existence + - Parameter existence + - Parameter requirement correctness + - Parameter type annotation existence + - Parameter type annotation correctness + - Parameter default value correctness + - No unexpected parameters + - Extra parameters should be keyword only + """ + ptb_method: FunctionType | None = getattr(telegram.Bot, tg_method.method_name, None) + assert ptb_method, f"Method {tg_method.method_name} not found in telegram.Bot" + + # Check arguments based on source + sig = inspect.signature(ptb_method, follow_wrapped=True) + checked = [] + + for tg_parameter in tg_method.method_parameters: + # Check if parameter is present in our method + ptb_param = sig.parameters.get(tg_parameter.param_name) + assert ( + ptb_param is not None + ), f"Parameter {tg_parameter.param_name} not found in {ptb_method.__name__}" + + # Now check if the parameter is required or not + assert check_required_param( + tg_parameter, ptb_param, ptb_method.__name__ + ), f"Param {ptb_param.name!r} of {ptb_method.__name__!r} requirement mismatch" + + # Check if type annotation is present + assert ( + ptb_param.annotation is not inspect.Parameter.empty + ), f"Param {ptb_param.name!r} of {ptb_method.__name__!r} should have a type annotation!" + # Check if type annotation is correct + correct_type_hint, expected_type_hint = check_param_type( + ptb_param, + tg_parameter, + ptb_method, + ) + assert correct_type_hint, ( + f"Type hint of param {ptb_param.name!r} of {ptb_method.__name__!r} should be " + f"{expected_type_hint!r} or something else!" + ) + + # Now we will check that we don't pass default values if the parameter is not required. + if ptb_param.default is not inspect.Parameter.empty: # If there is a default argument... + default_arg_none = check_defaults_type(ptb_param) # check if it's None + assert ( + default_arg_none + ), f"Param {ptb_param.name!r} of {ptb_method.__name__!r} should be `None`" + checked.append(tg_parameter.param_name) + + expected_additional_args = GLOBALLY_IGNORED_PARAMETERS.copy() + expected_additional_args |= ptb_extra_params(tg_method.method_name) + expected_additional_args |= backwards_compat_kwargs(tg_method.method_name) + + unexpected_args = (sig.parameters.keys() ^ checked) - expected_additional_args + assert ( + unexpected_args == set() + ), f"In {ptb_method.__qualname__}, unexpected args were found: {unexpected_args}." + + kw_or_positional_args = [ + p.name for p in sig.parameters.values() if p.kind != inspect.Parameter.KEYWORD_ONLY + ] + non_kw_only_args = set(kw_or_positional_args).difference(checked).difference(["self"]) + non_kw_only_args -= backwards_compat_kwargs(tg_method.method_name) + assert non_kw_only_args == set(), ( + f"In {ptb_method.__qualname__}, extra args should be keyword only (compared to " + f"{tg_method.method_name} in API)" + ) + + +@pytest.mark.parametrize("tg_class", argvalues=classes, ids=class_ids) +def test_check_object(tg_class: TelegramClass) -> None: + """This function checks for the following things compared to the official API docs: + + - Class existence + - Parameter existence + - Parameter requirement correctness + - Parameter type annotation existence + - Parameter type annotation correctness + - Parameter default value correctness + - No unexpected parameters + """ + obj = getattr(telegram, tg_class.class_name) + + # Check arguments based on source. Makes sure to only check __init__'s signature & nothing else + sig = inspect.signature(obj.__init__, follow_wrapped=True) + + checked = set() + fields_removed_by_ptb = ptb_ignored_params(tg_class.class_name) + + for tg_parameter in tg_class.class_parameters: + field: str = tg_parameter.param_name + + if field in fields_removed_by_ptb: + continue + + if field == "from": + field = "from_user" + + ptb_param = sig.parameters.get(field) + assert ptb_param is not None, f"Attribute {field} not found in {obj.__name__}" + + # Now check if the parameter is required or not + assert check_required_param( + tg_parameter, ptb_param, obj.__name__ + ), f"Param {ptb_param.name!r} of {obj.__name__!r} requirement mismatch" + + # Check if type annotation is present + assert ( + ptb_param.annotation is not inspect.Parameter.empty + ), f"Param {ptb_param.name!r} of {obj.__name__!r} should have a type annotation" + + # Check if type annotation is correct + correct_type_hint, expected_type_hint = check_param_type(ptb_param, tg_parameter, obj) + assert correct_type_hint, ( + f"Type hint of param {ptb_param.name!r} of {obj.__name__!r} should be " + f"{expected_type_hint!r} or something else!" + ) + + # Now we will check that we don't pass default values if the parameter is not required. + if ptb_param.default is not inspect.Parameter.empty: # If there is a default argument... + default_arg_none = check_defaults_type(ptb_param) # check if its None + assert ( + default_arg_none + ), f"Param {ptb_param.name!r} of {obj.__name__!r} should be `None`" + + checked.add(field) + + expected_additional_args = GLOBALLY_IGNORED_PARAMETERS.copy() + expected_additional_args |= ptb_extra_params(tg_class.class_name) + expected_additional_args |= backwards_compat_kwargs(tg_class.class_name) + + unexpected_args = (sig.parameters.keys() ^ checked) - expected_additional_args + assert ( + unexpected_args == set() + ), f"In {tg_class.class_name}, unexpected args were found: {unexpected_args}." From 5b6cd3a33bfd5bdc76b357854dce54cd392c842b Mon Sep 17 00:00:00 2001 From: Abdelrahman Elkheir <90580077+aelkheir@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:06:25 +0300 Subject: [PATCH 02/17] Update Copyright to 2024 (#4121) --- docs/auxil/admonition_inserter.py | 2 +- docs/auxil/kwargs_insertion.py | 2 +- docs/auxil/link_code.py | 2 +- docs/auxil/sphinx_hooks.py | 2 +- docs/auxil/tg_const_role.py | 2 +- docs/source/conf.py | 2 +- telegram/__init__.py | 2 +- telegram/__main__.py | 2 +- telegram/_bot.py | 2 +- telegram/_botcommand.py | 2 +- telegram/_botcommandscope.py | 2 +- telegram/_botdescription.py | 2 +- telegram/_botname.py | 2 +- telegram/_callbackquery.py | 2 +- telegram/_chat.py | 2 +- telegram/_chatadministratorrights.py | 2 +- telegram/_chatinvitelink.py | 2 +- telegram/_chatjoinrequest.py | 2 +- telegram/_chatlocation.py | 2 +- telegram/_chatmember.py | 2 +- telegram/_chatmemberupdated.py | 2 +- telegram/_chatpermissions.py | 2 +- telegram/_choseninlineresult.py | 2 +- telegram/_dice.py | 2 +- telegram/_files/_basemedium.py | 2 +- telegram/_files/_basethumbedmedium.py | 2 +- telegram/_files/animation.py | 2 +- telegram/_files/audio.py | 2 +- telegram/_files/chatphoto.py | 2 +- telegram/_files/contact.py | 2 +- telegram/_files/document.py | 2 +- telegram/_files/file.py | 2 +- telegram/_files/inputfile.py | 2 +- telegram/_files/inputmedia.py | 2 +- telegram/_files/inputsticker.py | 2 +- telegram/_files/location.py | 2 +- telegram/_files/photosize.py | 2 +- telegram/_files/sticker.py | 2 +- telegram/_files/venue.py | 2 +- telegram/_files/video.py | 2 +- telegram/_files/videonote.py | 2 +- telegram/_files/voice.py | 2 +- telegram/_forcereply.py | 2 +- telegram/_forumtopic.py | 2 +- telegram/_games/callbackgame.py | 2 +- telegram/_games/game.py | 2 +- telegram/_games/gamehighscore.py | 2 +- telegram/_giveaway.py | 2 +- telegram/_inline/inlinekeyboardbutton.py | 2 +- telegram/_inline/inlinekeyboardmarkup.py | 2 +- telegram/_inline/inlinequery.py | 2 +- telegram/_inline/inlinequeryresult.py | 2 +- telegram/_inline/inlinequeryresultarticle.py | 2 +- telegram/_inline/inlinequeryresultaudio.py | 2 +- telegram/_inline/inlinequeryresultcachedaudio.py | 2 +- telegram/_inline/inlinequeryresultcacheddocument.py | 2 +- telegram/_inline/inlinequeryresultcachedgif.py | 2 +- telegram/_inline/inlinequeryresultcachedmpeg4gif.py | 2 +- telegram/_inline/inlinequeryresultcachedphoto.py | 2 +- telegram/_inline/inlinequeryresultcachedsticker.py | 2 +- telegram/_inline/inlinequeryresultcachedvideo.py | 2 +- telegram/_inline/inlinequeryresultcachedvoice.py | 2 +- telegram/_inline/inlinequeryresultcontact.py | 2 +- telegram/_inline/inlinequeryresultdocument.py | 2 +- telegram/_inline/inlinequeryresultgame.py | 2 +- telegram/_inline/inlinequeryresultgif.py | 2 +- telegram/_inline/inlinequeryresultlocation.py | 2 +- telegram/_inline/inlinequeryresultmpeg4gif.py | 2 +- telegram/_inline/inlinequeryresultphoto.py | 2 +- telegram/_inline/inlinequeryresultsbutton.py | 2 +- telegram/_inline/inlinequeryresultvenue.py | 2 +- telegram/_inline/inlinequeryresultvideo.py | 2 +- telegram/_inline/inlinequeryresultvoice.py | 2 +- telegram/_inline/inputcontactmessagecontent.py | 2 +- telegram/_inline/inputinvoicemessagecontent.py | 2 +- telegram/_inline/inputlocationmessagecontent.py | 2 +- telegram/_inline/inputmessagecontent.py | 2 +- telegram/_inline/inputtextmessagecontent.py | 2 +- telegram/_inline/inputvenuemessagecontent.py | 2 +- telegram/_keyboardbutton.py | 2 +- telegram/_keyboardbuttonpolltype.py | 2 +- telegram/_keyboardbuttonrequest.py | 2 +- telegram/_loginurl.py | 2 +- telegram/_menubutton.py | 2 +- telegram/_message.py | 2 +- telegram/_messageautodeletetimerchanged.py | 2 +- telegram/_messageentity.py | 2 +- telegram/_messageid.py | 2 +- telegram/_passport/credentials.py | 2 +- telegram/_passport/data.py | 2 +- telegram/_passport/encryptedpassportelement.py | 2 +- telegram/_passport/passportdata.py | 2 +- telegram/_passport/passportelementerrors.py | 2 +- telegram/_passport/passportfile.py | 2 +- telegram/_payment/invoice.py | 2 +- telegram/_payment/labeledprice.py | 2 +- telegram/_payment/orderinfo.py | 2 +- telegram/_payment/precheckoutquery.py | 2 +- telegram/_payment/shippingaddress.py | 2 +- telegram/_payment/shippingoption.py | 2 +- telegram/_payment/shippingquery.py | 2 +- telegram/_payment/successfulpayment.py | 2 +- telegram/_poll.py | 2 +- telegram/_proximityalerttriggered.py | 2 +- telegram/_reaction.py | 2 +- telegram/_reply.py | 2 +- telegram/_replykeyboardmarkup.py | 2 +- telegram/_replykeyboardremove.py | 2 +- telegram/_sentwebappmessage.py | 2 +- telegram/_shared.py | 2 +- telegram/_story.py | 2 +- telegram/_switchinlinequerychosenchat.py | 2 +- telegram/_telegramobject.py | 2 +- telegram/_update.py | 2 +- telegram/_user.py | 2 +- telegram/_userprofilephotos.py | 2 +- telegram/_utils/argumentparsing.py | 2 +- telegram/_utils/datetime.py | 2 +- telegram/_utils/defaultvalue.py | 2 +- telegram/_utils/enum.py | 2 +- telegram/_utils/files.py | 2 +- telegram/_utils/logging.py | 2 +- telegram/_utils/markup.py | 2 +- telegram/_utils/repr.py | 2 +- telegram/_utils/strings.py | 2 +- telegram/_utils/types.py | 2 +- telegram/_utils/warnings.py | 2 +- telegram/_utils/warnings_transition.py | 2 +- telegram/_version.py | 2 +- telegram/_videochat.py | 2 +- telegram/_webappdata.py | 2 +- telegram/_webappinfo.py | 2 +- telegram/_webhookinfo.py | 2 +- telegram/_writeaccessallowed.py | 2 +- telegram/constants.py | 2 +- telegram/error.py | 2 +- telegram/ext/__init__.py | 2 +- telegram/ext/_aioratelimiter.py | 2 +- telegram/ext/_application.py | 2 +- telegram/ext/_applicationbuilder.py | 2 +- telegram/ext/_basepersistence.py | 2 +- telegram/ext/_baseratelimiter.py | 2 +- telegram/ext/_baseupdateprocessor.py | 2 +- telegram/ext/_callbackcontext.py | 2 +- telegram/ext/_callbackdatacache.py | 2 +- telegram/ext/_contexttypes.py | 2 +- telegram/ext/_defaults.py | 2 +- telegram/ext/_dictpersistence.py | 2 +- telegram/ext/_extbot.py | 2 +- telegram/ext/_handlers/basehandler.py | 2 +- telegram/ext/_handlers/callbackqueryhandler.py | 2 +- telegram/ext/_handlers/chatjoinrequesthandler.py | 2 +- telegram/ext/_handlers/chatmemberhandler.py | 2 +- telegram/ext/_handlers/choseninlineresulthandler.py | 2 +- telegram/ext/_handlers/commandhandler.py | 2 +- telegram/ext/_handlers/conversationhandler.py | 2 +- telegram/ext/_handlers/inlinequeryhandler.py | 2 +- telegram/ext/_handlers/messagehandler.py | 2 +- telegram/ext/_handlers/messagereactionhandler.py | 2 +- telegram/ext/_handlers/pollanswerhandler.py | 2 +- telegram/ext/_handlers/pollhandler.py | 2 +- telegram/ext/_handlers/precheckoutqueryhandler.py | 2 +- telegram/ext/_handlers/prefixhandler.py | 2 +- telegram/ext/_handlers/shippingqueryhandler.py | 2 +- telegram/ext/_handlers/stringcommandhandler.py | 2 +- telegram/ext/_handlers/stringregexhandler.py | 2 +- telegram/ext/_handlers/typehandler.py | 2 +- telegram/ext/_jobqueue.py | 2 +- telegram/ext/_picklepersistence.py | 2 +- telegram/ext/_updater.py | 2 +- telegram/ext/_utils/__init__.py | 2 +- telegram/ext/_utils/_update_parsing.py | 2 +- telegram/ext/_utils/stack.py | 2 +- telegram/ext/_utils/trackingdict.py | 2 +- telegram/ext/_utils/types.py | 2 +- telegram/ext/_utils/webhookhandler.py | 2 +- telegram/ext/filters.py | 2 +- telegram/helpers.py | 2 +- telegram/request/__init__.py | 2 +- telegram/request/_baserequest.py | 2 +- telegram/request/_httpxrequest.py | 2 +- telegram/request/_requestdata.py | 2 +- telegram/request/_requestparameter.py | 2 +- telegram/warnings.py | 2 +- tests/_files/__init__.py | 2 +- tests/_files/test_animation.py | 2 +- tests/_files/test_audio.py | 2 +- tests/_files/test_chatphoto.py | 2 +- tests/_files/test_contact.py | 2 +- tests/_files/test_document.py | 2 +- tests/_files/test_file.py | 2 +- tests/_files/test_inputfile.py | 2 +- tests/_files/test_inputmedia.py | 2 +- tests/_files/test_inputsticker.py | 2 +- tests/_files/test_location.py | 2 +- tests/_files/test_photo.py | 2 +- tests/_files/test_sticker.py | 2 +- tests/_files/test_venue.py | 2 +- tests/_files/test_video.py | 2 +- tests/_files/test_videonote.py | 2 +- tests/_files/test_voice.py | 2 +- tests/_games/__init__.py | 2 +- tests/_games/test_game.py | 2 +- tests/_games/test_gamehighscore.py | 2 +- tests/_inline/__init__.py | 2 +- tests/_inline/test_inlinekeyboardbutton.py | 2 +- tests/_inline/test_inlinekeyboardmarkup.py | 2 +- tests/_inline/test_inlinequery.py | 2 +- tests/_inline/test_inlinequeryhandler.py | 2 +- tests/_inline/test_inlinequeryresultarticle.py | 2 +- tests/_inline/test_inlinequeryresultaudio.py | 2 +- tests/_inline/test_inlinequeryresultcachedaudio.py | 2 +- tests/_inline/test_inlinequeryresultcacheddocument.py | 2 +- tests/_inline/test_inlinequeryresultcachedgif.py | 2 +- tests/_inline/test_inlinequeryresultcachedmpeg4gif.py | 2 +- tests/_inline/test_inlinequeryresultcachedphoto.py | 2 +- tests/_inline/test_inlinequeryresultcachedsticker.py | 2 +- tests/_inline/test_inlinequeryresultcachedvideo.py | 2 +- tests/_inline/test_inlinequeryresultcachedvoice.py | 2 +- tests/_inline/test_inlinequeryresultcontact.py | 2 +- tests/_inline/test_inlinequeryresultdocument.py | 2 +- tests/_inline/test_inlinequeryresultgame.py | 2 +- tests/_inline/test_inlinequeryresultgif.py | 2 +- tests/_inline/test_inlinequeryresultlocation.py | 2 +- tests/_inline/test_inlinequeryresultmpeg4gif.py | 2 +- tests/_inline/test_inlinequeryresultphoto.py | 2 +- tests/_inline/test_inlinequeryresultvenue.py | 2 +- tests/_inline/test_inlinequeryresultvideo.py | 2 +- tests/_inline/test_inlinequeryresultvoice.py | 2 +- tests/_inline/test_inputcontactmessagecontent.py | 2 +- tests/_inline/test_inputinvoicemessagecontent.py | 2 +- tests/_inline/test_inputlocationmessagecontent.py | 2 +- tests/_inline/test_inputtextmessagecontent.py | 2 +- tests/_inline/test_inputvenuemessagecontent.py | 2 +- tests/_passport/__init__.py | 2 +- tests/_passport/test_encryptedcredentials.py | 2 +- tests/_passport/test_encryptedpassportelement.py | 2 +- tests/_passport/test_no_passport.py | 2 +- tests/_passport/test_passport.py | 2 +- tests/_passport/test_passportelementerrordatafield.py | 2 +- tests/_passport/test_passportelementerrorfile.py | 2 +- tests/_passport/test_passportelementerrorfiles.py | 2 +- tests/_passport/test_passportelementerrorfrontside.py | 2 +- tests/_passport/test_passportelementerrorreverseside.py | 2 +- tests/_passport/test_passportelementerrorselfie.py | 2 +- tests/_passport/test_passportelementerrortranslationfile.py | 2 +- tests/_passport/test_passportelementerrortranslationfiles.py | 2 +- tests/_passport/test_passportelementerrorunspecified.py | 2 +- tests/_passport/test_passportfile.py | 2 +- tests/_payment/__init__.py | 2 +- tests/_payment/test_invoice.py | 2 +- tests/_payment/test_labeledprice.py | 2 +- tests/_payment/test_orderinfo.py | 2 +- tests/_payment/test_precheckoutquery.py | 2 +- tests/_payment/test_shippingaddress.py | 2 +- tests/_payment/test_shippingoption.py | 2 +- tests/_payment/test_shippingquery.py | 2 +- tests/_payment/test_successfulpayment.py | 2 +- tests/_utils/__init__.py | 2 +- tests/_utils/test_datetime.py | 2 +- tests/_utils/test_defaultvalue.py | 2 +- tests/_utils/test_files.py | 2 +- tests/auxil/__init__.py | 2 +- tests/auxil/asyncio_helpers.py | 2 +- tests/auxil/bot_method_checks.py | 2 +- tests/auxil/build_messages.py | 2 +- tests/auxil/ci_bots.py | 2 +- tests/auxil/constants.py | 2 +- tests/auxil/envvars.py | 2 +- tests/auxil/files.py | 2 +- tests/auxil/networking.py | 2 +- tests/auxil/pytest_classes.py | 2 +- tests/auxil/slots.py | 2 +- tests/auxil/timezones.py | 2 +- tests/conftest.py | 2 +- tests/docs/admonition_inserter.py | 2 +- tests/ext/__init__.py | 2 +- tests/ext/_utils/__init__.py | 2 +- tests/ext/_utils/test_stack.py | 2 +- tests/ext/_utils/test_trackingdict.py | 2 +- tests/ext/test_application.py | 2 +- tests/ext/test_applicationbuilder.py | 2 +- tests/ext/test_basehandler.py | 2 +- tests/ext/test_basepersistence.py | 2 +- tests/ext/test_baseupdateprocessor.py | 2 +- tests/ext/test_callbackcontext.py | 2 +- tests/ext/test_callbackdatacache.py | 2 +- tests/ext/test_callbackqueryhandler.py | 2 +- tests/ext/test_chatjoinrequesthandler.py | 2 +- tests/ext/test_chatmemberhandler.py | 2 +- tests/ext/test_choseninlineresulthandler.py | 2 +- tests/ext/test_commandhandler.py | 2 +- tests/ext/test_contexttypes.py | 2 +- tests/ext/test_conversationhandler.py | 2 +- tests/ext/test_defaults.py | 2 +- tests/ext/test_dictpersistence.py | 2 +- tests/ext/test_filters.py | 2 +- tests/ext/test_jobqueue.py | 2 +- tests/ext/test_messagehandler.py | 2 +- tests/ext/test_messagereactionhandler.py | 2 +- tests/ext/test_picklepersistence.py | 2 +- tests/ext/test_pollanswerhandler.py | 2 +- tests/ext/test_precheckoutqueryhandler.py | 2 +- tests/ext/test_prefixhandler.py | 2 +- tests/ext/test_ratelimiter.py | 2 +- tests/ext/test_shippingqueryhandler.py | 2 +- tests/ext/test_stringcommandhandler.py | 2 +- tests/ext/test_stringregexhandler.py | 2 +- tests/ext/test_typehandler.py | 2 +- tests/ext/test_updater.py | 2 +- tests/request/__init__.py | 2 +- tests/request/test_request.py | 2 +- tests/request/test_requestdata.py | 2 +- tests/request/test_requestparameter.py | 2 +- tests/test_bot.py | 2 +- tests/test_botcommand.py | 2 +- tests/test_botcommandscope.py | 2 +- tests/test_botdescription.py | 2 +- tests/test_botname.py | 2 +- tests/test_callbackquery.py | 2 +- tests/test_chat.py | 2 +- tests/test_chatadministratorrights.py | 2 +- tests/test_chatinvitelink.py | 2 +- tests/test_chatjoinrequest.py | 2 +- tests/test_chatlocation.py | 2 +- tests/test_chatmember.py | 2 +- tests/test_chatmemberupdated.py | 2 +- tests/test_chatpermissions.py | 2 +- tests/test_choseninlineresult.py | 2 +- tests/test_constants.py | 2 +- tests/test_dice.py | 2 +- tests/test_enum_types.py | 2 +- tests/test_error.py | 2 +- tests/test_forcereply.py | 2 +- tests/test_forum.py | 2 +- tests/test_giveaway.py | 2 +- tests/test_helpers.py | 2 +- tests/test_inlinequeryresultsbutton.py | 2 +- tests/test_keyboardbutton.py | 2 +- tests/test_keyboardbuttonpolltype.py | 2 +- tests/test_keyboardbuttonrequest.py | 2 +- tests/test_loginurl.py | 2 +- tests/test_maybeinaccessiblemessage.py | 2 +- tests/test_menubutton.py | 2 +- tests/test_message.py | 2 +- tests/test_messageautodeletetimerchanged.py | 2 +- tests/test_messageentity.py | 2 +- tests/test_messageid.py | 2 +- tests/test_messageorigin.py | 2 +- tests/test_meta.py | 2 +- tests/test_modules.py | 2 +- tests/test_poll.py | 2 +- tests/test_pollhandler.py | 2 +- tests/test_proximityalerttriggered.py | 2 +- tests/test_reaction.py | 2 +- tests/test_reply.py | 2 +- tests/test_replykeyboardmarkup.py | 2 +- tests/test_replykeyboardremove.py | 2 +- tests/test_sentwebappmessage.py | 2 +- tests/test_shared.py | 2 +- tests/test_slots.py | 2 +- tests/test_story.py | 2 +- tests/test_switchinlinequerychosenchat.py | 2 +- tests/test_telegramobject.py | 2 +- tests/test_update.py | 2 +- tests/test_user.py | 2 +- tests/test_userprofilephotos.py | 2 +- tests/test_version.py | 2 +- tests/test_videochat.py | 2 +- tests/test_warnings.py | 2 +- tests/test_webappdata.py | 2 +- tests/test_webappinfo.py | 2 +- tests/test_webhookinfo.py | 2 +- tests/test_writeaccessallowed.py | 2 +- 374 files changed, 374 insertions(+), 374 deletions(-) diff --git a/docs/auxil/admonition_inserter.py b/docs/auxil/admonition_inserter.py index b506f8308ea..9b1ddc98a43 100644 --- a/docs/auxil/admonition_inserter.py +++ b/docs/auxil/admonition_inserter.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/docs/auxil/kwargs_insertion.py b/docs/auxil/kwargs_insertion.py index 93b301ba6a1..a67d542f4f8 100644 --- a/docs/auxil/kwargs_insertion.py +++ b/docs/auxil/kwargs_insertion.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/docs/auxil/link_code.py b/docs/auxil/link_code.py index da40cfeb06a..f54479e01f1 100644 --- a/docs/auxil/link_code.py +++ b/docs/auxil/link_code.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/docs/auxil/sphinx_hooks.py b/docs/auxil/sphinx_hooks.py index 3748000f313..c9bd8bbe4fa 100644 --- a/docs/auxil/sphinx_hooks.py +++ b/docs/auxil/sphinx_hooks.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/docs/auxil/tg_const_role.py b/docs/auxil/tg_const_role.py index e5de978b20c..35c8bf3b1dd 100644 --- a/docs/auxil/tg_const_role.py +++ b/docs/auxil/tg_const_role.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/docs/source/conf.py b/docs/source/conf.py index cbbfd7a2928..5d3f3556780 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,7 +13,7 @@ # -- General configuration ------------------------------------------------ # General information about the project. project = "python-telegram-bot" -copyright = "2015-2023, Leandro Toledo" +copyright = "2015-2024, Leandro Toledo" author = "Leandro Toledo" # The version info for the project you're documenting, acts as replacement for diff --git a/telegram/__init__.py b/telegram/__init__.py index 44505e52732..25e357042ee 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/__main__.py b/telegram/__main__.py index 9d64eb11609..7f79dc0278a 100644 --- a/telegram/__main__.py +++ b/telegram/__main__.py @@ -1,7 +1,7 @@ # !/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_bot.py b/telegram/_bot.py index 48165bd9a5f..ffd08eaedae 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -2,7 +2,7 @@ # pylint: disable=no-self-argument, not-callable, no-member, too-many-arguments # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_botcommand.py b/telegram/_botcommand.py index e7fa824ade8..972db7c2402 100644 --- a/telegram/_botcommand.py +++ b/telegram/_botcommand.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_botcommandscope.py b/telegram/_botcommandscope.py index 4f1ac6c4ed2..2cac2f50a5b 100644 --- a/telegram/_botcommandscope.py +++ b/telegram/_botcommandscope.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_botdescription.py b/telegram/_botdescription.py index f920e3624cf..e2a9d36df1d 100644 --- a/telegram/_botdescription.py +++ b/telegram/_botdescription.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_botname.py b/telegram/_botname.py index 510cc2a9d54..2a57ea39f0d 100644 --- a/telegram/_botname.py +++ b/telegram/_botname.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index 66e4ebac54b..6ada8c1507e 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chat.py b/telegram/_chat.py index e9e40ee913d..9839ca0b1f3 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -2,7 +2,7 @@ # pylint: disable=redefined-builtin # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index f0c84eeb5e9..a6ec888ecfe 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatinvitelink.py b/telegram/_chatinvitelink.py index c245ca8a51c..18799d9028a 100644 --- a/telegram/_chatinvitelink.py +++ b/telegram/_chatinvitelink.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatjoinrequest.py b/telegram/_chatjoinrequest.py index 89f0c833c50..4d6fdf88581 100644 --- a/telegram/_chatjoinrequest.py +++ b/telegram/_chatjoinrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatlocation.py b/telegram/_chatlocation.py index 648d44c6868..3a3c561fc07 100644 --- a/telegram/_chatlocation.py +++ b/telegram/_chatlocation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index d385b8bf7b6..301130b7d79 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatmemberupdated.py b/telegram/_chatmemberupdated.py index 33a482b8bd5..7d5ee556be7 100644 --- a/telegram/_chatmemberupdated.py +++ b/telegram/_chatmemberupdated.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_chatpermissions.py b/telegram/_chatpermissions.py index 35bae8546c8..1bda731072e 100644 --- a/telegram/_chatpermissions.py +++ b/telegram/_chatpermissions.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_choseninlineresult.py b/telegram/_choseninlineresult.py index 62616a0b5d1..bef8fbb3164 100644 --- a/telegram/_choseninlineresult.py +++ b/telegram/_choseninlineresult.py @@ -2,7 +2,7 @@ # pylint: disable=too-many-arguments # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_dice.py b/telegram/_dice.py index 43fcbb5fbe0..621e4b13f98 100644 --- a/telegram/_dice.py +++ b/telegram/_dice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/_basemedium.py b/telegram/_files/_basemedium.py index c8bbbd333cc..4decb041206 100644 --- a/telegram/_files/_basemedium.py +++ b/telegram/_files/_basemedium.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/_basethumbedmedium.py b/telegram/_files/_basethumbedmedium.py index 0c7491f149d..6212e38f69a 100644 --- a/telegram/_files/_basethumbedmedium.py +++ b/telegram/_files/_basethumbedmedium.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/animation.py b/telegram/_files/animation.py index ab596039e03..3459e642778 100644 --- a/telegram/_files/animation.py +++ b/telegram/_files/animation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/audio.py b/telegram/_files/audio.py index 79c23bab1f0..bf5eb123d00 100644 --- a/telegram/_files/audio.py +++ b/telegram/_files/audio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/chatphoto.py b/telegram/_files/chatphoto.py index 3f77036a95a..ace7f9666f2 100644 --- a/telegram/_files/chatphoto.py +++ b/telegram/_files/chatphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/contact.py b/telegram/_files/contact.py index 1210e1347a0..113b11dc8d0 100644 --- a/telegram/_files/contact.py +++ b/telegram/_files/contact.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/document.py b/telegram/_files/document.py index 101c9400bf3..a281ffefeaf 100644 --- a/telegram/_files/document.py +++ b/telegram/_files/document.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/file.py b/telegram/_files/file.py index dd8ed7e9ec9..c9b8d22d49a 100644 --- a/telegram/_files/file.py +++ b/telegram/_files/file.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/inputfile.py b/telegram/_files/inputfile.py index 91ea229b8fd..994135bb5dd 100644 --- a/telegram/_files/inputfile.py +++ b/telegram/_files/inputfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/inputmedia.py b/telegram/_files/inputmedia.py index f0b73232f4d..163b3a62a2f 100644 --- a/telegram/_files/inputmedia.py +++ b/telegram/_files/inputmedia.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/inputsticker.py b/telegram/_files/inputsticker.py index d37629230b9..bfcd89300a2 100644 --- a/telegram/_files/inputsticker.py +++ b/telegram/_files/inputsticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/location.py b/telegram/_files/location.py index 4d32e34e1e7..45401868720 100644 --- a/telegram/_files/location.py +++ b/telegram/_files/location.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/photosize.py b/telegram/_files/photosize.py index 077a963c6fc..e8c8b699ac3 100644 --- a/telegram/_files/photosize.py +++ b/telegram/_files/photosize.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/sticker.py b/telegram/_files/sticker.py index 504951f9fcd..cb7b5deac0b 100644 --- a/telegram/_files/sticker.py +++ b/telegram/_files/sticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/venue.py b/telegram/_files/venue.py index 412e384a33f..caf60355533 100644 --- a/telegram/_files/venue.py +++ b/telegram/_files/venue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/video.py b/telegram/_files/video.py index 583a8895362..d28138c75e1 100644 --- a/telegram/_files/video.py +++ b/telegram/_files/video.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/videonote.py b/telegram/_files/videonote.py index 931292161be..2a1f760c1d5 100644 --- a/telegram/_files/videonote.py +++ b/telegram/_files/videonote.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_files/voice.py b/telegram/_files/voice.py index 155b4fd58b7..6c1f4dfb289 100644 --- a/telegram/_files/voice.py +++ b/telegram/_files/voice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_forcereply.py b/telegram/_forcereply.py index 61466f6107e..a5f0debaee5 100644 --- a/telegram/_forcereply.py +++ b/telegram/_forcereply.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_forumtopic.py b/telegram/_forumtopic.py index 5938b5d7ac7..bd66e40d053 100644 --- a/telegram/_forumtopic.py +++ b/telegram/_forumtopic.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_games/callbackgame.py b/telegram/_games/callbackgame.py index 20b788920e1..878816b0194 100644 --- a/telegram/_games/callbackgame.py +++ b/telegram/_games/callbackgame.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_games/game.py b/telegram/_games/game.py index 43cd4dbed2d..8eff71a0a61 100644 --- a/telegram/_games/game.py +++ b/telegram/_games/game.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_games/gamehighscore.py b/telegram/_games/gamehighscore.py index 482b2b991fd..991255fe1d5 100644 --- a/telegram/_games/gamehighscore.py +++ b/telegram/_games/gamehighscore.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_giveaway.py b/telegram/_giveaway.py index aa0ee400454..3251898031d 100644 --- a/telegram/_giveaway.py +++ b/telegram/_giveaway.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinekeyboardbutton.py b/telegram/_inline/inlinekeyboardbutton.py index c7479ab6a6f..0b5c75a5c45 100644 --- a/telegram/_inline/inlinekeyboardbutton.py +++ b/telegram/_inline/inlinekeyboardbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinekeyboardmarkup.py b/telegram/_inline/inlinekeyboardmarkup.py index 78b04fec755..c806318246a 100644 --- a/telegram/_inline/inlinekeyboardmarkup.py +++ b/telegram/_inline/inlinekeyboardmarkup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequery.py b/telegram/_inline/inlinequery.py index 53c3a4db424..cc9044beb18 100644 --- a/telegram/_inline/inlinequery.py +++ b/telegram/_inline/inlinequery.py @@ -2,7 +2,7 @@ # pylint: disable=too-many-arguments # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresult.py b/telegram/_inline/inlinequeryresult.py index 4a358e04b62..534d255c305 100644 --- a/telegram/_inline/inlinequeryresult.py +++ b/telegram/_inline/inlinequeryresult.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultarticle.py b/telegram/_inline/inlinequeryresultarticle.py index 583b4a4dd0c..92c358e77ef 100644 --- a/telegram/_inline/inlinequeryresultarticle.py +++ b/telegram/_inline/inlinequeryresultarticle.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultaudio.py b/telegram/_inline/inlinequeryresultaudio.py index cb92b58ad00..69353967adc 100644 --- a/telegram/_inline/inlinequeryresultaudio.py +++ b/telegram/_inline/inlinequeryresultaudio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedaudio.py b/telegram/_inline/inlinequeryresultcachedaudio.py index e3766423a53..2fb7cdbb54d 100644 --- a/telegram/_inline/inlinequeryresultcachedaudio.py +++ b/telegram/_inline/inlinequeryresultcachedaudio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcacheddocument.py b/telegram/_inline/inlinequeryresultcacheddocument.py index bd01263c6e4..b5416c2748c 100644 --- a/telegram/_inline/inlinequeryresultcacheddocument.py +++ b/telegram/_inline/inlinequeryresultcacheddocument.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedgif.py b/telegram/_inline/inlinequeryresultcachedgif.py index 9941aa35165..ca7188014ca 100644 --- a/telegram/_inline/inlinequeryresultcachedgif.py +++ b/telegram/_inline/inlinequeryresultcachedgif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedmpeg4gif.py b/telegram/_inline/inlinequeryresultcachedmpeg4gif.py index caa95f6cf76..f689734b80e 100644 --- a/telegram/_inline/inlinequeryresultcachedmpeg4gif.py +++ b/telegram/_inline/inlinequeryresultcachedmpeg4gif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedphoto.py b/telegram/_inline/inlinequeryresultcachedphoto.py index 60c93cc5107..be484e280dd 100644 --- a/telegram/_inline/inlinequeryresultcachedphoto.py +++ b/telegram/_inline/inlinequeryresultcachedphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedsticker.py b/telegram/_inline/inlinequeryresultcachedsticker.py index 5886c6ebb5b..8e8d22544ca 100644 --- a/telegram/_inline/inlinequeryresultcachedsticker.py +++ b/telegram/_inline/inlinequeryresultcachedsticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedvideo.py b/telegram/_inline/inlinequeryresultcachedvideo.py index 2892b8a8f15..e226d0e4f75 100644 --- a/telegram/_inline/inlinequeryresultcachedvideo.py +++ b/telegram/_inline/inlinequeryresultcachedvideo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcachedvoice.py b/telegram/_inline/inlinequeryresultcachedvoice.py index a4290c5f6aa..dc8bd2ad3a6 100644 --- a/telegram/_inline/inlinequeryresultcachedvoice.py +++ b/telegram/_inline/inlinequeryresultcachedvoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultcontact.py b/telegram/_inline/inlinequeryresultcontact.py index ac8e90e8687..faff47454d3 100644 --- a/telegram/_inline/inlinequeryresultcontact.py +++ b/telegram/_inline/inlinequeryresultcontact.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultdocument.py b/telegram/_inline/inlinequeryresultdocument.py index 115bf7080bb..e0380440b20 100644 --- a/telegram/_inline/inlinequeryresultdocument.py +++ b/telegram/_inline/inlinequeryresultdocument.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultgame.py b/telegram/_inline/inlinequeryresultgame.py index 13c0991860c..aeb78c0f1b4 100644 --- a/telegram/_inline/inlinequeryresultgame.py +++ b/telegram/_inline/inlinequeryresultgame.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultgif.py b/telegram/_inline/inlinequeryresultgif.py index 87e62bfae3c..1a889a1bb04 100644 --- a/telegram/_inline/inlinequeryresultgif.py +++ b/telegram/_inline/inlinequeryresultgif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultlocation.py b/telegram/_inline/inlinequeryresultlocation.py index 8712a90799c..0c370ee8a74 100644 --- a/telegram/_inline/inlinequeryresultlocation.py +++ b/telegram/_inline/inlinequeryresultlocation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultmpeg4gif.py b/telegram/_inline/inlinequeryresultmpeg4gif.py index f3662c24483..a744a040010 100644 --- a/telegram/_inline/inlinequeryresultmpeg4gif.py +++ b/telegram/_inline/inlinequeryresultmpeg4gif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultphoto.py b/telegram/_inline/inlinequeryresultphoto.py index 56d6e0244cc..5eef1acf66f 100644 --- a/telegram/_inline/inlinequeryresultphoto.py +++ b/telegram/_inline/inlinequeryresultphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultsbutton.py b/telegram/_inline/inlinequeryresultsbutton.py index 747c85df423..da850340cac 100644 --- a/telegram/_inline/inlinequeryresultsbutton.py +++ b/telegram/_inline/inlinequeryresultsbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultvenue.py b/telegram/_inline/inlinequeryresultvenue.py index ae46af0f3c5..60af4024f86 100644 --- a/telegram/_inline/inlinequeryresultvenue.py +++ b/telegram/_inline/inlinequeryresultvenue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultvideo.py b/telegram/_inline/inlinequeryresultvideo.py index 50e90a3a18b..90134c450b0 100644 --- a/telegram/_inline/inlinequeryresultvideo.py +++ b/telegram/_inline/inlinequeryresultvideo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inlinequeryresultvoice.py b/telegram/_inline/inlinequeryresultvoice.py index 1d6f96ee279..d33f31b34d8 100644 --- a/telegram/_inline/inlinequeryresultvoice.py +++ b/telegram/_inline/inlinequeryresultvoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputcontactmessagecontent.py b/telegram/_inline/inputcontactmessagecontent.py index b73c0c566ef..4060232bbed 100644 --- a/telegram/_inline/inputcontactmessagecontent.py +++ b/telegram/_inline/inputcontactmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputinvoicemessagecontent.py b/telegram/_inline/inputinvoicemessagecontent.py index cab2d33153b..64b9ff93b55 100644 --- a/telegram/_inline/inputinvoicemessagecontent.py +++ b/telegram/_inline/inputinvoicemessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputlocationmessagecontent.py b/telegram/_inline/inputlocationmessagecontent.py index e549426b604..22cb2d9ef62 100644 --- a/telegram/_inline/inputlocationmessagecontent.py +++ b/telegram/_inline/inputlocationmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputmessagecontent.py b/telegram/_inline/inputmessagecontent.py index e4e26a39834..40088f5a439 100644 --- a/telegram/_inline/inputmessagecontent.py +++ b/telegram/_inline/inputmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 1a9207864e2..969eae7de90 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_inline/inputvenuemessagecontent.py b/telegram/_inline/inputvenuemessagecontent.py index 9c83dd39881..016969b2256 100644 --- a/telegram/_inline/inputvenuemessagecontent.py +++ b/telegram/_inline/inputvenuemessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_keyboardbutton.py b/telegram/_keyboardbutton.py index 0c526b74ae8..0231290e209 100644 --- a/telegram/_keyboardbutton.py +++ b/telegram/_keyboardbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_keyboardbuttonpolltype.py b/telegram/_keyboardbuttonpolltype.py index d5ea851ca0b..f3b987a7fc0 100644 --- a/telegram/_keyboardbuttonpolltype.py +++ b/telegram/_keyboardbuttonpolltype.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_keyboardbuttonrequest.py b/telegram/_keyboardbuttonrequest.py index e06d5c0f780..96968112c82 100644 --- a/telegram/_keyboardbuttonrequest.py +++ b/telegram/_keyboardbuttonrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_loginurl.py b/telegram/_loginurl.py index 01133efaea6..4201b7ab50f 100644 --- a/telegram/_loginurl.py +++ b/telegram/_loginurl.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_menubutton.py b/telegram/_menubutton.py index 26690f8ed6f..2044fb551fe 100644 --- a/telegram/_menubutton.py +++ b/telegram/_menubutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_message.py b/telegram/_message.py index 5c896b83483..2d324287af5 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -2,7 +2,7 @@ # pylint: disable=too-many-instance-attributes, too-many-arguments # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_messageautodeletetimerchanged.py b/telegram/_messageautodeletetimerchanged.py index 9a96b93c868..0d9f136d9f0 100644 --- a/telegram/_messageautodeletetimerchanged.py +++ b/telegram/_messageautodeletetimerchanged.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_messageentity.py b/telegram/_messageentity.py index 10f1e0291c6..f6e0ba6edfe 100644 --- a/telegram/_messageentity.py +++ b/telegram/_messageentity.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_messageid.py b/telegram/_messageid.py index 2ad575f18cf..bbfedf47037 100644 --- a/telegram/_messageid.py +++ b/telegram/_messageid.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/credentials.py b/telegram/_passport/credentials.py index 8dd12428902..bc48077b516 100644 --- a/telegram/_passport/credentials.py +++ b/telegram/_passport/credentials.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/data.py b/telegram/_passport/data.py index 6465c969999..49d194a2631 100644 --- a/telegram/_passport/data.py +++ b/telegram/_passport/data.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/encryptedpassportelement.py b/telegram/_passport/encryptedpassportelement.py index bae6f0e1b4a..46b7ac15fb2 100644 --- a/telegram/_passport/encryptedpassportelement.py +++ b/telegram/_passport/encryptedpassportelement.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # flake8: noqa: E501 # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/passportdata.py b/telegram/_passport/passportdata.py index 7e19ff13689..0dae4ba68c8 100644 --- a/telegram/_passport/passportdata.py +++ b/telegram/_passport/passportdata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/passportelementerrors.py b/telegram/_passport/passportelementerrors.py index 49b30e88b5b..0692c98f314 100644 --- a/telegram/_passport/passportelementerrors.py +++ b/telegram/_passport/passportelementerrors.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_passport/passportfile.py b/telegram/_passport/passportfile.py index 3f5ccc30422..3d37910629c 100644 --- a/telegram/_passport/passportfile.py +++ b/telegram/_passport/passportfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/invoice.py b/telegram/_payment/invoice.py index 4a2d4229eae..04878424698 100644 --- a/telegram/_payment/invoice.py +++ b/telegram/_payment/invoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/labeledprice.py b/telegram/_payment/labeledprice.py index 454c9da4315..b668931b9d4 100644 --- a/telegram/_payment/labeledprice.py +++ b/telegram/_payment/labeledprice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/orderinfo.py b/telegram/_payment/orderinfo.py index 32b6642dd0e..b3a41b54345 100644 --- a/telegram/_payment/orderinfo.py +++ b/telegram/_payment/orderinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/precheckoutquery.py b/telegram/_payment/precheckoutquery.py index 92b98408462..4e7127eea07 100644 --- a/telegram/_payment/precheckoutquery.py +++ b/telegram/_payment/precheckoutquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/shippingaddress.py b/telegram/_payment/shippingaddress.py index 5642cb879a1..6153d34fb95 100644 --- a/telegram/_payment/shippingaddress.py +++ b/telegram/_payment/shippingaddress.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/shippingoption.py b/telegram/_payment/shippingoption.py index 1753da52b0e..15047a00b1f 100644 --- a/telegram/_payment/shippingoption.py +++ b/telegram/_payment/shippingoption.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/shippingquery.py b/telegram/_payment/shippingquery.py index 20651e3513a..ab7e5a1b2f4 100644 --- a/telegram/_payment/shippingquery.py +++ b/telegram/_payment/shippingquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_payment/successfulpayment.py b/telegram/_payment/successfulpayment.py index 9875318a691..737ad841e55 100644 --- a/telegram/_payment/successfulpayment.py +++ b/telegram/_payment/successfulpayment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_poll.py b/telegram/_poll.py index 84a29ec97bf..7c1a65204a4 100644 --- a/telegram/_poll.py +++ b/telegram/_poll.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_proximityalerttriggered.py b/telegram/_proximityalerttriggered.py index 3f09c7c827c..dd05c1ddd95 100644 --- a/telegram/_proximityalerttriggered.py +++ b/telegram/_proximityalerttriggered.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_reaction.py b/telegram/_reaction.py index 36a330f19d4..60bdbebc489 100644 --- a/telegram/_reaction.py +++ b/telegram/_reaction.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_reply.py b/telegram/_reply.py index 2788aa5936e..c77e33ddbe9 100644 --- a/telegram/_reply.py +++ b/telegram/_reply.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_replykeyboardmarkup.py b/telegram/_replykeyboardmarkup.py index a9b379d5f66..dfc0640d27a 100644 --- a/telegram/_replykeyboardmarkup.py +++ b/telegram/_replykeyboardmarkup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_replykeyboardremove.py b/telegram/_replykeyboardremove.py index cae4b97799c..92fc464e4c5 100644 --- a/telegram/_replykeyboardremove.py +++ b/telegram/_replykeyboardremove.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_sentwebappmessage.py b/telegram/_sentwebappmessage.py index 395d12cfe28..28ae55f7516 100644 --- a/telegram/_sentwebappmessage.py +++ b/telegram/_sentwebappmessage.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_shared.py b/telegram/_shared.py index f062ea4a7be..671c83b8fe2 100644 --- a/telegram/_shared.py +++ b/telegram/_shared.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_story.py b/telegram/_story.py index 7a1db0a3697..cdf6dd6ad11 100644 --- a/telegram/_story.py +++ b/telegram/_story.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_switchinlinequerychosenchat.py b/telegram/_switchinlinequerychosenchat.py index 3d6e875dd61..631dbd6798a 100644 --- a/telegram/_switchinlinequerychosenchat.py +++ b/telegram/_switchinlinequerychosenchat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_telegramobject.py b/telegram/_telegramobject.py index 0f26ada7600..772863efd61 100644 --- a/telegram/_telegramobject.py +++ b/telegram/_telegramobject.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_update.py b/telegram/_update.py index df7bd621907..566ca9cfd3f 100644 --- a/telegram/_update.py +++ b/telegram/_update.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_user.py b/telegram/_user.py index 5f6e251f578..2acaa658cda 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -2,7 +2,7 @@ # pylint: disable=redefined-builtin # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_userprofilephotos.py b/telegram/_userprofilephotos.py index 60aa926053f..36e260da9f2 100644 --- a/telegram/_userprofilephotos.py +++ b/telegram/_userprofilephotos.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/argumentparsing.py b/telegram/_utils/argumentparsing.py index b7232d7faa5..cfd1877a685 100644 --- a/telegram/_utils/argumentparsing.py +++ b/telegram/_utils/argumentparsing.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/datetime.py b/telegram/_utils/datetime.py index 70df6b8a6c3..9790e27857d 100644 --- a/telegram/_utils/datetime.py +++ b/telegram/_utils/datetime.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/defaultvalue.py b/telegram/_utils/defaultvalue.py index a79b5629872..7f5df64652a 100644 --- a/telegram/_utils/defaultvalue.py +++ b/telegram/_utils/defaultvalue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/enum.py b/telegram/_utils/enum.py index 8795d97dbe8..20a045c02fe 100644 --- a/telegram/_utils/enum.py +++ b/telegram/_utils/enum.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/files.py b/telegram/_utils/files.py index 21f68106ee7..387743025ee 100644 --- a/telegram/_utils/files.py +++ b/telegram/_utils/files.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/logging.py b/telegram/_utils/logging.py index da888cc83aa..d8b17d82d45 100644 --- a/telegram/_utils/logging.py +++ b/telegram/_utils/logging.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/markup.py b/telegram/_utils/markup.py index 2a79d9bac3d..0531bfd5bd0 100644 --- a/telegram/_utils/markup.py +++ b/telegram/_utils/markup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/repr.py b/telegram/_utils/repr.py index 2792580689a..39881b6ceea 100644 --- a/telegram/_utils/repr.py +++ b/telegram/_utils/repr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/strings.py b/telegram/_utils/strings.py index 62e1cf0ef5b..dc044e86420 100644 --- a/telegram/_utils/strings.py +++ b/telegram/_utils/strings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/types.py b/telegram/_utils/types.py index 046a72dfc74..efde2807f2b 100644 --- a/telegram/_utils/types.py +++ b/telegram/_utils/types.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/warnings.py b/telegram/_utils/warnings.py index aa9d5e4c552..d81f4e79234 100644 --- a/telegram/_utils/warnings.py +++ b/telegram/_utils/warnings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_utils/warnings_transition.py b/telegram/_utils/warnings_transition.py index b4e56d600d1..5d844546b9d 100644 --- a/telegram/_utils/warnings_transition.py +++ b/telegram/_utils/warnings_transition.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_version.py b/telegram/_version.py index d94de6e4ae4..89211499cb4 100644 --- a/telegram/_version.py +++ b/telegram/_version.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_videochat.py b/telegram/_videochat.py index ae854ae9103..3e5027c99fd 100644 --- a/telegram/_videochat.py +++ b/telegram/_videochat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_webappdata.py b/telegram/_webappdata.py index b3ad9001c75..50b68d3460b 100644 --- a/telegram/_webappdata.py +++ b/telegram/_webappdata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_webappinfo.py b/telegram/_webappinfo.py index 46fd8f53b5d..c5452ab0adb 100644 --- a/telegram/_webappinfo.py +++ b/telegram/_webappinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_webhookinfo.py b/telegram/_webhookinfo.py index a31667c3c88..c1b049b7109 100644 --- a/telegram/_webhookinfo.py +++ b/telegram/_webhookinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/_writeaccessallowed.py b/telegram/_writeaccessallowed.py index 52378f799c9..0169cb6e7a0 100644 --- a/telegram/_writeaccessallowed.py +++ b/telegram/_writeaccessallowed.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/constants.py b/telegram/constants.py index 59ba4b73e3c..d78dd8280a7 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -1,5 +1,5 @@ # python-telegram-bot - a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # by the python-telegram-bot contributors # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/error.py b/telegram/error.py index a67cdd828aa..6dcc509a8d4 100644 --- a/telegram/error.py +++ b/telegram/error.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/__init__.py b/telegram/ext/__init__.py index 00c132d8df4..d1101bcf21c 100644 --- a/telegram/ext/__init__.py +++ b/telegram/ext/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_aioratelimiter.py b/telegram/ext/_aioratelimiter.py index 92bc9b7e45a..ac9c4f3f79b 100644 --- a/telegram/ext/_aioratelimiter.py +++ b/telegram/ext/_aioratelimiter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index 8a1e0e52839..4f951741dc0 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_applicationbuilder.py b/telegram/ext/_applicationbuilder.py index b4ab583abd7..71c4bd31286 100644 --- a/telegram/ext/_applicationbuilder.py +++ b/telegram/ext/_applicationbuilder.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_basepersistence.py b/telegram/ext/_basepersistence.py index 782c6c7bb8c..dafd352340c 100644 --- a/telegram/ext/_basepersistence.py +++ b/telegram/ext/_basepersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_baseratelimiter.py b/telegram/ext/_baseratelimiter.py index cef939cbfc4..3d7a6afb1e5 100644 --- a/telegram/ext/_baseratelimiter.py +++ b/telegram/ext/_baseratelimiter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_baseupdateprocessor.py b/telegram/ext/_baseupdateprocessor.py index 79eadaa1426..7bcca890edf 100644 --- a/telegram/ext/_baseupdateprocessor.py +++ b/telegram/ext/_baseupdateprocessor.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_callbackcontext.py b/telegram/ext/_callbackcontext.py index ad68caac8c7..65abe7d520e 100644 --- a/telegram/ext/_callbackcontext.py +++ b/telegram/ext/_callbackcontext.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_callbackdatacache.py b/telegram/ext/_callbackdatacache.py index 5e5b28ac86d..893150b480d 100644 --- a/telegram/ext/_callbackdatacache.py +++ b/telegram/ext/_callbackdatacache.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_contexttypes.py b/telegram/ext/_contexttypes.py index 7644658dee3..ea1065112cb 100644 --- a/telegram/ext/_contexttypes.py +++ b/telegram/ext/_contexttypes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_defaults.py b/telegram/ext/_defaults.py index 2455ed05856..f277a4b0e61 100644 --- a/telegram/ext/_defaults.py +++ b/telegram/ext/_defaults.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_dictpersistence.py b/telegram/ext/_dictpersistence.py index 13a2eb6d402..d046561a253 100644 --- a/telegram/ext/_dictpersistence.py +++ b/telegram/ext/_dictpersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index 1b6e4fcdc73..2dd5abfe17f 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -2,7 +2,7 @@ # pylint: disable=too-many-arguments # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/basehandler.py b/telegram/ext/_handlers/basehandler.py index 5cbe309f832..ea0d9b1640f 100644 --- a/telegram/ext/_handlers/basehandler.py +++ b/telegram/ext/_handlers/basehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/callbackqueryhandler.py b/telegram/ext/_handlers/callbackqueryhandler.py index 0ca5068d77b..2fb79b567d3 100644 --- a/telegram/ext/_handlers/callbackqueryhandler.py +++ b/telegram/ext/_handlers/callbackqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/chatjoinrequesthandler.py b/telegram/ext/_handlers/chatjoinrequesthandler.py index 79ebdccc4b9..9e4f3a011af 100644 --- a/telegram/ext/_handlers/chatjoinrequesthandler.py +++ b/telegram/ext/_handlers/chatjoinrequesthandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/chatmemberhandler.py b/telegram/ext/_handlers/chatmemberhandler.py index a5c5c0d8b7d..87232d84261 100644 --- a/telegram/ext/_handlers/chatmemberhandler.py +++ b/telegram/ext/_handlers/chatmemberhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/choseninlineresulthandler.py b/telegram/ext/_handlers/choseninlineresulthandler.py index f97c582345d..9191ad250f2 100644 --- a/telegram/ext/_handlers/choseninlineresulthandler.py +++ b/telegram/ext/_handlers/choseninlineresulthandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/commandhandler.py b/telegram/ext/_handlers/commandhandler.py index a6644d39ddd..b509918d797 100644 --- a/telegram/ext/_handlers/commandhandler.py +++ b/telegram/ext/_handlers/commandhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/conversationhandler.py b/telegram/ext/_handlers/conversationhandler.py index 64216a4889f..3c7dcc767c6 100644 --- a/telegram/ext/_handlers/conversationhandler.py +++ b/telegram/ext/_handlers/conversationhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/inlinequeryhandler.py b/telegram/ext/_handlers/inlinequeryhandler.py index f501fbbee75..1db74fb28bc 100644 --- a/telegram/ext/_handlers/inlinequeryhandler.py +++ b/telegram/ext/_handlers/inlinequeryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/messagehandler.py b/telegram/ext/_handlers/messagehandler.py index 15f589165da..fab4422fe77 100644 --- a/telegram/ext/_handlers/messagehandler.py +++ b/telegram/ext/_handlers/messagehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/messagereactionhandler.py b/telegram/ext/_handlers/messagereactionhandler.py index 0fc028b5b27..4b52a17a8ab 100644 --- a/telegram/ext/_handlers/messagereactionhandler.py +++ b/telegram/ext/_handlers/messagereactionhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/pollanswerhandler.py b/telegram/ext/_handlers/pollanswerhandler.py index ea30d645d76..91e8df82b70 100644 --- a/telegram/ext/_handlers/pollanswerhandler.py +++ b/telegram/ext/_handlers/pollanswerhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/pollhandler.py b/telegram/ext/_handlers/pollhandler.py index 2aac563dc1e..fb183c53805 100644 --- a/telegram/ext/_handlers/pollhandler.py +++ b/telegram/ext/_handlers/pollhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/precheckoutqueryhandler.py b/telegram/ext/_handlers/precheckoutqueryhandler.py index 0a55a140765..3c6f3f186df 100644 --- a/telegram/ext/_handlers/precheckoutqueryhandler.py +++ b/telegram/ext/_handlers/precheckoutqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/prefixhandler.py b/telegram/ext/_handlers/prefixhandler.py index e4f2c0e90d8..00a9ff1964e 100644 --- a/telegram/ext/_handlers/prefixhandler.py +++ b/telegram/ext/_handlers/prefixhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/shippingqueryhandler.py b/telegram/ext/_handlers/shippingqueryhandler.py index f84077a788a..f0234c2a962 100644 --- a/telegram/ext/_handlers/shippingqueryhandler.py +++ b/telegram/ext/_handlers/shippingqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/stringcommandhandler.py b/telegram/ext/_handlers/stringcommandhandler.py index ae099566e85..2fa085899a1 100644 --- a/telegram/ext/_handlers/stringcommandhandler.py +++ b/telegram/ext/_handlers/stringcommandhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/stringregexhandler.py b/telegram/ext/_handlers/stringregexhandler.py index 9a7d51a4896..2eeb2b4d08e 100644 --- a/telegram/ext/_handlers/stringregexhandler.py +++ b/telegram/ext/_handlers/stringregexhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_handlers/typehandler.py b/telegram/ext/_handlers/typehandler.py index 50125abdc8e..ac195b8982a 100644 --- a/telegram/ext/_handlers/typehandler.py +++ b/telegram/ext/_handlers/typehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_jobqueue.py b/telegram/ext/_jobqueue.py index 1b358cc27f3..940a80bb462 100644 --- a/telegram/ext/_jobqueue.py +++ b/telegram/ext/_jobqueue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_picklepersistence.py b/telegram/ext/_picklepersistence.py index fff11fc6c75..adc8220af48 100644 --- a/telegram/ext/_picklepersistence.py +++ b/telegram/ext/_picklepersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 14b9a0b93b8..24f2bc04588 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/__init__.py b/telegram/ext/_utils/__init__.py index c422adbe4e8..ea85ad53711 100644 --- a/telegram/ext/_utils/__init__.py +++ b/telegram/ext/_utils/__init__.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/_update_parsing.py b/telegram/ext/_utils/_update_parsing.py index 8f32d04e3ff..f74c35e8c45 100644 --- a/telegram/ext/_utils/_update_parsing.py +++ b/telegram/ext/_utils/_update_parsing.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/stack.py b/telegram/ext/_utils/stack.py index a8fb3c3dd1e..6ade607567a 100644 --- a/telegram/ext/_utils/stack.py +++ b/telegram/ext/_utils/stack.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/trackingdict.py b/telegram/ext/_utils/trackingdict.py index 28c7ef89a59..682cd648613 100644 --- a/telegram/ext/_utils/trackingdict.py +++ b/telegram/ext/_utils/trackingdict.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/types.py b/telegram/ext/_utils/types.py index 12a64ff9206..5f9fc083218 100644 --- a/telegram/ext/_utils/types.py +++ b/telegram/ext/_utils/types.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/_utils/webhookhandler.py b/telegram/ext/_utils/webhookhandler.py index 0d16b10054f..f630ec94185 100644 --- a/telegram/ext/_utils/webhookhandler.py +++ b/telegram/ext/_utils/webhookhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index e4bba593b9e..28bc595cf7a 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/helpers.py b/telegram/helpers.py index 91d7937ac74..d303b64a78b 100644 --- a/telegram/helpers.py +++ b/telegram/helpers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/request/__init__.py b/telegram/request/__init__.py index 72b57d9b825..5e6a44631be 100644 --- a/telegram/request/__init__.py +++ b/telegram/request/__init__.py @@ -1,6 +1,6 @@ # !/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/request/_baserequest.py b/telegram/request/_baserequest.py index fadf9299929..cc8b73706a0 100644 --- a/telegram/request/_baserequest.py +++ b/telegram/request/_baserequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/request/_httpxrequest.py b/telegram/request/_httpxrequest.py index 6b86783ddef..7ca54c5c534 100644 --- a/telegram/request/_httpxrequest.py +++ b/telegram/request/_httpxrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/request/_requestdata.py b/telegram/request/_requestdata.py index b48c05da9e5..658a445649d 100644 --- a/telegram/request/_requestdata.py +++ b/telegram/request/_requestdata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/request/_requestparameter.py b/telegram/request/_requestparameter.py index f71f5bacfe3..6b16a5cae66 100644 --- a/telegram/request/_requestparameter.py +++ b/telegram/request/_requestparameter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/telegram/warnings.py b/telegram/warnings.py index 5be2aabc632..5ff74191a70 100644 --- a/telegram/warnings.py +++ b/telegram/warnings.py @@ -1,6 +1,6 @@ #! /usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/__init__.py b/tests/_files/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_files/__init__.py +++ b/tests/_files/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_animation.py b/tests/_files/test_animation.py index b35c509d1bb..ba35fb700eb 100644 --- a/tests/_files/test_animation.py +++ b/tests/_files/test_animation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_audio.py b/tests/_files/test_audio.py index 9a19ea1524e..4e7b8cc0504 100644 --- a/tests/_files/test_audio.py +++ b/tests/_files/test_audio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_chatphoto.py b/tests/_files/test_chatphoto.py index d09876e28ea..ea853fd6b4f 100644 --- a/tests/_files/test_chatphoto.py +++ b/tests/_files/test_chatphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_contact.py b/tests/_files/test_contact.py index b8fa54da851..539dcfad9c6 100644 --- a/tests/_files/test_contact.py +++ b/tests/_files/test_contact.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_document.py b/tests/_files/test_document.py index 76236ae2eaa..a1c63fd0e82 100644 --- a/tests/_files/test_document.py +++ b/tests/_files/test_document.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_file.py b/tests/_files/test_file.py index 7b3a47c3c2c..86979e4181c 100644 --- a/tests/_files/test_file.py +++ b/tests/_files/test_file.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_inputfile.py b/tests/_files/test_inputfile.py index c772192dfae..2a2a3b60734 100644 --- a/tests/_files/test_inputfile.py +++ b/tests/_files/test_inputfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_inputmedia.py b/tests/_files/test_inputmedia.py index 066958681c2..72d981f7bf2 100644 --- a/tests/_files/test_inputmedia.py +++ b/tests/_files/test_inputmedia.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_inputsticker.py b/tests/_files/test_inputsticker.py index 780a7fbbac3..c974853f268 100644 --- a/tests/_files/test_inputsticker.py +++ b/tests/_files/test_inputsticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_location.py b/tests/_files/test_location.py index 59e881969b8..44d96ffe57f 100644 --- a/tests/_files/test_location.py +++ b/tests/_files/test_location.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_photo.py b/tests/_files/test_photo.py index ec3fbf59a7b..267b414274b 100644 --- a/tests/_files/test_photo.py +++ b/tests/_files/test_photo.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_sticker.py b/tests/_files/test_sticker.py index c11141acdfb..86a2da710c0 100644 --- a/tests/_files/test_sticker.py +++ b/tests/_files/test_sticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_venue.py b/tests/_files/test_venue.py index 2ae53c5a6a7..85a950bf81e 100644 --- a/tests/_files/test_venue.py +++ b/tests/_files/test_venue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_video.py b/tests/_files/test_video.py index 8e1d985d03b..59b49c3d925 100644 --- a/tests/_files/test_video.py +++ b/tests/_files/test_video.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_videonote.py b/tests/_files/test_videonote.py index c4cf5437389..d9f66ae6e25 100644 --- a/tests/_files/test_videonote.py +++ b/tests/_files/test_videonote.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_files/test_voice.py b/tests/_files/test_voice.py index 2cf9af77191..cc85e8bdab5 100644 --- a/tests/_files/test_voice.py +++ b/tests/_files/test_voice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_games/__init__.py b/tests/_games/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_games/__init__.py +++ b/tests/_games/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_games/test_game.py b/tests/_games/test_game.py index d9f686a1841..49067a8009a 100644 --- a/tests/_games/test_game.py +++ b/tests/_games/test_game.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_games/test_gamehighscore.py b/tests/_games/test_gamehighscore.py index 3ca03ef4498..02738be2123 100644 --- a/tests/_games/test_gamehighscore.py +++ b/tests/_games/test_gamehighscore.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/__init__.py b/tests/_inline/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_inline/__init__.py +++ b/tests/_inline/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinekeyboardbutton.py b/tests/_inline/test_inlinekeyboardbutton.py index 96cf4c15331..9eb1eff49cf 100644 --- a/tests/_inline/test_inlinekeyboardbutton.py +++ b/tests/_inline/test_inlinekeyboardbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinekeyboardmarkup.py b/tests/_inline/test_inlinekeyboardmarkup.py index 3e67e4db22d..d7e8700dd6d 100644 --- a/tests/_inline/test_inlinekeyboardmarkup.py +++ b/tests/_inline/test_inlinekeyboardmarkup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequery.py b/tests/_inline/test_inlinequery.py index c03cb5efe3d..e5c8562c528 100644 --- a/tests/_inline/test_inlinequery.py +++ b/tests/_inline/test_inlinequery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryhandler.py b/tests/_inline/test_inlinequeryhandler.py index 0e50666a477..556cea46492 100644 --- a/tests/_inline/test_inlinequeryhandler.py +++ b/tests/_inline/test_inlinequeryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultarticle.py b/tests/_inline/test_inlinequeryresultarticle.py index 74ae376ec9a..4bc56c92d80 100644 --- a/tests/_inline/test_inlinequeryresultarticle.py +++ b/tests/_inline/test_inlinequeryresultarticle.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultaudio.py b/tests/_inline/test_inlinequeryresultaudio.py index e1331d6900b..33542787ed8 100644 --- a/tests/_inline/test_inlinequeryresultaudio.py +++ b/tests/_inline/test_inlinequeryresultaudio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedaudio.py b/tests/_inline/test_inlinequeryresultcachedaudio.py index 3896fe6dc79..efa0cb06e27 100644 --- a/tests/_inline/test_inlinequeryresultcachedaudio.py +++ b/tests/_inline/test_inlinequeryresultcachedaudio.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcacheddocument.py b/tests/_inline/test_inlinequeryresultcacheddocument.py index 3b4477b4da4..48c9eef252b 100644 --- a/tests/_inline/test_inlinequeryresultcacheddocument.py +++ b/tests/_inline/test_inlinequeryresultcacheddocument.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedgif.py b/tests/_inline/test_inlinequeryresultcachedgif.py index 9a2e7db00c8..d1a3fcdb85f 100644 --- a/tests/_inline/test_inlinequeryresultcachedgif.py +++ b/tests/_inline/test_inlinequeryresultcachedgif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedmpeg4gif.py b/tests/_inline/test_inlinequeryresultcachedmpeg4gif.py index 52ccbf64701..770b9d5c50c 100644 --- a/tests/_inline/test_inlinequeryresultcachedmpeg4gif.py +++ b/tests/_inline/test_inlinequeryresultcachedmpeg4gif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedphoto.py b/tests/_inline/test_inlinequeryresultcachedphoto.py index 0b4e422548d..02b8df1562d 100644 --- a/tests/_inline/test_inlinequeryresultcachedphoto.py +++ b/tests/_inline/test_inlinequeryresultcachedphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedsticker.py b/tests/_inline/test_inlinequeryresultcachedsticker.py index deded624d06..63b7f2425fd 100644 --- a/tests/_inline/test_inlinequeryresultcachedsticker.py +++ b/tests/_inline/test_inlinequeryresultcachedsticker.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedvideo.py b/tests/_inline/test_inlinequeryresultcachedvideo.py index 5609032f9c0..fd108551b5d 100644 --- a/tests/_inline/test_inlinequeryresultcachedvideo.py +++ b/tests/_inline/test_inlinequeryresultcachedvideo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcachedvoice.py b/tests/_inline/test_inlinequeryresultcachedvoice.py index 79746a7525b..de6810b2b58 100644 --- a/tests/_inline/test_inlinequeryresultcachedvoice.py +++ b/tests/_inline/test_inlinequeryresultcachedvoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultcontact.py b/tests/_inline/test_inlinequeryresultcontact.py index f231e163b07..4b691f3801b 100644 --- a/tests/_inline/test_inlinequeryresultcontact.py +++ b/tests/_inline/test_inlinequeryresultcontact.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultdocument.py b/tests/_inline/test_inlinequeryresultdocument.py index ea7b8c30a1a..aacf9d85860 100644 --- a/tests/_inline/test_inlinequeryresultdocument.py +++ b/tests/_inline/test_inlinequeryresultdocument.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultgame.py b/tests/_inline/test_inlinequeryresultgame.py index 0e5ca9269a9..8a72ae401e5 100644 --- a/tests/_inline/test_inlinequeryresultgame.py +++ b/tests/_inline/test_inlinequeryresultgame.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultgif.py b/tests/_inline/test_inlinequeryresultgif.py index 43da739620d..abb3a936fd7 100644 --- a/tests/_inline/test_inlinequeryresultgif.py +++ b/tests/_inline/test_inlinequeryresultgif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultlocation.py b/tests/_inline/test_inlinequeryresultlocation.py index 79c4532a3be..2f5023d5144 100644 --- a/tests/_inline/test_inlinequeryresultlocation.py +++ b/tests/_inline/test_inlinequeryresultlocation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultmpeg4gif.py b/tests/_inline/test_inlinequeryresultmpeg4gif.py index 4dd5e6e819b..cd211bd4c2d 100644 --- a/tests/_inline/test_inlinequeryresultmpeg4gif.py +++ b/tests/_inline/test_inlinequeryresultmpeg4gif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultphoto.py b/tests/_inline/test_inlinequeryresultphoto.py index 8d86123ff83..3078353ca97 100644 --- a/tests/_inline/test_inlinequeryresultphoto.py +++ b/tests/_inline/test_inlinequeryresultphoto.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultvenue.py b/tests/_inline/test_inlinequeryresultvenue.py index 69a1e4a6827..ba09ad7d180 100644 --- a/tests/_inline/test_inlinequeryresultvenue.py +++ b/tests/_inline/test_inlinequeryresultvenue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultvideo.py b/tests/_inline/test_inlinequeryresultvideo.py index dc2a08c7731..40664af1992 100644 --- a/tests/_inline/test_inlinequeryresultvideo.py +++ b/tests/_inline/test_inlinequeryresultvideo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inlinequeryresultvoice.py b/tests/_inline/test_inlinequeryresultvoice.py index cbfb7e9f01d..34ea013cb60 100644 --- a/tests/_inline/test_inlinequeryresultvoice.py +++ b/tests/_inline/test_inlinequeryresultvoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inputcontactmessagecontent.py b/tests/_inline/test_inputcontactmessagecontent.py index 0f5d8d11d61..5a48f7dc5cc 100644 --- a/tests/_inline/test_inputcontactmessagecontent.py +++ b/tests/_inline/test_inputcontactmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inputinvoicemessagecontent.py b/tests/_inline/test_inputinvoicemessagecontent.py index 1503fc96731..577ba677599 100644 --- a/tests/_inline/test_inputinvoicemessagecontent.py +++ b/tests/_inline/test_inputinvoicemessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inputlocationmessagecontent.py b/tests/_inline/test_inputlocationmessagecontent.py index 0bfb1f4cffb..61d311cae38 100644 --- a/tests/_inline/test_inputlocationmessagecontent.py +++ b/tests/_inline/test_inputlocationmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inputtextmessagecontent.py b/tests/_inline/test_inputtextmessagecontent.py index 052df0bbfa9..4f1db4043cf 100644 --- a/tests/_inline/test_inputtextmessagecontent.py +++ b/tests/_inline/test_inputtextmessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_inline/test_inputvenuemessagecontent.py b/tests/_inline/test_inputvenuemessagecontent.py index f54ac4cb0d2..8c9d4c62d10 100644 --- a/tests/_inline/test_inputvenuemessagecontent.py +++ b/tests/_inline/test_inputvenuemessagecontent.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/__init__.py b/tests/_passport/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_passport/__init__.py +++ b/tests/_passport/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_encryptedcredentials.py b/tests/_passport/test_encryptedcredentials.py index e80424396a2..3b45ee157c3 100644 --- a/tests/_passport/test_encryptedcredentials.py +++ b/tests/_passport/test_encryptedcredentials.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_encryptedpassportelement.py b/tests/_passport/test_encryptedpassportelement.py index e2b05a74669..f1299029017 100644 --- a/tests/_passport/test_encryptedpassportelement.py +++ b/tests/_passport/test_encryptedpassportelement.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_no_passport.py b/tests/_passport/test_no_passport.py index 8fa4b092534..8b1af252cb3 100644 --- a/tests/_passport/test_no_passport.py +++ b/tests/_passport/test_no_passport.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passport.py b/tests/_passport/test_passport.py index 15951010d8e..c35eeaf1761 100644 --- a/tests/_passport/test_passport.py +++ b/tests/_passport/test_passport.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # flake8: noqa: E501 # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrordatafield.py b/tests/_passport/test_passportelementerrordatafield.py index 40db20fc2f0..0d49359a3fa 100644 --- a/tests/_passport/test_passportelementerrordatafield.py +++ b/tests/_passport/test_passportelementerrordatafield.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorfile.py b/tests/_passport/test_passportelementerrorfile.py index be96a7a20e0..ef892b183ff 100644 --- a/tests/_passport/test_passportelementerrorfile.py +++ b/tests/_passport/test_passportelementerrorfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorfiles.py b/tests/_passport/test_passportelementerrorfiles.py index 73737516f1d..43ee7cb5da8 100644 --- a/tests/_passport/test_passportelementerrorfiles.py +++ b/tests/_passport/test_passportelementerrorfiles.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorfrontside.py b/tests/_passport/test_passportelementerrorfrontside.py index f7cb3942dc2..6a29052d319 100644 --- a/tests/_passport/test_passportelementerrorfrontside.py +++ b/tests/_passport/test_passportelementerrorfrontside.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorreverseside.py b/tests/_passport/test_passportelementerrorreverseside.py index 9e29dc4a353..bda4cd73167 100644 --- a/tests/_passport/test_passportelementerrorreverseside.py +++ b/tests/_passport/test_passportelementerrorreverseside.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorselfie.py b/tests/_passport/test_passportelementerrorselfie.py index 1e22b1b0b05..9580e24ae74 100644 --- a/tests/_passport/test_passportelementerrorselfie.py +++ b/tests/_passport/test_passportelementerrorselfie.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrortranslationfile.py b/tests/_passport/test_passportelementerrortranslationfile.py index 189ba6159a0..f55a8ad7017 100644 --- a/tests/_passport/test_passportelementerrortranslationfile.py +++ b/tests/_passport/test_passportelementerrortranslationfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrortranslationfiles.py b/tests/_passport/test_passportelementerrortranslationfiles.py index 58196e713fc..eb62aa5d1d7 100644 --- a/tests/_passport/test_passportelementerrortranslationfiles.py +++ b/tests/_passport/test_passportelementerrortranslationfiles.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportelementerrorunspecified.py b/tests/_passport/test_passportelementerrorunspecified.py index 97612f600c5..260192e18c6 100644 --- a/tests/_passport/test_passportelementerrorunspecified.py +++ b/tests/_passport/test_passportelementerrorunspecified.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_passport/test_passportfile.py b/tests/_passport/test_passportfile.py index 7ec9fc41b7b..d12e0ce9f11 100644 --- a/tests/_passport/test_passportfile.py +++ b/tests/_passport/test_passportfile.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/__init__.py b/tests/_payment/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_payment/__init__.py +++ b/tests/_payment/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_invoice.py b/tests/_payment/test_invoice.py index 6bf290906d2..bdbc56a0403 100644 --- a/tests/_payment/test_invoice.py +++ b/tests/_payment/test_invoice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_labeledprice.py b/tests/_payment/test_labeledprice.py index a7c14d4fbe8..c05672de3c5 100644 --- a/tests/_payment/test_labeledprice.py +++ b/tests/_payment/test_labeledprice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_orderinfo.py b/tests/_payment/test_orderinfo.py index bcfc9dd2495..a8a01fb5e27 100644 --- a/tests/_payment/test_orderinfo.py +++ b/tests/_payment/test_orderinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_precheckoutquery.py b/tests/_payment/test_precheckoutquery.py index 0fd0e103ebf..57637187df5 100644 --- a/tests/_payment/test_precheckoutquery.py +++ b/tests/_payment/test_precheckoutquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_shippingaddress.py b/tests/_payment/test_shippingaddress.py index 271539b3130..ee69fded956 100644 --- a/tests/_payment/test_shippingaddress.py +++ b/tests/_payment/test_shippingaddress.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_shippingoption.py b/tests/_payment/test_shippingoption.py index be09d9ce204..cc969879056 100644 --- a/tests/_payment/test_shippingoption.py +++ b/tests/_payment/test_shippingoption.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_shippingquery.py b/tests/_payment/test_shippingquery.py index ba405eb084a..bf8fc820d17 100644 --- a/tests/_payment/test_shippingquery.py +++ b/tests/_payment/test_shippingquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_payment/test_successfulpayment.py b/tests/_payment/test_successfulpayment.py index a2bc81f169a..a0de91198c7 100644 --- a/tests/_payment/test_successfulpayment.py +++ b/tests/_payment/test_successfulpayment.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_utils/__init__.py b/tests/_utils/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/_utils/__init__.py +++ b/tests/_utils/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_utils/test_datetime.py b/tests/_utils/test_datetime.py index ca89390bcf3..7ef28468839 100644 --- a/tests/_utils/test_datetime.py +++ b/tests/_utils/test_datetime.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_utils/test_defaultvalue.py b/tests/_utils/test_defaultvalue.py index 04d72614fb6..64d1ba90c25 100644 --- a/tests/_utils/test_defaultvalue.py +++ b/tests/_utils/test_defaultvalue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/_utils/test_files.py b/tests/_utils/test_files.py index 977567d85dd..196b81f8df8 100644 --- a/tests/_utils/test_files.py +++ b/tests/_utils/test_files.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/__init__.py b/tests/auxil/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/auxil/__init__.py +++ b/tests/auxil/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/asyncio_helpers.py b/tests/auxil/asyncio_helpers.py index a9fbfb103de..7d2458ca873 100644 --- a/tests/auxil/asyncio_helpers.py +++ b/tests/auxil/asyncio_helpers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/bot_method_checks.py b/tests/auxil/bot_method_checks.py index 396516f216d..ff838bae588 100644 --- a/tests/auxil/bot_method_checks.py +++ b/tests/auxil/bot_method_checks.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/build_messages.py b/tests/auxil/build_messages.py index 9e9ef288714..69370977efb 100644 --- a/tests/auxil/build_messages.py +++ b/tests/auxil/build_messages.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/ci_bots.py b/tests/auxil/ci_bots.py index b1561433450..bfad962b811 100644 --- a/tests/auxil/ci_bots.py +++ b/tests/auxil/ci_bots.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/constants.py b/tests/auxil/constants.py index 602e6ef8edc..8ec314bfbe5 100644 --- a/tests/auxil/constants.py +++ b/tests/auxil/constants.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/envvars.py b/tests/auxil/envvars.py index 5a3de55ec80..1b360e5d551 100644 --- a/tests/auxil/envvars.py +++ b/tests/auxil/envvars.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/files.py b/tests/auxil/files.py index 486686c0f94..6b1f87eacff 100644 --- a/tests/auxil/files.py +++ b/tests/auxil/files.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/networking.py b/tests/auxil/networking.py index 9966fb32977..2284f31fc50 100644 --- a/tests/auxil/networking.py +++ b/tests/auxil/networking.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/pytest_classes.py b/tests/auxil/pytest_classes.py index 52f0e59ad27..5586a8ea0b7 100644 --- a/tests/auxil/pytest_classes.py +++ b/tests/auxil/pytest_classes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/slots.py b/tests/auxil/slots.py index 0d05dd0c9ca..d04f2b001a0 100644 --- a/tests/auxil/slots.py +++ b/tests/auxil/slots.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/auxil/timezones.py b/tests/auxil/timezones.py index 34e42afeeab..2b87dd89499 100644 --- a/tests/auxil/timezones.py +++ b/tests/auxil/timezones.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/conftest.py b/tests/conftest.py index 689d816bb49..c7e816672ae 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/docs/admonition_inserter.py b/tests/docs/admonition_inserter.py index 2ef684ffe40..fa19d9a0f9d 100644 --- a/tests/docs/admonition_inserter.py +++ b/tests/docs/admonition_inserter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/__init__.py b/tests/ext/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/ext/__init__.py +++ b/tests/ext/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/_utils/__init__.py b/tests/ext/_utils/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/ext/_utils/__init__.py +++ b/tests/ext/_utils/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/_utils/test_stack.py b/tests/ext/_utils/test_stack.py index 13305b5029d..5867fa49a20 100644 --- a/tests/ext/_utils/test_stack.py +++ b/tests/ext/_utils/test_stack.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/_utils/test_trackingdict.py b/tests/ext/_utils/test_trackingdict.py index 5ed327c7161..5ddf3d371b3 100644 --- a/tests/ext/_utils/test_trackingdict.py +++ b/tests/ext/_utils/test_trackingdict.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_application.py b/tests/ext/test_application.py index a51ea46e2a9..3f80bc40bb2 100644 --- a/tests/ext/test_application.py +++ b/tests/ext/test_application.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_applicationbuilder.py b/tests/ext/test_applicationbuilder.py index b2a38bd9196..89990601bc5 100644 --- a/tests/ext/test_applicationbuilder.py +++ b/tests/ext/test_applicationbuilder.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_basehandler.py b/tests/ext/test_basehandler.py index c61258266f0..8bc1ae35a37 100644 --- a/tests/ext/test_basehandler.py +++ b/tests/ext/test_basehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_basepersistence.py b/tests/ext/test_basepersistence.py index 04c7e819eec..fb61e79bb55 100644 --- a/tests/ext/test_basepersistence.py +++ b/tests/ext/test_basepersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_baseupdateprocessor.py b/tests/ext/test_baseupdateprocessor.py index 3ae10d2dd16..de36ea4aa38 100644 --- a/tests/ext/test_baseupdateprocessor.py +++ b/tests/ext/test_baseupdateprocessor.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_callbackcontext.py b/tests/ext/test_callbackcontext.py index 2ccb785fafd..ed4f014b2b2 100644 --- a/tests/ext/test_callbackcontext.py +++ b/tests/ext/test_callbackcontext.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_callbackdatacache.py b/tests/ext/test_callbackdatacache.py index c1bc1645dc9..be7fbace0a5 100644 --- a/tests/ext/test_callbackdatacache.py +++ b/tests/ext/test_callbackdatacache.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_callbackqueryhandler.py b/tests/ext/test_callbackqueryhandler.py index f150f778f05..65b5589c041 100644 --- a/tests/ext/test_callbackqueryhandler.py +++ b/tests/ext/test_callbackqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_chatjoinrequesthandler.py b/tests/ext/test_chatjoinrequesthandler.py index bc359a6c1d5..3d2e38f4483 100644 --- a/tests/ext/test_chatjoinrequesthandler.py +++ b/tests/ext/test_chatjoinrequesthandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_chatmemberhandler.py b/tests/ext/test_chatmemberhandler.py index 45f16eb35d8..9182b2a1124 100644 --- a/tests/ext/test_chatmemberhandler.py +++ b/tests/ext/test_chatmemberhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_choseninlineresulthandler.py b/tests/ext/test_choseninlineresulthandler.py index 83c98667187..6d51c1447e5 100644 --- a/tests/ext/test_choseninlineresulthandler.py +++ b/tests/ext/test_choseninlineresulthandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_commandhandler.py b/tests/ext/test_commandhandler.py index c9780e3e338..4e0e11d4159 100644 --- a/tests/ext/test_commandhandler.py +++ b/tests/ext/test_commandhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_contexttypes.py b/tests/ext/test_contexttypes.py index 907209b3c1b..afe73bb21d4 100644 --- a/tests/ext/test_contexttypes.py +++ b/tests/ext/test_contexttypes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_conversationhandler.py b/tests/ext/test_conversationhandler.py index 72f67895177..ebf1dfe2ebb 100644 --- a/tests/ext/test_conversationhandler.py +++ b/tests/ext/test_conversationhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_defaults.py b/tests/ext/test_defaults.py index 52f32587821..abc00aa61ad 100644 --- a/tests/ext/test_defaults.py +++ b/tests/ext/test_defaults.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_dictpersistence.py b/tests/ext/test_dictpersistence.py index b74db2d55f0..ecd004858a4 100644 --- a/tests/ext/test_dictpersistence.py +++ b/tests/ext/test_dictpersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_filters.py b/tests/ext/test_filters.py index bc848a17a19..39914085cf1 100644 --- a/tests/ext/test_filters.py +++ b/tests/ext/test_filters.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_jobqueue.py b/tests/ext/test_jobqueue.py index 7da673bc3f9..458fc4cc4f9 100644 --- a/tests/ext/test_jobqueue.py +++ b/tests/ext/test_jobqueue.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_messagehandler.py b/tests/ext/test_messagehandler.py index e521c6ac86e..62129cea58d 100644 --- a/tests/ext/test_messagehandler.py +++ b/tests/ext/test_messagehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_messagereactionhandler.py b/tests/ext/test_messagereactionhandler.py index afeaa9c1d49..8f4172c9e34 100644 --- a/tests/ext/test_messagereactionhandler.py +++ b/tests/ext/test_messagereactionhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_picklepersistence.py b/tests/ext/test_picklepersistence.py index a8fba1555fd..86a26eeb3ba 100644 --- a/tests/ext/test_picklepersistence.py +++ b/tests/ext/test_picklepersistence.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_pollanswerhandler.py b/tests/ext/test_pollanswerhandler.py index 7b27868a714..d36b38d226e 100644 --- a/tests/ext/test_pollanswerhandler.py +++ b/tests/ext/test_pollanswerhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_precheckoutqueryhandler.py b/tests/ext/test_precheckoutqueryhandler.py index 37ba8ba1dbe..9e40737cf50 100644 --- a/tests/ext/test_precheckoutqueryhandler.py +++ b/tests/ext/test_precheckoutqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_prefixhandler.py b/tests/ext/test_prefixhandler.py index 65c8a412c24..b0d75b06951 100644 --- a/tests/ext/test_prefixhandler.py +++ b/tests/ext/test_prefixhandler.py @@ -1,6 +1,6 @@ # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_ratelimiter.py b/tests/ext/test_ratelimiter.py index e2c949ce143..4b0e9ed4d3f 100644 --- a/tests/ext/test_ratelimiter.py +++ b/tests/ext/test_ratelimiter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_shippingqueryhandler.py b/tests/ext/test_shippingqueryhandler.py index 2d8b3bb801e..1832b191f13 100644 --- a/tests/ext/test_shippingqueryhandler.py +++ b/tests/ext/test_shippingqueryhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_stringcommandhandler.py b/tests/ext/test_stringcommandhandler.py index 6d8f9d77bdb..493304242bd 100644 --- a/tests/ext/test_stringcommandhandler.py +++ b/tests/ext/test_stringcommandhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_stringregexhandler.py b/tests/ext/test_stringregexhandler.py index 208a63cf49b..504325b4a27 100644 --- a/tests/ext/test_stringregexhandler.py +++ b/tests/ext/test_stringregexhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_typehandler.py b/tests/ext/test_typehandler.py index 8b3e6407168..245229c5bac 100644 --- a/tests/ext/test_typehandler.py +++ b/tests/ext/test_typehandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/ext/test_updater.py b/tests/ext/test_updater.py index f4c7a906e28..9e0b7754773 100644 --- a/tests/ext/test_updater.py +++ b/tests/ext/test_updater.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/request/__init__.py b/tests/request/__init__.py index 1eaba12c869..c03255563b4 100644 --- a/tests/request/__init__.py +++ b/tests/request/__init__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/request/test_request.py b/tests/request/test_request.py index 51f3831e9ee..8dddd0e3f7a 100644 --- a/tests/request/test_request.py +++ b/tests/request/test_request.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/request/test_requestdata.py b/tests/request/test_requestdata.py index 733f71d379b..3dc8ca1af97 100644 --- a/tests/request/test_requestdata.py +++ b/tests/request/test_requestdata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/request/test_requestparameter.py b/tests/request/test_requestparameter.py index 2f78e483534..59a3e3f9145 100644 --- a/tests/request/test_requestparameter.py +++ b/tests/request/test_requestparameter.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_bot.py b/tests/test_bot.py index 991d7e534cb..d1357d57826 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_botcommand.py b/tests/test_botcommand.py index 5e8ff724c8e..1e4a360e065 100644 --- a/tests/test_botcommand.py +++ b/tests/test_botcommand.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_botcommandscope.py b/tests/test_botcommandscope.py index 24b7ffda37a..63766b95e17 100644 --- a/tests/test_botcommandscope.py +++ b/tests/test_botcommandscope.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_botdescription.py b/tests/test_botdescription.py index 9ae588f9634..4e84eb558c3 100644 --- a/tests/test_botdescription.py +++ b/tests/test_botdescription.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_botname.py b/tests/test_botname.py index 89d2482ed31..3fadfa76b4b 100644 --- a/tests/test_botname.py +++ b/tests/test_botname.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_callbackquery.py b/tests/test_callbackquery.py index 7f98c9def0d..1db05e4b973 100644 --- a/tests/test_callbackquery.py +++ b/tests/test_callbackquery.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chat.py b/tests/test_chat.py index c6c19828dee..514b5f4e7b0 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatadministratorrights.py b/tests/test_chatadministratorrights.py index 31a69cfeef0..4b49792b098 100644 --- a/tests/test_chatadministratorrights.py +++ b/tests/test_chatadministratorrights.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatinvitelink.py b/tests/test_chatinvitelink.py index 0cbe9b41289..1b95177d9d5 100644 --- a/tests/test_chatinvitelink.py +++ b/tests/test_chatinvitelink.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatjoinrequest.py b/tests/test_chatjoinrequest.py index 3f5d1e4ef4c..3d8b19386de 100644 --- a/tests/test_chatjoinrequest.py +++ b/tests/test_chatjoinrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatlocation.py b/tests/test_chatlocation.py index a7858c637a4..a57d157cce1 100644 --- a/tests/test_chatlocation.py +++ b/tests/test_chatlocation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index 8a09e28b071..643f0e3b018 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatmemberupdated.py b/tests/test_chatmemberupdated.py index f0baf88e038..4e73526d0e0 100644 --- a/tests/test_chatmemberupdated.py +++ b/tests/test_chatmemberupdated.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_chatpermissions.py b/tests/test_chatpermissions.py index 9ba3df5bdd5..9317de22769 100644 --- a/tests/test_chatpermissions.py +++ b/tests/test_chatpermissions.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_choseninlineresult.py b/tests/test_choseninlineresult.py index 0ed4605c99b..d1cb3622649 100644 --- a/tests/test_choseninlineresult.py +++ b/tests/test_choseninlineresult.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_constants.py b/tests/test_constants.py index 8f75f3dfe4c..5055f75795c 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_dice.py b/tests/test_dice.py index 11277912861..53242efa770 100644 --- a/tests/test_dice.py +++ b/tests/test_dice.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_enum_types.py b/tests/test_enum_types.py index 2a236f37324..9e7140ee1df 100644 --- a/tests/test_enum_types.py +++ b/tests/test_enum_types.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_error.py b/tests/test_error.py index 77f0eb209fd..ef6d2ed61bd 100644 --- a/tests/test_error.py +++ b/tests/test_error.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_forcereply.py b/tests/test_forcereply.py index eac3c70c7d8..ca9d7cae5ed 100644 --- a/tests/test_forcereply.py +++ b/tests/test_forcereply.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_forum.py b/tests/test_forum.py index d367fc9c9eb..55419a3854f 100644 --- a/tests/test_forum.py +++ b/tests/test_forum.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_giveaway.py b/tests/test_giveaway.py index 611e098a6c8..35945118363 100644 --- a/tests/test_giveaway.py +++ b/tests/test_giveaway.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 78652d77c72..5a453da716d 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_inlinequeryresultsbutton.py b/tests/test_inlinequeryresultsbutton.py index db87326c556..2c6ad4336c2 100644 --- a/tests/test_inlinequeryresultsbutton.py +++ b/tests/test_inlinequeryresultsbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index 4709ee18cf3..b41239cc057 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_keyboardbuttonpolltype.py b/tests/test_keyboardbuttonpolltype.py index 4732af83bbd..2d4f0dd5b17 100644 --- a/tests/test_keyboardbuttonpolltype.py +++ b/tests/test_keyboardbuttonpolltype.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_keyboardbuttonrequest.py b/tests/test_keyboardbuttonrequest.py index 2a70df2406e..58fa8e7c1bb 100644 --- a/tests/test_keyboardbuttonrequest.py +++ b/tests/test_keyboardbuttonrequest.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_loginurl.py b/tests/test_loginurl.py index 6f22d33ded8..a9f69699b5f 100644 --- a/tests/test_loginurl.py +++ b/tests/test_loginurl.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_maybeinaccessiblemessage.py b/tests/test_maybeinaccessiblemessage.py index 0db8fc75ef3..890ff923f7d 100644 --- a/tests/test_maybeinaccessiblemessage.py +++ b/tests/test_maybeinaccessiblemessage.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_menubutton.py b/tests/test_menubutton.py index 59d0e9ca5e8..bb859a20609 100644 --- a/tests/test_menubutton.py +++ b/tests/test_menubutton.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_message.py b/tests/test_message.py index ae9e79b69c5..232ddfb1be1 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_messageautodeletetimerchanged.py b/tests/test_messageautodeletetimerchanged.py index bc9e02e1886..4628dae5b1b 100644 --- a/tests/test_messageautodeletetimerchanged.py +++ b/tests/test_messageautodeletetimerchanged.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_messageentity.py b/tests/test_messageentity.py index 8162a8a44d4..b14ec79c321 100644 --- a/tests/test_messageentity.py +++ b/tests/test_messageentity.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_messageid.py b/tests/test_messageid.py index efb980de45d..fb7c23fe6e1 100644 --- a/tests/test_messageid.py +++ b/tests/test_messageid.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_messageorigin.py b/tests/test_messageorigin.py index 554cedcc914..1e46fc53c9a 100644 --- a/tests/test_messageorigin.py +++ b/tests/test_messageorigin.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_meta.py b/tests/test_meta.py index 683c6c1e3e0..077f9ae0544 100644 --- a/tests/test_meta.py +++ b/tests/test_meta.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_modules.py b/tests/test_modules.py index 519bdda9545..4d69b6a09af 100644 --- a/tests/test_modules.py +++ b/tests/test_modules.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_poll.py b/tests/test_poll.py index 09133e908cb..5ec4291130b 100644 --- a/tests/test_poll.py +++ b/tests/test_poll.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_pollhandler.py b/tests/test_pollhandler.py index c83a0d41871..52b0675e15d 100644 --- a/tests/test_pollhandler.py +++ b/tests/test_pollhandler.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_proximityalerttriggered.py b/tests/test_proximityalerttriggered.py index 6a1207cf52c..3db91ffbe0b 100644 --- a/tests/test_proximityalerttriggered.py +++ b/tests/test_proximityalerttriggered.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_reaction.py b/tests/test_reaction.py index 1a152347965..30e287ca5e5 100644 --- a/tests/test_reaction.py +++ b/tests/test_reaction.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_reply.py b/tests/test_reply.py index e79725b5e48..4d2c35e8d31 100644 --- a/tests/test_reply.py +++ b/tests/test_reply.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_replykeyboardmarkup.py b/tests/test_replykeyboardmarkup.py index b0f329b983e..15654208d2f 100644 --- a/tests/test_replykeyboardmarkup.py +++ b/tests/test_replykeyboardmarkup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_replykeyboardremove.py b/tests/test_replykeyboardremove.py index 92df80cb143..f1a771e7f4c 100644 --- a/tests/test_replykeyboardremove.py +++ b/tests/test_replykeyboardremove.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_sentwebappmessage.py b/tests/test_sentwebappmessage.py index 59afeaeb252..c523ea09f75 100644 --- a/tests/test_sentwebappmessage.py +++ b/tests/test_sentwebappmessage.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_shared.py b/tests/test_shared.py index 1ea98ac5d20..0e92dcf3603 100644 --- a/tests/test_shared.py +++ b/tests/test_shared.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_slots.py b/tests/test_slots.py index cf257c74882..31a5a7e3312 100644 --- a/tests/test_slots.py +++ b/tests/test_slots.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_story.py b/tests/test_story.py index 2aa9358ad65..99524ec7937 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_switchinlinequerychosenchat.py b/tests/test_switchinlinequerychosenchat.py index dc610e449dc..8a55398606f 100644 --- a/tests/test_switchinlinequerychosenchat.py +++ b/tests/test_switchinlinequerychosenchat.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index 48101724418..a22912d9d24 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_update.py b/tests/test_update.py index 0420df59fa0..7c7a35a4c02 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_user.py b/tests/test_user.py index cdec4f070c9..9edc0db6b53 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_userprofilephotos.py b/tests/test_userprofilephotos.py index 25c9dd8e8df..caff6a2a5a8 100644 --- a/tests/test_userprofilephotos.py +++ b/tests/test_userprofilephotos.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_version.py b/tests/test_version.py index f521bdf38b9..489bde0d6f9 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_videochat.py b/tests/test_videochat.py index a3272c7b03b..5fbdf8ba8eb 100644 --- a/tests/test_videochat.py +++ b/tests/test_videochat.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_warnings.py b/tests/test_warnings.py index 172ee343893..06161d59ffe 100644 --- a/tests/test_warnings.py +++ b/tests/test_warnings.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_webappdata.py b/tests/test_webappdata.py index 3e53e0d276b..5a1a5c3fc02 100644 --- a/tests/test_webappdata.py +++ b/tests/test_webappdata.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_webappinfo.py b/tests/test_webappinfo.py index d40e1531864..b0c8db81704 100644 --- a/tests/test_webappinfo.py +++ b/tests/test_webappinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_webhookinfo.py b/tests/test_webhookinfo.py index acba601ff8a..8075095342a 100644 --- a/tests/test_webhookinfo.py +++ b/tests/test_webhookinfo.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify diff --git a/tests/test_writeaccessallowed.py b/tests/test_writeaccessallowed.py index 6bc45a26769..0f8a0431569 100644 --- a/tests/test_writeaccessallowed.py +++ b/tests/test_writeaccessallowed.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2023 +# Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify From bb6c85609a9aab4f9bb512934bb20eaa83782743 Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sat, 24 Feb 2024 06:31:50 -0500 Subject: [PATCH 03/17] Add Missing Slot to `Updater` (#4130) --- telegram/ext/_updater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 24f2bc04588..70fb650a27f 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -102,6 +102,7 @@ class Updater(AsyncContextManager["Updater"]): __slots__ = ( "__lock", + "__polling_cleanup_cb", "__polling_task", "_httpd", "_initialized", From c513d51147d9afebfc5de6d8af934263b2365471 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:14:26 +0100 Subject: [PATCH 04/17] Update `httpx` requirement from ~=0.26.0 to ~=0.27.0 (#4131) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- README.rst | 2 +- README_RAW.rst | 2 +- requirements.txt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd7bd92422d..890060ec7f0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: name: ruff files: ^(telegram|examples|tests)/.*\.py$ additional_dependencies: - - httpx~=0.26.0 + - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.2 @@ -34,7 +34,7 @@ repos: - id: pylint files: ^(telegram|examples)/.*\.py$ additional_dependencies: - - httpx~=0.26.0 + - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.2 @@ -50,7 +50,7 @@ repos: - types-pytz - types-cryptography - types-cachetools - - httpx~=0.26.0 + - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.2 diff --git a/README.rst b/README.rst index b40ac1331ee..993e7239689 100644 --- a/README.rst +++ b/README.rst @@ -135,7 +135,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n Instead, they are listed as optional dependencies. This allows to avoid unnecessary dependency conflicts for users who don't need the optional features. -The only required dependency is `httpx ~= 0.26.0 `_ for +The only required dependency is `httpx ~= 0.27.0 `_ for ``telegram.request.HTTPXRequest``, the default networking backend. ``python-telegram-bot`` is most useful when used along with additional libraries. diff --git a/README_RAW.rst b/README_RAW.rst index 5c3f7f60dfa..f3428cefbe5 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -136,7 +136,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n Instead, they are listed as optional dependencies. This allows to avoid unnecessary dependency conflicts for users who don't need the optional features. -The only required dependency is `httpx ~= 0.26.0 `_ for +The only required dependency is `httpx ~= 0.27.0 `_ for ``telegram.request.HTTPXRequest``, the default networking backend. ``python-telegram-bot`` is most useful when used along with additional libraries. diff --git a/requirements.txt b/requirements.txt index 5151309fed7..7c24fc990f1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ # versions and only increase the lower bound if necessary # httpx has no stable release yet, so let's be cautious for now -httpx ~= 0.26.0 +httpx ~= 0.27.0 From 277031cfb256933921531403fa70d036f863f459 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 25 Feb 2024 10:34:47 +0100 Subject: [PATCH 05/17] Remove Functionality Deprecated in API 7.0 (#4114) --- docs/source/telegram.at-tree.rst | 2 - .../telegram.keyboardbuttonrequestuser.rst | 6 - docs/source/telegram.usershared.rst | 6 - docs/substitutions/global.rst | 2 +- telegram/__init__.py | 10 +- telegram/_bot.py | 733 +++++++++--------- telegram/_callbackquery.py | 6 +- telegram/_chat.py | 78 +- telegram/_inline/inputtextmessagecontent.py | 56 +- telegram/_keyboardbutton.py | 61 +- telegram/_keyboardbuttonrequest.py | 48 +- telegram/_message.py | 421 ++-------- telegram/_shared.py | 57 +- telegram/_user.py | 78 +- telegram/_utils/argumentparsing.py | 21 + telegram/_utils/warnings_transition.py | 25 - telegram/ext/_extbot.py | 80 +- telegram/ext/filters.py | 16 +- tests/_inline/test_inputtextmessagecontent.py | 12 +- tests/auxil/bot_method_checks.py | 6 +- tests/ext/test_filters.py | 4 +- tests/test_bot.py | 18 +- tests/test_keyboardbutton.py | 54 +- tests/test_keyboardbuttonrequest.py | 31 +- tests/test_maybeinaccessiblemessage.py | 26 +- tests/test_message.py | 156 +--- tests/test_official/exceptions.py | 27 +- tests/test_shared.py | 78 +- 28 files changed, 706 insertions(+), 1412 deletions(-) delete mode 100644 docs/source/telegram.keyboardbuttonrequestuser.rst delete mode 100644 docs/source/telegram.usershared.rst diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index c5159a71e0c..ed71b5f6760 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -73,7 +73,6 @@ Available Types telegram.keyboardbutton telegram.keyboardbuttonpolltype telegram.keyboardbuttonrequestchat - telegram.keyboardbuttonrequestuser telegram.keyboardbuttonrequestusers telegram.linkpreviewoptions telegram.location @@ -115,7 +114,6 @@ Available Types telegram.user telegram.userchatboosts telegram.userprofilephotos - telegram.usershared telegram.usersshared telegram.venue telegram.video diff --git a/docs/source/telegram.keyboardbuttonrequestuser.rst b/docs/source/telegram.keyboardbuttonrequestuser.rst deleted file mode 100644 index 24ebfa758a4..00000000000 --- a/docs/source/telegram.keyboardbuttonrequestuser.rst +++ /dev/null @@ -1,6 +0,0 @@ -KeyboardButtonRequestUser -========================= - -.. autoclass:: telegram.KeyboardButtonRequestUser - :members: - :show-inheritance: diff --git a/docs/source/telegram.usershared.rst b/docs/source/telegram.usershared.rst deleted file mode 100644 index 831c1d9492a..00000000000 --- a/docs/source/telegram.usershared.rst +++ /dev/null @@ -1,6 +0,0 @@ -UserShared -========== - -.. autoclass:: telegram.UserShared - :members: - :show-inheritance: diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 3909c0d51d9..228bd459bac 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -68,7 +68,7 @@ .. |rtm_aswr_deprecated| replace:: replacing this argument. PTB will automatically convert this argument to that one, but you should update your code to use the new argument. -.. |keyword_only_arg| replace:: In future versions, this argument will become a keyword-only argument. +.. |keyword_only_arg| replace:: This argument is now a keyword-only argument. .. |text_html| replace:: The return value of this property is a best-effort approach. Unfortunately, it can not be guaranteed that sending a message with the returned string will render in the same way as the original message produces the same :attr:`~telegram.Message.entities`/:attr:`~telegram.Message.caption_entities` as the original message. For example, Telegram recommends that entities of type :attr:`~telegram.MessageEntity.BLOCKQUOTE` and :attr:`~telegram.MessageEntity.PRE` *should* start and end on a new line, but does not enforce this and leaves rendering decisions up to the clients. diff --git a/telegram/__init__.py b/telegram/__init__.py index 25e357042ee..8e58edb33e8 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -130,7 +130,6 @@ "KeyboardButton", "KeyboardButtonPollType", "KeyboardButtonRequestChat", - "KeyboardButtonRequestUser", "KeyboardButtonRequestUsers", "LabeledPrice", "LinkPreviewOptions", @@ -198,7 +197,6 @@ "User", "UserChatBoosts", "UserProfilePhotos", - "UserShared", "UsersShared", "Venue", "Video", @@ -338,11 +336,7 @@ from ._inline.inputvenuemessagecontent import InputVenueMessageContent from ._keyboardbutton import KeyboardButton from ._keyboardbuttonpolltype import KeyboardButtonPollType -from ._keyboardbuttonrequest import ( - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) +from ._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers from ._linkpreviewoptions import LinkPreviewOptions from ._loginurl import LoginUrl from ._menubutton import MenuButton, MenuButtonCommands, MenuButtonDefault, MenuButtonWebApp @@ -397,7 +391,7 @@ from ._replykeyboardmarkup import ReplyKeyboardMarkup from ._replykeyboardremove import ReplyKeyboardRemove from ._sentwebappmessage import SentWebAppMessage -from ._shared import ChatShared, UserShared, UsersShared +from ._shared import ChatShared, UsersShared from ._story import Story from ._switchinlinequerychosenchat import SwitchInlineQueryChosenChat from ._telegramobject import TelegramObject diff --git a/telegram/_bot.py b/telegram/_bot.py index ffd08eaedae..4ca0ff267b7 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -92,7 +92,7 @@ from telegram._update import Update from telegram._user import User from telegram._userprofilephotos import UserProfilePhotos -from telegram._utils.argumentparsing import parse_sequence_arg +from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue from telegram._utils.files import is_local_file, parse_file_input from telegram._utils.logging import get_logger @@ -100,7 +100,6 @@ from telegram._utils.strings import to_camel_case from telegram._utils.types import CorrectOptionID, FileInput, JSONDict, ODVInput, ReplyMarkup from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import warn_for_link_preview_options from telegram._webhookinfo import WebhookInfo from telegram.constants import InlineQueryLimit, ReactionEmoji from telegram.error import EndPointNotFound, InvalidToken @@ -668,10 +667,8 @@ async def _send_message( self, endpoint: str, data: JSONDict, - reply_to_message_id: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, caption: Optional[str] = None, @@ -680,6 +677,8 @@ async def _send_message( link_preview_options: ODVInput["LinkPreviewOptions"] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -918,19 +917,16 @@ async def send_message( text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, - # Deprecated since Bot API 7.0 (to be made keyword arg): - # --- - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - # --- disable_notification: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -957,49 +953,52 @@ async def send_message( .. versionadded:: 20.8 - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Mutually exclusive with :paramref:`link_preview_options`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`link_preview_options` replacing this - argument. PTB will automatically convert this argument to that one, but - for advanced options, please use :paramref:`link_preview_options` directly. - - .. deprecated:: 20.8 - In future versions, this argument will become a keyword-only argument. - disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| .. versionadded:: 13.10 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.0 + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.0 - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in + this message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`link_preview_options` replacing this + argument. PTB will automatically convert this argument to that one, but + for advanced options, please use :paramref:`link_preview_options` directly. + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent message is returned. @@ -1011,9 +1010,7 @@ async def send_message( """ data: JSONDict = {"chat_id": chat_id, "text": text, "entities": entities} - link_preview_options = warn_for_link_preview_options( - disable_web_page_preview, link_preview_options - ) + link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) return await self._send_message( "sendMessage", @@ -1271,16 +1268,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1326,23 +1323,6 @@ async def send_photo( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1357,6 +1337,24 @@ async def send_photo( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the photo, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1406,16 +1404,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1470,23 +1468,6 @@ async def send_audio( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1501,6 +1482,24 @@ async def send_audio( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the audio, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1550,17 +1549,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1614,23 +1613,6 @@ async def send_document( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -1645,6 +1627,24 @@ async def send_document( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the document, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1689,14 +1689,14 @@ async def send_sticker( chat_id: Union[int, str], sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1734,31 +1734,34 @@ async def send_sticker( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -1797,13 +1800,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1811,6 +1812,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1870,24 +1873,6 @@ async def send_video( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -1905,6 +1890,24 @@ async def send_video( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -1957,14 +1960,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2012,23 +2015,6 @@ async def send_video_note( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -2043,6 +2029,24 @@ async def send_video_note( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video note, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2092,9 +2096,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2102,6 +2104,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2155,24 +2159,6 @@ async def send_animation( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -2190,6 +2176,24 @@ async def send_animation( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the animation, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2241,15 +2245,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2299,27 +2303,10 @@ async def send_voice( disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| - .. versionadded:: 13.10 - message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - - .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + .. versionadded:: 13.10 + message_thread_id (:obj:`int`, optional): |message_thread_id_arg| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.0 reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): @@ -2330,6 +2317,24 @@ async def send_voice( .. versionadded:: 20.8 Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the voice, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the :obj:`tempfile` module. @@ -2377,12 +2382,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2423,29 +2428,30 @@ async def send_media_group( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| caption (:obj:`str`, optional): Caption that will be added to the first element of :paramref:`media`, so that it will be used as caption for the whole media group. @@ -2539,17 +2545,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, location: Optional[Location] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2590,33 +2596,34 @@ async def send_location( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| location (:class:`telegram.Location`, optional): The location to send. Returns: @@ -2820,16 +2827,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, venue: Optional[Venue] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2868,33 +2875,34 @@ async def send_venue( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| venue (:class:`telegram.Venue`, optional): The venue to send. Returns: @@ -2964,14 +2972,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, contact: Optional[Contact] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3000,33 +3008,34 @@ async def send_contact( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - - .. versionadded:: 20.8 + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - Keyword Args: + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| contact (:class:`telegram.Contact`, optional): The contact to send. Returns: @@ -3085,13 +3094,13 @@ async def send_game( chat_id: int, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3111,29 +3120,33 @@ async def send_game( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new + inline keyboard. If empty, one "Play game_title" button will be + shown. If not empty, the first button must launch the game. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for a new - inline keyboard. If empty, one "Play game_title" button will be - shown. If not empty, the first button must launch the game. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -3782,14 +3795,11 @@ async def edit_message_text( message_id: Optional[int] = None, inline_message_id: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - # Deprecated since Bot API 7.0 (to be keyword only): - # --- - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - # --- reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3829,19 +3839,22 @@ async def edit_message_text( .. versionadded:: 20.8 + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an + inline keyboard. + + Keyword Args: disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. Mutually exclusive with :paramref:`link_preview_options`. + this message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`link_preview_options` replacing this argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. deprecated:: 20.8 - In future versions, this argument will become keyword only. + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. Returns: :class:`telegram.Message`: On success, if edited message is not an inline message, the @@ -3861,9 +3874,7 @@ async def edit_message_text( "entities": entities, } - link_preview_options = warn_for_link_preview_options( - disable_web_page_preview, link_preview_options - ) + link_preview_options = parse_lpo_and_dwpp(disable_web_page_preview, link_preview_options) return await self._send_message( "editMessageText", @@ -4777,18 +4788,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -4884,30 +4895,33 @@ async def send_invoice( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an + inline keyboard. If empty, one 'Pay total price' button will be + shown. If not empty, the first button must be a Pay button. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): An object for an - inline keyboard. If empty, one 'Pay total price' button will be - shown. If not empty, the first button must be a Pay button. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -6794,18 +6808,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -6870,30 +6884,34 @@ async def send_poll( message_thread_id (:obj:`int`, optional): |message_thread_id_arg| .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -6986,14 +7004,14 @@ async def send_dice( self, chat_id: Union[int, str], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -7006,15 +7024,6 @@ async def send_dice( Args: chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| disable_notification (:obj:`bool`, optional): |disable_notification| - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): Additional interface options. An object for an inline keyboard, custom reply @@ -7034,15 +7043,6 @@ async def send_dice( .. versionchanged:: 13.4 Added the :tg-const:`telegram.Dice.BOWLING` emoji. - allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - - .. deprecated:: 20.8 - |keyword_only_arg| - protect_content (:obj:`bool`, optional): |protect_content| .. versionadded:: 13.10 @@ -7053,6 +7053,27 @@ async def send_dice( .. versionadded:: 20.8 + Keyword Args: + allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for + + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| + + Returns: :class:`telegram.Message`: On success, the sent Message is returned. @@ -7409,13 +7430,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -7449,31 +7470,33 @@ async def copy_message( .. versionadded:: 20.0 - reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| - Mutually exclusive with :paramref:`reply_parameters`. - - .. versionchanged:: 20.8 - Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| + reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ + :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): + Additional interface options. An object for an inline keyboard, custom reply + keyboard, instructions to remove reply keyboard or to force a reply from the user. + reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| - .. deprecated:: 20.8 - |keyword_only_arg| + .. versionadded:: 20.8 + Keyword Args: allow_sending_without_reply (:obj:`bool`, optional): |allow_sending_without_reply| - Mutually exclusive with :paramref:`reply_parameters`. + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. deprecated:: 20.8 + .. versionchanged:: NEXT.VERSION |keyword_only_arg| + reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| + Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience + parameter for - reply_markup (:class:`InlineKeyboardMarkup` | :class:`ReplyKeyboardMarkup` | \ - :class:`ReplyKeyboardRemove` | :class:`ForceReply`, optional): - Additional interface options. An object for an inline keyboard, custom reply - keyboard, instructions to remove reply keyboard or to force a reply from the user. - reply_parameters (:class:`telegram.ReplyParameters`, optional): |reply_parameters| + .. versionchanged:: 20.8 + Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Returns: :class:`telegram.MessageId`: On success diff --git a/telegram/_callbackquery.py b/telegram/_callbackquery.py index 6ada8c1507e..8fbd0013a4e 100644 --- a/telegram/_callbackquery.py +++ b/telegram/_callbackquery.py @@ -209,11 +209,11 @@ async def edit_message_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -808,13 +808,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: Optional[int] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_chat.py b/telegram/_chat.py index 9839ca0b1f3..e830e83c2f2 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -1411,17 +1411,17 @@ async def send_message( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1529,12 +1529,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1614,16 +1614,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1669,14 +1669,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional["Contact"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1723,16 +1723,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1780,17 +1780,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1834,14 +1834,14 @@ async def send_document( async def send_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1879,13 +1879,13 @@ async def send_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1938,18 +1938,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2018,17 +2018,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional["Location"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2078,9 +2078,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2088,6 +2086,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2135,14 +2135,14 @@ async def send_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2185,16 +2185,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional["Venue"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2243,13 +2243,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2257,6 +2255,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2307,14 +2307,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2359,15 +2359,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2417,18 +2417,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2481,13 +2481,13 @@ async def send_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2535,13 +2535,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 969eae7de90..711393da7bf 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -21,13 +21,9 @@ from telegram._inline.inputmessagecontent import InputMessageContent from telegram._messageentity import MessageEntity -from telegram._utils.argumentparsing import parse_sequence_arg -from telegram._utils.defaultvalue import DEFAULT_NONE, DefaultValue +from telegram._utils.argumentparsing import parse_lpo_and_dwpp, parse_sequence_arg +from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._utils.types import JSONDict, ODVInput -from telegram._utils.warnings_transition import ( - warn_about_deprecated_attr_in_property, - warn_for_link_preview_options, -) if TYPE_CHECKING: from telegram._linkpreviewoptions import LinkPreviewOptions @@ -54,22 +50,24 @@ class InputTextMessageContent(InputMessageContent): .. versionchanged:: 20.0 |sequenceclassargs| + link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation + options for the message. Mutually exclusive with + :paramref:`disable_web_page_preview`. + + .. versionadded:: 20.8 + + Keyword Args: disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the - sent message. Mutually exclusive with :paramref:`link_preview_options`. + sent message. Convenience parameter for setting :paramref:`link_preview_options`. + Mutually exclusive with :paramref:`link_preview_options`. .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`link_preview_options` replacing this argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. deprecated:: 20.8 - In future versions, this argument will become keyword only. - - link_preview_options (:obj:`LinkPreviewOptions`, optional): Link preview generation - options for the message. Mutually exclusive with - :paramref:`disable_web_page_preview`. - - .. versionadded:: 20.8 + .. versionchanged:: NEXT.VERSION + |keyword_only_arg| Attributes: message_text (:obj:`str`): Text of the message to be sent, @@ -84,8 +82,7 @@ class InputTextMessageContent(InputMessageContent): * |tupleclassattrs| * |alwaystuple| link_preview_options (:obj:`LinkPreviewOptions`): Optional. Link preview generation - options for the message. Mutually exclusive with - :attr:`disable_web_page_preview`. + options for the message. .. versionadded:: 20.8 @@ -97,10 +94,10 @@ def __init__( self, message_text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence[MessageEntity]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) @@ -111,27 +108,8 @@ def __init__( # Optionals self.parse_mode: ODVInput[str] = parse_mode self.entities: Tuple[MessageEntity, ...] = parse_sequence_arg(entities) - self.link_preview_options: ODVInput["LinkPreviewOptions"] = ( - warn_for_link_preview_options(disable_web_page_preview, link_preview_options) + self.link_preview_options: ODVInput["LinkPreviewOptions"] = parse_lpo_and_dwpp( + disable_web_page_preview, link_preview_options ) self._id_attrs = (self.message_text,) - - @property - def disable_web_page_preview(self) -> Optional[bool]: - """Optional[:obj:`bool`]: Disables link previews for links in the sent message. - - .. deprecated:: 20.8 - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="disable_web_page_preview", - new_attr_name="link_preview_options", - bot_api_version="7.0", - stacklevel=2, - ) - if ( - isinstance(self.link_preview_options, DefaultValue) - or self.link_preview_options is None - ): - return None - return bool(self.link_preview_options.is_disabled) diff --git a/telegram/_keyboardbutton.py b/telegram/_keyboardbutton.py index 0231290e209..1f0ae352915 100644 --- a/telegram/_keyboardbutton.py +++ b/telegram/_keyboardbutton.py @@ -18,20 +18,12 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram KeyboardButton.""" -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Optional from telegram._keyboardbuttonpolltype import KeyboardButtonPollType -from telegram._keyboardbuttonrequest import ( - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) +from telegram._keyboardbuttonrequest import KeyboardButtonRequestChat, KeyboardButtonRequestUsers from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings_transition import ( - warn_about_deprecated_arg_return_new_arg, - warn_about_deprecated_attr_in_property, -) from telegram._webappinfo import WebAppInfo if TYPE_CHECKING: @@ -60,6 +52,8 @@ class KeyboardButton(TelegramObject): versions released after 3 February, 2023. Older clients will display unsupported message. + .. versionchanged:: NEXT.VERSION + Removed deprecated argument and attribute ``request_user``. .. versionchanged:: 20.0 :attr:`web_app` is considered as well when comparing objects of this type in terms of equality. @@ -83,17 +77,10 @@ class KeyboardButton(TelegramObject): Available in private chats only. .. versionadded:: 20.0 - request_user (:class:`KeyboardButtonRequestUser` | :class:`KeyboardButtonRequestUsers`, \ - optional): Alias for - :attr:`request_users`. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates this argument in favor of ref`request_users`. request_users (:class:`KeyboardButtonRequestUsers`, optional): If specified, pressing the button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.user_shared` service message. + identifier to the bot in a :attr:`telegram.Message.users_shared` service message. Available in private chats only. .. versionadded:: 20.8 @@ -121,7 +108,7 @@ class KeyboardButton(TelegramObject): .. versionadded:: 20.0 request_users (:class:`KeyboardButtonRequestUsers`): Optional. If specified, pressing the button will open a list of suitable users. Tapping on any user will send its - identifier to the bot in a :attr:`telegram.Message.user_shared` service message. + identifier to the bot in a :attr:`telegram.Message.users_shared` service message. Available in private chats only. .. versionadded:: 20.8 @@ -150,9 +137,6 @@ def __init__( request_location: Optional[bool] = None, request_poll: Optional[KeyboardButtonPollType] = None, web_app: Optional[WebAppInfo] = None, - request_user: Optional[ - Union[KeyboardButtonRequestUsers, KeyboardButtonRequestUser] - ] = None, request_chat: Optional[KeyboardButtonRequestChat] = None, request_users: Optional[KeyboardButtonRequestUsers] = None, *, @@ -167,15 +151,7 @@ def __init__( self.request_location: Optional[bool] = request_location self.request_poll: Optional[KeyboardButtonPollType] = request_poll self.web_app: Optional[WebAppInfo] = web_app - self.request_users: Optional[KeyboardButtonRequestUsers] = ( - warn_about_deprecated_arg_return_new_arg( - deprecated_arg=request_user, - new_arg=request_users, - deprecated_arg_name="request_user", - new_arg_name="request_users", - bot_api_version="7.0", - ) - ) + self.request_users: Optional[KeyboardButtonRequestUsers] = request_users self.request_chat: Optional[KeyboardButtonRequestChat] = request_chat self._id_attrs = ( @@ -190,21 +166,6 @@ def __init__( self._freeze() - @property - def request_user(self) -> Optional[KeyboardButtonRequestUsers]: - """Optional[:class:`KeyboardButtonRequestUsers`]: Alias for :attr:`request_users`. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates this attribute in favor of :attr:`request_users`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="request_user", - new_attr_name="request_users", - bot_api_version="7.0", - ) - return self.request_users - @classmethod def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["KeyboardButton"]: """See :meth:`telegram.TelegramObject.de_json`.""" @@ -218,4 +179,10 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["KeyboardButt data["request_chat"] = KeyboardButtonRequestChat.de_json(data.get("request_chat"), bot) data["web_app"] = WebAppInfo.de_json(data.get("web_app"), bot) - return super().de_json(data=data, bot=bot) + api_kwargs = {} + # This is a deprecated field that TG still returns for backwards compatibility + # Let's filter it out to speed up the de-json process + if request_user := data.get("request_user"): + api_kwargs = {"request_user": request_user} + + return super()._de_json(data=data, bot=bot, api_kwargs=api_kwargs) diff --git a/telegram/_keyboardbuttonrequest.py b/telegram/_keyboardbuttonrequest.py index 96968112c82..78bb2e50545 100644 --- a/telegram/_keyboardbuttonrequest.py +++ b/telegram/_keyboardbuttonrequest.py @@ -22,9 +22,6 @@ from telegram._chatadministratorrights import ChatAdministratorRights from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import build_deprecation_warning_message -from telegram.warnings import PTBDeprecationWarning if TYPE_CHECKING: from telegram import Bot @@ -42,7 +39,7 @@ class KeyboardButtonRequestUsers(TelegramObject): `_ .. versionadded:: 20.8 - This class was previously named :class:`KeyboardButtonRequestUser`. + This class was previously named ``KeyboardButtonRequestUser``. Args: request_id (:obj:`int`): Signed 32-bit identifier of the request, which will be received @@ -106,49 +103,6 @@ def __init__( self._freeze() -class KeyboardButtonRequestUser(KeyboardButtonRequestUsers): - """Alias for :class:`KeyboardButtonRequestUsers`, kept for backward compatibility. - - .. versionadded:: 20.1 - - .. deprecated:: 20.8 - Use :class:`KeyboardButtonRequestUsers` instead. - - """ - - __slots__ = () - - def __init__( - self, - request_id: int, - user_is_bot: Optional[bool] = None, - user_is_premium: Optional[bool] = None, - max_quantity: Optional[int] = None, - *, - api_kwargs: Optional[JSONDict] = None, # skipcq: PYL-W0622 - ): - super().__init__( - request_id=request_id, - user_is_bot=user_is_bot, - user_is_premium=user_is_premium, - max_quantity=max_quantity, - api_kwargs=api_kwargs, - ) - - warn( - build_deprecation_warning_message( - deprecated_name="KeyboardButtonRequestUser", - new_name="KeyboardButtonRequestUsers", - object_type="class", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - - self._freeze() - - class KeyboardButtonRequestChat(TelegramObject): """This object defines the criteria used to request a suitable chat. The identifier of the selected user will be shared with the bot when the corresponding button is pressed. diff --git a/telegram/_message.py b/telegram/_message.py index 2d324287af5..b94210a5efa 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -55,7 +55,7 @@ from telegram._poll import Poll from telegram._proximityalerttriggered import ProximityAlertTriggered from telegram._reply import ReplyParameters -from telegram._shared import ChatShared, UserShared, UsersShared +from telegram._shared import ChatShared, UsersShared from telegram._story import Story from telegram._telegramobject import TelegramObject from telegram._user import User @@ -71,10 +71,6 @@ ReplyMarkup, ) from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import ( - build_deprecation_warning_message, - warn_about_deprecated_attr_in_property, -) from telegram._videochat import ( VideoChatEnded, VideoChatParticipantsInvited, @@ -124,6 +120,9 @@ class MaybeInaccessibleMessage(TelegramObject): Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`message_id` and :attr:`chat` are equal + .. versionchanged:: NEXT.VERSION + ``__bool__`` is no longer overriden and defaults to Pythons standard implementation. + .. versionadded:: 20.8 Args: @@ -162,51 +161,6 @@ def __init__( self._freeze() - def __bool__(self) -> bool: - """Overrides :meth:`object.__bool__` to return the value of :attr:`is_accessible`. - This is intended to ease migration to Bot API 7.0, as this allows checks like - - .. code-block:: python - - if message.pinned_message: - ... - - to work as before, when ``message.pinned_message`` was :obj:`None`. Note that this does not - help with check like - - .. code-block:: python - - if message.pinned_message is None: - ... - - for cases where ``message.pinned_message`` is now no longer :obj:`None`. - - Tip: - Since objects that can only be of type :class:`~telegram.Message` or :obj:`None` are - not affected by this change, :meth:`Message.__bool__` is not overridden and will - continue to work as before. - - .. versionadded:: 20.8 - .. deprecated:: 20.8 - This behavior is introduced only temporarily to ease migration to Bot API 7.0. It will - be removed along with other functionality deprecated by Bot API 7.0. - """ - # Once we remove this method, also remove `Message.__bool__`. - warn( - category=PTBDeprecationWarning, - message=( - "You probably see this warning " - "because you wrote `if callback_query.message` or `if message.pinned_message` in " - "your code. This is not the supported way of checking the existence of a message " - "as of API 7.0. Please use `if message.is_accessible` or `if isinstance(message, " - "Message)` instead. `if message is None` may be suitable for specific use cases " - f"as well.\n`{self.__class__.__name__}.__bool__` will be reverted to Pythons " - f"default implementation in future versions." - ), - stacklevel=2, - ) - return self.is_accessible - @property def is_accessible(self) -> bool: """Convenience attribute. :obj:`True`, if the date is not 0 in Unix time. @@ -218,7 +172,9 @@ def is_accessible(self) -> bool: return self.date != ZERO_DATE @classmethod - def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MaybeInaccessibleMessage"]: + def _de_json( + cls, data: Optional[JSONDict], bot: "Bot", api_kwargs: Optional[JSONDict] = None + ) -> Optional["MaybeInaccessibleMessage"]: """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) @@ -240,7 +196,7 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["MaybeInacces data["date"] = from_timestamp(data["date"], tzinfo=loc_tzinfo) data["chat"] = Chat.de_json(data.get("chat"), bot) - return super().de_json(data=data, bot=bot) + return super()._de_json(data=data, bot=bot) class InaccessibleMessage(MaybeInaccessibleMessage): @@ -287,6 +243,11 @@ class Message(MaybeInaccessibleMessage): Note: In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. + .. versionchanged:: NEXT.VERSION + Removed deprecated arguments and attributes ``user_shared``, ``forward_from``, + ``forward_from_chat``, ``forward_from_message_id``, ``forward_signature``, + ``forward_sender_name`` and ``forward_date``. + .. versionchanged:: 20.8 * This class is now a subclass of :class:`telegram.MaybeInaccessibleMessage`. * The :paramref:`pinned_message` now can be either class:`telegram.Message` or @@ -323,39 +284,6 @@ class Message(MaybeInaccessibleMessage): .. versionchanged:: 20.3 |datetime_localization| chat (:class:`telegram.Chat`): Conversation the message belongs to. - forward_from (:class:`telegram.User`, optional): For forwarded messages, sender of - the original message. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from` in favor of - :paramref:`forward_origin`. - forward_from_chat (:class:`telegram.Chat`, optional): For messages forwarded from channels - or from anonymous administrators, information about the original sender chat. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from_chat` in favor of - :paramref:`forward_origin`. - forward_from_message_id (:obj:`int`, optional): For forwarded channel posts, identifier of - the original message in the channel. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_from_message_id` in favor of - :paramref:`forward_origin`. - forward_sender_name (:obj:`str`, optional): Sender's name for messages forwarded from - users who disallow adding a link to their account in forwarded messages. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_sender_name` in favor of - :paramref:`forward_origin`. - forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the - original message was sent in Unix time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_date` in favor of - :paramref:`forward_origin`. is_automatic_forward (:obj:`bool`, optional): :obj:`True`, if the message is a channel post that was automatically forwarded to the connected discussion group. @@ -481,12 +409,6 @@ class Message(MaybeInaccessibleMessage): message about a successful payment, information about the payment. connected_website (:obj:`str`, optional): The domain name of the website on which the user has logged in. - forward_signature (:obj:`str`, optional): For messages forwarded from channels, signature - of the post author if present. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`forward_signature` in favor of - :paramref:`forward_origin`. author_signature (:obj:`str`, optional): Signature of the post author for messages in channels, or the custom title of an anonymous group administrator. passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data. @@ -563,12 +485,6 @@ class Message(MaybeInaccessibleMessage): by a spoiler animation. .. versionadded:: 20.0 - user_shared (:class:`telegram.UserShared`, optional): Service message: a user was shared - with the bot. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates :paramref:`user_shared` in favor of :paramref:`users_shared`. users_shared (:class:`telegram.UsersShared`, optional): Service message: users were shared with the bot @@ -888,13 +804,6 @@ class Message(MaybeInaccessibleMessage): # fmt: on __slots__ = ( "_effective_attachment", - "_forward_date", - "_forward_from", - "_forward_from_chat", - "_forward_from_message_id", - "_forward_sender_name", - "_forward_signature", - "_user_shared", "animation", "audio", "author_signature", @@ -974,10 +883,6 @@ def __init__( date: datetime.datetime, chat: Chat, from_user: Optional[User] = None, - forward_from: Optional[User] = None, - forward_from_chat: Optional[Chat] = None, - forward_from_message_id: Optional[int] = None, - forward_date: Optional[datetime.datetime] = None, reply_to_message: Optional["Message"] = None, edit_date: Optional[datetime.datetime] = None, text: Optional[str] = None, @@ -1008,14 +913,12 @@ def __init__( pinned_message: Optional[MaybeInaccessibleMessage] = None, invoice: Optional[Invoice] = None, successful_payment: Optional[SuccessfulPayment] = None, - forward_signature: Optional[str] = None, author_signature: Optional[str] = None, media_group_id: Optional[str] = None, connected_website: Optional[str] = None, animation: Optional[Animation] = None, passport_data: Optional[PassportData] = None, poll: Optional[Poll] = None, - forward_sender_name: Optional[str] = None, reply_markup: Optional[InlineKeyboardMarkup] = None, dice: Optional[Dice] = None, via_bot: Optional[User] = None, @@ -1039,7 +942,6 @@ def __init__( general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None, write_access_allowed: Optional[WriteAccessAllowed] = None, has_media_spoiler: Optional[bool] = None, - user_shared: Optional[UserShared] = None, chat_shared: Optional[ChatShared] = None, story: Optional[Story] = None, giveaway: Optional["Giveaway"] = None, @@ -1056,49 +958,6 @@ def __init__( ): super().__init__(chat=chat, message_id=message_id, date=date, api_kwargs=api_kwargs) - if user_shared: - warn( - build_deprecation_warning_message( - deprecated_name="user_shared", - new_name="users_shared", - object_type="parameter", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - - if any( - ( - forward_from, - forward_from_chat, - forward_from_message_id, - forward_signature, - forward_sender_name, - forward_date, - ) - ): - if forward_from: - _warn_param = "forward_from" - elif forward_from_chat: - _warn_param = "forward_from_chat" - elif forward_from_message_id: - _warn_param = "forward_from_message_id" - elif forward_signature: - _warn_param = "forward_signature" - elif forward_sender_name: - _warn_param = "forward_sender_name" - else: - _warn_param = "forward_date" - - warn( - f"The information about parameter '{_warn_param}' was transferred to " - "'forward_origin' in Bot API 7.0. We recommend using 'forward_origin' instead of " - f"'{_warn_param}'", - PTBDeprecationWarning, - stacklevel=2, - ) - with self._unfrozen(): # Required self.message_id: int = message_id @@ -1107,9 +966,6 @@ def __init__( self.sender_chat: Optional[Chat] = sender_chat self.date: datetime.datetime = date self.chat: Chat = chat - self._forward_from: Optional[User] = forward_from - self._forward_from_chat: Optional[Chat] = forward_from_chat - self._forward_date: Optional[datetime.datetime] = forward_date self.is_automatic_forward: Optional[bool] = is_automatic_forward self.reply_to_message: Optional[Message] = reply_to_message self.edit_date: Optional[datetime.datetime] = edit_date @@ -1143,12 +999,9 @@ def __init__( message_auto_delete_timer_changed ) self.pinned_message: Optional[MaybeInaccessibleMessage] = pinned_message - self._forward_from_message_id: Optional[int] = forward_from_message_id self.invoice: Optional[Invoice] = invoice self.successful_payment: Optional[SuccessfulPayment] = successful_payment self.connected_website: Optional[str] = connected_website - self._forward_signature: Optional[str] = forward_signature - self._forward_sender_name: Optional[str] = forward_sender_name self.author_signature: Optional[str] = author_signature self.media_group_id: Optional[str] = media_group_id self.animation: Optional[Animation] = animation @@ -1181,7 +1034,6 @@ def __init__( ) self.write_access_allowed: Optional[WriteAccessAllowed] = write_access_allowed self.has_media_spoiler: Optional[bool] = has_media_spoiler - self._user_shared: Optional[UserShared] = user_shared self.users_shared: Optional[UsersShared] = users_shared self.chat_shared: Optional[ChatShared] = chat_shared self.story: Optional[Story] = story @@ -1198,132 +1050,6 @@ def __init__( self._id_attrs = (self.message_id, self.chat) - def __bool__(self) -> bool: - """Overrides :meth:`telegram.MaybeInaccessibleMessage.__bool__` to use Pythons - default implementation of :meth:`object.__bool__` instead. - - Tip: - The current behavior is the same as before the introduction of - :class:`telegram.MaybeInaccessibleMessage`. This documentation is relevant only until - :meth:`telegram.MaybeInaccessibleMessage.__bool__` is removed. - """ - return True - - @property - def user_shared(self) -> Optional[UserShared]: - """:class:`telegram.UserShared`: Optional. Service message. A user was shared with the - bot. - - Hint: - In case a single user was shared, :attr:`user_shared` will be present in addition to - :attr:`users_shared`. If multiple users where shared, only :attr:`users_shared` will - be present. However, this behavior is not documented and may be changed by Telegram. - - .. versionadded:: 20.1 - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`user_shared` in favor of :attr:`users_shared`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="user_shared", - new_attr_name="users_shared", - bot_api_version="7.0", - ) - return self._user_shared - - @property - def forward_from(self) -> Optional[User]: - """:class:`telegram.User`: Optional. For forwarded messages, sender of the original - message. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from - - @property - def forward_from_chat(self) -> Optional[Chat]: - """:class:`telegram.Chat`: Optional. For messages forwarded from channels or from anonymous - administrators, information about the original sender chat. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from_chat` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from_chat", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from_chat - - @property - def forward_from_message_id(self) -> Optional[int]: - """:obj:`int`: Optional. For forwarded channel posts, identifier of the original message - in the channel. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_from_message_id` in favor of - :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_from_message_id", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_from_message_id - - @property - def forward_signature(self) -> Optional[str]: - """:obj:`str`: Optional. For messages forwarded from channels, signature - of the post author if present. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_signature` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_signature", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_signature - - @property - def forward_sender_name(self) -> Optional[str]: - """:class:`telegram.User`: Optional. Sender's name for messages forwarded from users who - disallow adding a link to their account in forwarded messages. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_sender_name` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_sender_name", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_sender_name - - @property - def forward_date(self) -> Optional[datetime.datetime]: - """:obj:`datetime.datetime`: Optional. For forwarded messages, date the original message - was sent in Unix time. Converted to :class:`datetime.datetime`. - - .. versionchanged:: 20.3 - |datetime_localization| - - .. deprecated:: 20.8 - Bot API 7.0 deprecates :attr:`forward_date` in favor of :attr:`forward_origin`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="forward_date", - new_attr_name="forward_origin", - bot_api_version="7.0", - ) - return self._forward_date - @property def chat_id(self) -> int: """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`.""" @@ -1373,9 +1099,6 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["sender_chat"] = Chat.de_json(data.get("sender_chat"), bot) data["entities"] = MessageEntity.de_list(data.get("entities"), bot) data["caption_entities"] = MessageEntity.de_list(data.get("caption_entities"), bot) - data["forward_from"] = User.de_json(data.get("forward_from"), bot) - data["forward_from_chat"] = Chat.de_json(data.get("forward_from_chat"), bot) - data["forward_date"] = from_timestamp(data.get("forward_date"), tzinfo=loc_tzinfo) data["reply_to_message"] = Message.de_json(data.get("reply_to_message"), bot) data["edit_date"] = from_timestamp(data.get("edit_date"), tzinfo=loc_tzinfo) data["audio"] = Audio.de_json(data.get("audio"), bot) @@ -1434,7 +1157,6 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["write_access_allowed"] = WriteAccessAllowed.de_json( data.get("write_access_allowed"), bot ) - data["user_shared"] = UserShared.de_json(data.get("user_shared"), bot) data["users_shared"] = UsersShared.de_json(data.get("users_shared"), bot) data["chat_shared"] = ChatShared.de_json(data.get("chat_shared"), bot) @@ -1464,7 +1186,24 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["quote"] = TextQuote.de_json(data.get("quote"), bot) data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot) - return super().de_json(data=data, bot=bot) # type: ignore[return-value] + api_kwargs = {} + # This is a deprecated field that TG still returns for backwards compatibility + # Let's filter it out to speed up the de-json process + for key in ( + "user_shared", + "forward_from", + "forward_from_chat", + "forward_from_message_id", + "forward_signature", + "forward_sender_name", + "forward_date", + ): + if entry := data.get(key): + api_kwargs = {key: entry} + + return super()._de_json( # type: ignore[return-value] + data=data, bot=bot, api_kwargs=api_kwargs + ) @property def effective_attachment( @@ -1764,17 +1503,17 @@ async def reply_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1829,17 +1568,17 @@ async def reply_text( async def reply_markdown( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1904,17 +1643,17 @@ async def reply_markdown( async def reply_markdown_v2( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1975,17 +1714,17 @@ async def reply_markdown_v2( async def reply_html( self, text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + disable_web_page_preview: Optional[bool] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2049,12 +1788,12 @@ async def reply_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2114,16 +1853,16 @@ async def reply_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2185,16 +1924,16 @@ async def reply_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2256,17 +1995,17 @@ async def reply_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2330,9 +2069,7 @@ async def reply_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2340,6 +2077,8 @@ async def reply_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2401,14 +2140,14 @@ async def reply_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2463,13 +2202,11 @@ async def reply_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2477,6 +2214,8 @@ async def reply_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2541,14 +2280,14 @@ async def reply_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2607,15 +2346,15 @@ async def reply_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2674,17 +2413,17 @@ async def reply_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional[Location] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2747,16 +2486,16 @@ async def reply_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional[Venue] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2819,14 +2558,14 @@ async def reply_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional[Contact] = None, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, @@ -2889,18 +2628,18 @@ async def reply_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime.datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2962,14 +2701,14 @@ async def reply_poll( async def reply_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3055,13 +2794,13 @@ async def reply_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3130,18 +2869,18 @@ async def reply_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3278,13 +3017,13 @@ async def copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3336,13 +3075,13 @@ async def reply_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, quote: Optional[bool] = None, do_quote: Optional[Union[bool, _ReplyKwargs]] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3404,11 +3143,11 @@ async def edit_text( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_shared.py b/telegram/_shared.py index 671c83b8fe2..89cb0b5d6a2 100644 --- a/telegram/_shared.py +++ b/telegram/_shared.py @@ -21,12 +21,6 @@ from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict -from telegram._utils.warnings import warn -from telegram._utils.warnings_transition import ( - build_deprecation_warning_message, - warn_about_deprecated_attr_in_property, -) -from telegram.warnings import PTBDeprecationWarning class UsersShared(TelegramObject): @@ -38,7 +32,7 @@ class UsersShared(TelegramObject): considered equal, if their :attr:`request_id` and :attr:`user_ids` are equal. .. versionadded:: 20.8 - Bot API 7.0 replaces :class:`UserShared` with this class. The only difference is that now + Bot API 7.0 replaces ``UserShared`` with this class. The only difference is that now the :attr:`user_ids` is a sequence instead of a single integer. Args: @@ -78,55 +72,6 @@ def __init__( self._freeze() -class UserShared(UsersShared): - """Alias for :class:`UsersShared`, kept for backward compatibility. - - .. versionadded:: 20.1 - - .. deprecated:: 20.8 - Use :class:`UsersShared` instead. - - """ - - __slots__ = () - - def __init__( - self, - request_id: int, - user_id: int, - *, - api_kwargs: Optional[JSONDict] = None, - ): - super().__init__(request_id, (user_id,), api_kwargs=api_kwargs) - - warn( - build_deprecation_warning_message( - deprecated_name="UserShared", - new_name="UsersShared", - object_type="class", - bot_api_version="7.0", - ), - PTBDeprecationWarning, - stacklevel=2, - ) - - self._freeze() - - @property - def user_id(self) -> int: - """Alias for the first entry of :attr:`UsersShared.user_ids`. - - .. deprecated:: 20.8 - Bot API 7.0 deprecates this attribute in favor of :attr:`UsersShared.user_ids`. - """ - warn_about_deprecated_attr_in_property( - deprecated_attr_name="user_id", - new_attr_name="user_ids", - bot_api_version="7.0", - ) - return self.user_ids[0] - - class ChatShared(TelegramObject): """ This object contains information about the chat whose identifier was shared with the bot diff --git a/telegram/_user.py b/telegram/_user.py index 2acaa658cda..914d7024f5c 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -386,17 +386,17 @@ async def send_message( self, text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + disable_web_page_preview: Optional[bool] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -506,16 +506,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -564,12 +564,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -620,16 +620,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -719,14 +719,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional["Contact"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -771,14 +771,14 @@ async def send_contact( async def send_dice( self, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -820,17 +820,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -878,13 +878,13 @@ async def send_game( self, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -940,18 +940,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1023,17 +1023,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional["Location"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1086,9 +1086,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1096,6 +1094,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1146,14 +1146,14 @@ async def send_sticker( self, sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1197,13 +1197,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -1211,6 +1209,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1266,16 +1266,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional["Venue"] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1327,14 +1327,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1382,15 +1382,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1443,18 +1443,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1510,13 +1510,13 @@ async def send_copy( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1565,13 +1565,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/_utils/argumentparsing.py b/telegram/_utils/argumentparsing.py index cfd1877a685..c3613ecdd9c 100644 --- a/telegram/_utils/argumentparsing.py +++ b/telegram/_utils/argumentparsing.py @@ -25,6 +25,9 @@ """ from typing import Optional, Sequence, Tuple, TypeVar +from telegram._linkpreviewoptions import LinkPreviewOptions +from telegram._utils.types import ODVInput + T = TypeVar("T") @@ -38,3 +41,21 @@ def parse_sequence_arg(arg: Optional[Sequence[T]]) -> Tuple[T, ...]: :obj:`Tuple`: The sequence converted to a tuple or an empty tuple. """ return tuple(arg) if arg else () + + +def parse_lpo_and_dwpp( + disable_web_page_preview: Optional[bool], link_preview_options: ODVInput[LinkPreviewOptions] +) -> ODVInput[LinkPreviewOptions]: + """Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting + disable_web_page_preview to LinkPreviewOptions. + """ + if disable_web_page_preview and link_preview_options: + raise ValueError( + "Parameters `disable_web_page_preview` and `link_preview_options` are mutually " + "exclusive." + ) + + if disable_web_page_preview is not None: + link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview) + + return link_preview_options diff --git a/telegram/_utils/warnings_transition.py b/telegram/_utils/warnings_transition.py index 5d844546b9d..655450d158d 100644 --- a/telegram/_utils/warnings_transition.py +++ b/telegram/_utils/warnings_transition.py @@ -25,9 +25,6 @@ """ from typing import Any, Callable, Type -from telegram._linkpreviewoptions import LinkPreviewOptions -from telegram._utils.defaultvalue import DefaultValue -from telegram._utils.types import ODVInput from telegram._utils.warnings import warn from telegram.warnings import PTBDeprecationWarning @@ -93,28 +90,6 @@ def warn_about_deprecated_arg_return_new_arg( return new_arg -def warn_for_link_preview_options( - disable_web_page_preview: ODVInput[bool], link_preview_options: ODVInput[LinkPreviewOptions] -) -> ODVInput[LinkPreviewOptions]: - """Wrapper around warn_about_deprecated_arg_return_new_arg. Takes care of converting - disable_web_page_preview to LinkPreviewOptions. - """ - warn_about_deprecated_arg_return_new_arg( - deprecated_arg=disable_web_page_preview, - new_arg=link_preview_options, - deprecated_arg_name="disable_web_page_preview", - new_arg_name="link_preview_options", - bot_api_version="7.0", - stacklevel=2, - ) - - # Convert to LinkPreviewOptions: - if not isinstance(disable_web_page_preview, DefaultValue): - link_preview_options = LinkPreviewOptions(is_disabled=disable_web_page_preview) - - return link_preview_options - - def warn_about_deprecated_attr_in_property( deprecated_attr_name: str, new_attr_name: str, diff --git a/telegram/ext/_extbot.py b/telegram/ext/_extbot.py index 2dd5abfe17f..eefda3bf3d7 100644 --- a/telegram/ext/_extbot.py +++ b/telegram/ext/_extbot.py @@ -558,10 +558,8 @@ async def _send_message( self, endpoint: str, data: JSONDict, - reply_to_message_id: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, caption: Optional[str] = None, @@ -570,6 +568,8 @@ async def _send_message( link_preview_options: ODVInput["LinkPreviewOptions"] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -767,13 +767,13 @@ async def copy_message( parse_mode: ODVInput[str] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -1603,11 +1603,11 @@ async def edit_message_text( message_id: Optional[int] = None, inline_message_id: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional["InlineKeyboardMarkup"] = None, entities: Optional[Sequence["MessageEntity"]] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, *, + disable_web_page_preview: Optional[bool] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2344,9 +2344,7 @@ async def send_animation( caption: Optional[str] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -2354,6 +2352,8 @@ async def send_animation( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2397,16 +2397,16 @@ async def send_audio( title: Optional[str] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2471,14 +2471,14 @@ async def send_contact( first_name: Optional[str] = None, last_name: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, vcard: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, contact: Optional[Contact] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2512,14 +2512,14 @@ async def send_dice( self, chat_id: Union[int, str], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, emoji: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2550,17 +2550,17 @@ async def send_document( document: Union[FileInput, "Document"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, disable_content_type_detection: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2597,13 +2597,13 @@ async def send_game( chat_id: int, game_short_name: str, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2648,18 +2648,18 @@ async def send_invoice( need_shipping_address: Optional[bool] = None, is_flexible: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional["InlineKeyboardMarkup"] = None, provider_data: Optional[Union[str, object]] = None, send_phone_number_to_provider: Optional[bool] = None, send_email_to_provider: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, max_tip_amount: Optional[int] = None, suggested_tip_amounts: Optional[Sequence[int]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2710,17 +2710,17 @@ async def send_location( latitude: Optional[float] = None, longitude: Optional[float] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, live_period: Optional[int] = None, horizontal_accuracy: Optional[float] = None, heading: Optional[int] = None, proximity_alert_radius: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, location: Optional[Location] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2759,12 +2759,12 @@ async def send_media_group( Union["InputMediaAudio", "InputMediaDocument", "InputMediaPhoto", "InputMediaVideo"] ], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2800,16 +2800,16 @@ async def send_message( text: str, parse_mode: ODVInput[str] = DEFAULT_NONE, entities: Optional[Sequence["MessageEntity"]] = None, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, disable_notification: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, reply_markup: Optional[ReplyMarkup] = None, message_thread_id: Optional[int] = None, link_preview_options: ODVInput["LinkPreviewOptions"] = DEFAULT_NONE, reply_parameters: Optional["ReplyParameters"] = None, *, + disable_web_page_preview: Optional[bool] = None, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2844,16 +2844,16 @@ async def send_photo( photo: Union[FileInput, "PhotoSize"], caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, has_spoiler: Optional[bool] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2895,18 +2895,18 @@ async def send_poll( correct_option_id: Optional[CorrectOptionID] = None, is_closed: Optional[bool] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, explanation: Optional[str] = None, explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, open_period: Optional[int] = None, close_date: Optional[Union[int, datetime]] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, explanation_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2947,14 +2947,14 @@ async def send_sticker( chat_id: Union[int, str], sticker: Union[FileInput, "Sticker"], disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, emoji: Optional[str] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -2989,16 +2989,16 @@ async def send_venue( address: Optional[str] = None, foursquare_id: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, foursquare_type: Optional[str] = None, google_place_id: Optional[str] = None, google_place_type: Optional[str] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, venue: Optional[Venue] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3039,13 +3039,11 @@ async def send_video( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, width: Optional[int] = None, height: Optional[int] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, supports_streaming: Optional[bool] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, @@ -3053,6 +3051,8 @@ async def send_video( thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3095,14 +3095,14 @@ async def send_video_note( duration: Optional[int] = None, length: Optional[int] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, thumbnail: Optional[FileInput] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, @@ -3139,15 +3139,15 @@ async def send_voice( duration: Optional[int] = None, caption: Optional[str] = None, disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: Optional[int] = None, reply_markup: Optional[ReplyMarkup] = None, parse_mode: ODVInput[str] = DEFAULT_NONE, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, caption_entities: Optional[Sequence["MessageEntity"]] = None, protect_content: ODVInput[bool] = DEFAULT_NONE, message_thread_id: Optional[int] = None, reply_parameters: Optional["ReplyParameters"] = None, *, + reply_to_message_id: Optional[int] = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, filename: Optional[str] = None, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index 28bc595cf7a..d78fa0d979f 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -1364,7 +1364,7 @@ def filter(self, message: Message) -> bool: .. versionchanged:: 20.8 Now based on :attr:`telegram.Message.forward_origin` instead of - :attr:`telegram.Message.forward_date`. + ``telegram.Message.forward_date``. """ @@ -1379,8 +1379,8 @@ class ForwardedFrom(_ChatUserBaseFilter): .. versionadded:: 13.5 .. versionchanged:: 20.8 - Was previously based on :attr:`telegram.Message.forward_from` and - :attr:`telegram.Message.forward_from_chat`. + Was previously based on ``telegram.Message.forward_from`` and + ``telegram.Message.forward_from_chat``. Examples: ``MessageHandler(filters.ForwardedFrom(chat_id=1234), callback_method)`` @@ -2146,15 +2146,19 @@ class _UserShared(MessageFilter): __slots__ = () def filter(self, message: Message) -> bool: - return bool(message.user_shared) + return bool(message.api_kwargs.get("user_shared")) USER_SHARED = _UserShared(name="filters.StatusUpdate.USER_SHARED") - """Messages that contain :attr:`telegram.Message.user_shared`. + """Messages that contain ``"user_shared"`` in :attr:`telegram.TelegramObject.api_kwargs`. Warning: - This will only catch the legacy :attr:`telegram.Message.user_shared` attribute, not the + This will only catch the legacy ``user_shared`` field, not the new :attr:`telegram.Message.users_shared` attribute! + .. versionchanged:: NEXT.VERSION + Now relies on :attr:`telegram.TelegramObject.api_kwargs` as the native attribute + ``Message.user_shared`` was removed. + .. versionadded:: 20.1 .. deprecated:: 20.8 Use :attr:`USERS_SHARED` instead. diff --git a/tests/_inline/test_inputtextmessagecontent.py b/tests/_inline/test_inputtextmessagecontent.py index 4f1db4043cf..632a29db189 100644 --- a/tests/_inline/test_inputtextmessagecontent.py +++ b/tests/_inline/test_inputtextmessagecontent.py @@ -20,7 +20,6 @@ from telegram import InputTextMessageContent, LinkPreviewOptions, MessageEntity from telegram.constants import ParseMode -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -52,7 +51,6 @@ def test_slot_behaviour(self, input_text_message_content): def test_expected_values(self, input_text_message_content): assert input_text_message_content.parse_mode == self.parse_mode assert input_text_message_content.message_text == self.message_text - assert input_text_message_content.disable_web_page_preview == self.disable_web_page_preview assert input_text_message_content.entities == tuple(self.entities) assert input_text_message_content.link_preview_options == self.link_preview_options @@ -95,13 +93,11 @@ def test_equality(self): assert hash(a) != hash(d) def test_mutually_exclusive(self): - with pytest.raises(ValueError, match="'link_preview_options' in Bot API 7.0"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): InputTextMessageContent( "text", disable_web_page_preview=True, link_preview_options=LinkPreviewOptions() ) - def test_disable_web_page_preview_deprecated(self): - with pytest.warns( - PTBDeprecationWarning, match="'disable_web_page_preview' to 'link_preview_options'" - ): - InputTextMessageContent("text", disable_web_page_preview=True).disable_web_page_preview + def test_disable_web_page_preview_deprecation(self): + itmc = InputTextMessageContent("text", disable_web_page_preview=True) + assert itmc.link_preview_options.is_disabled is True diff --git a/tests/auxil/bot_method_checks.py b/tests/auxil/bot_method_checks.py index ff838bae588..1e85af1baca 100644 --- a/tests/auxil/bot_method_checks.py +++ b/tests/auxil/bot_method_checks.py @@ -549,11 +549,9 @@ async def check_defaults_handling( } # We tested this for a long time, but Bot API 7.0 deprecated it in favor of # reply_parameters. In the transition phase, both exist in a mutually exclusive - # way. Testing both cases would require a lot of additional code, so we just - # ignore this parameter here until it is removed. - # Same for disable_web_page_preview + # way. Testing both cases would require a lot of additional code, so we for now are content + # with the explicit tests that we have inplace for allow_sending_without_reply kwargs_need_default.discard("allow_sending_without_reply") - kwargs_need_default.discard("disable_web_page_preview") if method.__name__.endswith("_media_group"): # the parse_mode is applied to the first media item, and we test this elsewhere diff --git a/tests/ext/test_filters.py b/tests/ext/test_filters.py index 39914085cf1..3a0f860d81b 100644 --- a/tests/ext/test_filters.py +++ b/tests/ext/test_filters.py @@ -1065,10 +1065,10 @@ def test_filters_status_update(self, update): assert filters.StatusUpdate.WRITE_ACCESS_ALLOWED.check_update(update) update.message.write_access_allowed = None - update.message._user_shared = "user_shared" + update.message.api_kwargs = {"user_shared": "user_shared"} assert filters.StatusUpdate.ALL.check_update(update) assert filters.StatusUpdate.USER_SHARED.check_update(update) - update.message._user_shared = None + update.message.api_kwargs = {} update.message.users_shared = "users_shared" assert filters.StatusUpdate.ALL.check_update(update) diff --git a/tests/test_bot.py b/tests/test_bot.py index d1357d57826..71e5b23041d 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -1061,12 +1061,12 @@ async def make_assertion(url, request_data: RequestData, *args, **kwargs): async def test_send_edit_message_mutually_exclusive_link_preview(self, bot, chat_id): """Test that link_preview is mutually exclusive with disable_web_page_preview.""" - with pytest.raises(ValueError, match="'disable_web_page_preview' was renamed to"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): await bot.send_message( chat_id, "text", disable_web_page_preview=True, link_preview_options="something" ) - with pytest.raises(ValueError, match="'disable_web_page_preview' was renamed to"): + with pytest.raises(ValueError, match="`link_preview_options` are mutually exclusive"): await bot.edit_message_text( "text", chat_id, 1, disable_web_page_preview=True, link_preview_options="something" ) @@ -2120,8 +2120,8 @@ async def test_forward_message(self, bot, chat_id, message): ) assert forward_message.text == message.text - assert forward_message.forward_from.username == message.from_user.username - assert isinstance(forward_message.forward_date, dtm.datetime) + assert forward_message.forward_origin.sender_user == message.from_user + assert isinstance(forward_message.forward_origin.date, dtm.datetime) async def test_forward_protected_message(self, bot, chat_id): tasks = asyncio.gather( @@ -2155,7 +2155,7 @@ async def test_forward_messages(self, bot, chat_id): msg1, msg2 = await tasks forward_messages = await bot.forward_messages( - chat_id, from_chat_id=chat_id, message_ids=(msg1.message_id, msg2.message_id) + chat_id, from_chat_id=chat_id, message_ids=sorted((msg1.message_id, msg2.message_id)) ) assert isinstance(forward_messages, tuple) @@ -2174,12 +2174,12 @@ async def test_forward_messages(self, bot, chat_id): forward_msg2 = temp_msg2.reply_to_message assert forward_msg1.text == msg1.text - assert forward_msg1.forward_from.username == msg1.from_user.username - assert isinstance(forward_msg1.forward_date, dtm.datetime) + assert forward_msg1.forward_origin.sender_user == msg1.from_user + assert isinstance(forward_msg1.forward_origin.date, dtm.datetime) assert forward_msg2.text == msg2.text - assert forward_msg2.forward_from.username == msg2.from_user.username - assert isinstance(forward_msg2.forward_date, dtm.datetime) + assert forward_msg2.forward_origin.sender_user == msg2.from_user + assert isinstance(forward_msg2.forward_origin.date, dtm.datetime) async def test_delete_message(self, bot, chat_id): message = await bot.send_message(chat_id, text="will be deleted") diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index b41239cc057..edd45cc9a8b 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -23,11 +23,9 @@ KeyboardButton, KeyboardButtonPollType, KeyboardButtonRequestChat, - KeyboardButtonRequestUser, KeyboardButtonRequestUsers, WebAppInfo, ) -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -82,7 +80,8 @@ def test_to_dict(self, keyboard_button): assert keyboard_button_dict["request_chat"] == keyboard_button.request_chat.to_dict() assert keyboard_button_dict["request_users"] == keyboard_button.request_users.to_dict() - def test_de_json(self, bot): + @pytest.mark.parametrize("request_user", [True, False]) + def test_de_json(self, bot, request_user): json_dict = { "text": self.text, "request_location": self.request_location, @@ -92,45 +91,26 @@ def test_de_json(self, bot): "request_chat": self.request_chat.to_dict(), "request_users": self.request_users.to_dict(), } + if request_user: + json_dict["request_user"] = {"request_id": 2} - inline_keyboard_button = KeyboardButton.de_json(json_dict, None) - assert inline_keyboard_button.api_kwargs == {} - assert inline_keyboard_button.text == self.text - assert inline_keyboard_button.request_location == self.request_location - assert inline_keyboard_button.request_contact == self.request_contact - assert inline_keyboard_button.request_poll == self.request_poll - assert inline_keyboard_button.web_app == self.web_app - assert inline_keyboard_button.request_chat == self.request_chat - assert inline_keyboard_button.request_user == self.request_users - assert inline_keyboard_button.request_users == self.request_users + keyboard_button = KeyboardButton.de_json(json_dict, None) + if request_user: + assert keyboard_button.api_kwargs == {"request_user": {"request_id": 2}} + else: + assert keyboard_button.api_kwargs == {} + + assert keyboard_button.text == self.text + assert keyboard_button.request_location == self.request_location + assert keyboard_button.request_contact == self.request_contact + assert keyboard_button.request_poll == self.request_poll + assert keyboard_button.web_app == self.web_app + assert keyboard_button.request_chat == self.request_chat + assert keyboard_button.request_users == self.request_users none = KeyboardButton.de_json({}, None) assert none is None - def test_request_user_deprecation_mutually_exclusive(self): - with pytest.raises(ValueError, match="'request_user' was renamed to 'request_users'"): - KeyboardButton( - "test", - request_users=KeyboardButtonRequestUsers(1), - request_user=KeyboardButtonRequestUsers(2), - ) - - def test_request_user_argument_deprecation_warning(self): - with pytest.warns( - PTBDeprecationWarning, match="'request_user' to 'request_users'" - ) as record: - KeyboardButton("test", request_user=KeyboardButtonRequestUser(2)) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_request_user_property_deprecation_warning(self, keyboard_button): - with pytest.warns( - PTBDeprecationWarning, match="'request_user' to 'request_users'" - ) as record: - assert keyboard_button.request_user is keyboard_button.request_users - - assert record[0].filename == __file__, "wrong stacklevel" - def test_equality(self): a = KeyboardButton("test", request_contact=True) b = KeyboardButton("test", request_contact=True) diff --git a/tests/test_keyboardbuttonrequest.py b/tests/test_keyboardbuttonrequest.py index 58fa8e7c1bb..c8f620ff5d8 100644 --- a/tests/test_keyboardbuttonrequest.py +++ b/tests/test_keyboardbuttonrequest.py @@ -16,17 +16,10 @@ # # 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 inspect import pytest -from telegram import ( - ChatAdministratorRights, - KeyboardButtonRequestChat, - KeyboardButtonRequestUser, - KeyboardButtonRequestUsers, -) -from telegram.warnings import PTBDeprecationWarning +from telegram import ChatAdministratorRights, KeyboardButtonRequestChat, KeyboardButtonRequestUsers from tests.auxil.slots import mro_slots @@ -92,28 +85,6 @@ def test_equality(self): assert hash(a) != hash(c) -class TestKeyboardButtonRequestUserWithoutRequest: - def test_slot_behaviour(self): - inst = KeyboardButtonRequestUser(1) - for attr in inst.__slots__: - assert getattr(inst, attr, "err") != "err", f"got extra slot '{attr}'" - assert len(mro_slots(inst)) == len(set(mro_slots(inst))), "duplicate slot" - - def test_signature(self): - assert inspect.signature(KeyboardButtonRequestUser) == inspect.signature( - KeyboardButtonRequestUsers - ) - - def test_deprecation_warning(self): - with pytest.warns( - PTBDeprecationWarning, - match="'KeyboardButtonRequestUser' was renamed to 'KeyboardButtonRequestUsers'", - ) as record: - KeyboardButtonRequestUser(request_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - @pytest.fixture(scope="class") def request_chat(): return KeyboardButtonRequestChat( diff --git a/tests/test_maybeinaccessiblemessage.py b/tests/test_maybeinaccessiblemessage.py index 890ff923f7d..2c6617af8f4 100644 --- a/tests/test_maybeinaccessiblemessage.py +++ b/tests/test_maybeinaccessiblemessage.py @@ -20,10 +20,9 @@ import pytest -from telegram import Chat, InaccessibleMessage, MaybeInaccessibleMessage +from telegram import Chat, MaybeInaccessibleMessage from telegram._utils.datetime import UTC, to_timestamp from telegram.constants import ZERO_DATE -from telegram.warnings import PTBDeprecationWarning from tests.auxil.slots import mro_slots @@ -111,29 +110,6 @@ def test_is_accessible(self): assert MaybeInaccessibleMessage(self.chat, self.message_id, self.date).is_accessible assert not MaybeInaccessibleMessage(self.chat, self.message_id, ZERO_DATE).is_accessible - def test_bool(self): - assert bool(MaybeInaccessibleMessage(self.chat, self.message_id, self.date).is_accessible) - assert not bool( - MaybeInaccessibleMessage(self.chat, self.message_id, ZERO_DATE).is_accessible - ) - - @pytest.mark.parametrize("cls", [MaybeInaccessibleMessage, InaccessibleMessage]) - def test_bool_deprecation_warning(self, cls): - if cls is MaybeInaccessibleMessage: - args = (self.chat, self.message_id, self.date) - else: - args = (self.chat, self.message_id) - - with pytest.warns( - PTBDeprecationWarning, - match=( - f"`{cls.__name__}.__bool__` will be reverted to Pythons default implementation" - ), - ) as record: - bool(cls(*args)) - - assert record[0].filename == __file__, "wrong stacklevel" - def test_equality(self, maybe_inaccessible_message): a = maybe_inaccessible_message b = MaybeInaccessibleMessage( diff --git a/tests/test_message.py b/tests/test_message.py index 232ddfb1be1..f79505035b2 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -98,12 +98,6 @@ def message(bot): @pytest.fixture( params=[ - {"forward_from": User(99, "forward_user", False), "forward_date": datetime.utcnow()}, - { - "forward_from_chat": Chat(-23, "channel"), - "forward_from_message_id": 101, - "forward_date": datetime.utcnow(), - }, { "reply_to_message": Message( 50, datetime.utcnow(), Chat(13, "channel"), User(9, "i", False) @@ -165,7 +159,6 @@ def message(bot): ) }, {"connected_website": "http://example.com/"}, - {"forward_signature": "some_forward_sign"}, {"author_signature": "some_author_sign"}, { "photo": [PhotoSize("photo_id", "unique_id", 50, 50)], @@ -224,9 +217,6 @@ def message(bot): }, {"web_app_data": WebAppData("some_data", "some_button_text")}, {"message_thread_id": 123}, - # Using a `UserShared` object here doesn't work, because `to_dict` produces `user_ids` - # instead of `user_id` - but that's what we want to test here. - {"user_shared": {"request_id": 1, "user_id": 2}}, {"users_shared": UsersShared(1, [2, 3])}, {"chat_shared": ChatShared(3, 4)}, { @@ -271,8 +261,6 @@ def message(bot): {"forward_origin": MessageOriginChat(datetime.utcnow(), Chat(1, Chat.PRIVATE))}, ], ids=[ - "forwarded_user", - "forwarded_channel", "reply", "edited", "text", @@ -305,7 +293,6 @@ def message(bot): "invoice", "successful_payment", "connected_website", - "forward_signature", "author_signature", "photo_from_media_group", "passport_data", @@ -324,7 +311,6 @@ def message(bot): "entities", "web_app_data", "message_thread_id", - "user_shared", "users_shared", "chat_shared", "giveaway", @@ -518,7 +504,6 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): "date": int(datetime.now().timestamp()), "chat": None, "edit_date": int(datetime.now().timestamp()), - "forward_date": int(datetime.now().timestamp()), } message_raw = Message.de_json(json_dict, raw_bot) @@ -534,11 +519,6 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): message_tz.edit_date.replace(tzinfo=None) ) - forward_date_offset = message_tz.forward_date.utcoffset() - forward_date_tz_bot_offset = tz_bot.defaults.tzinfo.utcoffset( - message_tz.forward_date.replace(tzinfo=None) - ) - assert message_raw.date.tzinfo == UTC assert message_bot.date.tzinfo == UTC assert date_offset == date_tz_bot_offset @@ -547,9 +527,21 @@ def test_de_json_localization(self, bot, raw_bot, tz_bot): assert message_bot.edit_date.tzinfo == UTC assert edit_date_offset == edit_date_tz_bot_offset - assert message_raw.forward_date.tzinfo == UTC - assert message_bot.forward_date.tzinfo == UTC - assert forward_date_offset == forward_date_tz_bot_offset + def test_de_json_api_kwargs_backward_compatibility(self, bot, message_params): + message_dict = message_params.to_dict() + keys = ( + "user_shared", + "forward_from", + "forward_from_chat", + "forward_from_message_id", + "forward_signature", + "forward_sender_name", + "forward_date", + ) + for key in keys: + message_dict[key] = key + message = Message.de_json(message_dict, bot) + assert message.api_kwargs == {key: key for key in keys} def test_equality(self): id_ = 1 @@ -572,124 +564,6 @@ def test_equality(self): assert a != e assert hash(a) != hash(e) - def test_user_shared_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'user_shared' was renamed to 'users_shared'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, user_shared=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_user_shared_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'user_shared' to 'users_shared'" - ) as record: - message.user_shared - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from' was transferred to 'forward_origin'" - ) as record: - Message( - message_id=1, date=self.date, chat=self.chat, forward_from=User(1, "user", False) - ) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from' to 'forward_origin'" - ) as record: - message.forward_from - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_chat_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_chat' was transferred to 'forward_origin'" - ) as record: - Message( - message_id=1, date=self.date, chat=self.chat, forward_from_chat=Chat(1, "private") - ) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_chat_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_chat' to 'forward_origin'" - ) as record: - message.forward_from_chat - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_message_id_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, - match="'forward_from_message_id' was transferred to 'forward_origin'", - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_from_message_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_from_message_id_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_from_message_id' to 'forward_origin'" - ) as record: - message.forward_from_message_id - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_signature_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_signature' was transferred to 'forward_origin'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_signature="signature") - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_signature_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_signature' to 'forward_origin'" - ) as record: - message.forward_signature - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_sender_name_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, - match="'forward_sender_name' was transferred to 'forward_origin'", - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_sender_name="name") - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_sender_name_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_sender_name' to 'forward_origin'" - ) as record: - message.forward_sender_name - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_date_init_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_date' was transferred to 'forward_origin'" - ) as record: - Message(message_id=1, date=self.date, chat=self.chat, forward_date=datetime.utcnow()) - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_forward_date_property_deprecation(self, message): - with pytest.warns( - PTBDeprecationWarning, match="'forward_date' to 'forward_origin'" - ) as record: - message.forward_date - - assert record[0].filename == __file__, "wrong stacklevel" - def test_bool(self, message, recwarn): # Relevant as long as we override MaybeInaccessibleMessage.__bool__ # Can be removed once that's removed diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index e554b0888ad..7807a02784a 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -94,6 +94,13 @@ class ParamTypeCheckingExceptions: PTB_EXTRA_PARAMS = { "send_contact": {"contact"}, "send_location": {"location"}, + "(send_message|edit_message_text)": { # convenience parameters + "disable_web_page_preview", + }, + r"(send|copy)_\w+": { # convenience parameters + "reply_to_message_id", + "allow_sending_without_reply", + }, "edit_message_live_location": {"location"}, "send_venue": {"venue"}, "answer_inline_query": {"current_offset"}, @@ -159,25 +166,7 @@ def ignored_param_requirements(object_name: str) -> set[str]: # Arguments that are optional arguments for now for backwards compatibility -BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { - # Deprecated by Bot API 7.0, kept for now for bw compat: - "KeyboardButton": {"request_user"}, - "Message": { - "forward_from", - "forward_signature", - "forward_sender_name", - "forward_date", - "forward_from_chat", - "forward_from_message_id", - "user_shared", - }, - "(send_message|edit_message_text)": { - "disable_web_page_preview", - "reply_to_message_id", - "allow_sending_without_reply", - }, - r"copy_message|send_\w+": {"allow_sending_without_reply", "reply_to_message_id"}, -} +BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {} def backwards_compat_kwargs(object_name: str) -> set[str]: diff --git a/tests/test_shared.py b/tests/test_shared.py index 0e92dcf3603..3c76eb329f5 100644 --- a/tests/test_shared.py +++ b/tests/test_shared.py @@ -16,20 +16,13 @@ # # 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 inspect import pytest -from telegram import ChatShared, UserShared, UsersShared -from telegram.warnings import PTBDeprecationWarning +from telegram import ChatShared, UsersShared from tests.auxil.slots import mro_slots -@pytest.fixture(scope="class") -def user_shared(): - return UserShared(TestUsersSharedBase.request_id, TestUsersSharedBase.user_id) - - @pytest.fixture(scope="class") def users_shared(): return UsersShared(TestUsersSharedBase.request_id, TestUsersSharedBase.user_ids) @@ -82,75 +75,6 @@ def test_equality(self): assert hash(a) != hash(d) -class TestUserSharedWithoutRequest(TestUsersSharedBase): - def test_slot_behaviour(self, user_shared): - for attr in user_shared.__slots__: - assert getattr(user_shared, attr, "err") != "err", f"got extra slot '{attr}'" - assert len(mro_slots(user_shared)) == len(set(mro_slots(user_shared))), "duplicate slot" - - def test_to_dict(self, user_shared): - user_shared_dict = user_shared.to_dict() - - assert isinstance(user_shared_dict, dict) - assert user_shared_dict["request_id"] == self.request_id - assert user_shared_dict["user_ids"] == [self.user_id] - - def test_de_json(self, bot): - json_dict = { - "request_id": self.request_id, - "user_id": self.user_id, - } - user_shared = UserShared.de_json(json_dict, bot) - assert user_shared.api_kwargs == {} - - assert user_shared.request_id == self.request_id - assert user_shared.user_id == self.user_id - assert user_shared.user_ids == (self.user_id,) - - def test_signature(self): - user_signature = inspect.signature(UserShared) - users_signature = inspect.signature(UsersShared) - - assert user_signature.return_annotation == users_signature.return_annotation - - for name, parameter in user_signature.parameters.items(): - if name not in users_signature.parameters: - assert name == "user_id" - else: - assert parameter.annotation == users_signature.parameters[name].annotation - - assert set(users_signature.parameters) - set(user_signature.parameters) == {"user_ids"} - - def test_deprecation_warnings(self): - with pytest.warns( - PTBDeprecationWarning, match="'UserShared' was renamed to 'UsersShared'" - ) as record: - user_shared = UserShared(request_id=1, user_id=1) - - assert record[0].filename == __file__, "wrong stacklevel" - - with pytest.warns(PTBDeprecationWarning, match="'user_id' to 'user_ids'") as record: - user_shared.user_id - - assert record[0].filename == __file__, "wrong stacklevel" - - def test_equality(self): - a = UserShared(self.request_id, self.user_id) - b = UserShared(self.request_id, self.user_id) - c = UserShared(1, self.user_id) - d = UserShared(self.request_id, 1) - - assert a == b - assert hash(a) == hash(b) - assert a is not b - - assert a != c - assert hash(a) != hash(c) - - assert a != d - assert hash(a) != hash(d) - - @pytest.fixture(scope="class") def chat_shared(): return ChatShared( From 9c263fbd1a9a5d070622fbf13d9fdbb64c5252d3 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:47:04 +0100 Subject: [PATCH 06/17] Add Parameter `media_write_timeout` to `HTTPXRequest` and Method `ApplicationBuilder.media_write_timeout` (#4120) --- telegram/ext/_applicationbuilder.py | 33 +++++++++++++++++++++++++++- telegram/request/_httpxrequest.py | 20 ++++++++++++----- tests/ext/test_applicationbuilder.py | 19 +++++++++++++++- tests/request/test_request.py | 33 ++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 8 deletions(-) diff --git a/telegram/ext/_applicationbuilder.py b/telegram/ext/_applicationbuilder.py index 71c4bd31286..106c73462b8 100644 --- a/telegram/ext/_applicationbuilder.py +++ b/telegram/ext/_applicationbuilder.py @@ -78,6 +78,7 @@ ("connect_timeout", "connect_timeout"), ("read_timeout", "read_timeout"), ("write_timeout", "write_timeout"), + ("media_write_timeout", "media_write_timeout"), ("http_version", "http_version"), ("get_updates_connection_pool_size", "get_updates_connection_pool_size"), ("get_updates_proxy", "get_updates_proxy"), @@ -152,6 +153,7 @@ class ApplicationBuilder(Generic[BT, CCT, UD, CD, BD, JQ]): "_http_version", "_job_queue", "_local_mode", + "_media_write_timeout", "_persistence", "_pool_timeout", "_post_init", @@ -181,6 +183,7 @@ def __init__(self: "InitApplicationBuilder"): self._connect_timeout: ODVInput[float] = DEFAULT_NONE self._read_timeout: ODVInput[float] = DEFAULT_NONE self._write_timeout: ODVInput[float] = DEFAULT_NONE + self._media_write_timeout: ODVInput[float] = DEFAULT_NONE self._pool_timeout: ODVInput[float] = DEFAULT_NONE self._request: DVInput[BaseRequest] = DEFAULT_NONE self._get_updates_connection_pool_size: DVInput[int] = DEFAULT_NONE @@ -243,6 +246,10 @@ def _build_request(self, get_updates: bool) -> BaseRequest: "write_timeout": getattr(self, f"{prefix}write_timeout"), "pool_timeout": getattr(self, f"{prefix}pool_timeout"), } + + if not get_updates: + timeouts["media_write_timeout"] = self._media_write_timeout + # Get timeouts that were actually set- effective_timeouts = { key: value for key, value in timeouts.items() if not isinstance(value, DefaultValue) @@ -424,9 +431,13 @@ def _request_check(self, get_updates: bool) -> None: prefix = "get_updates_" if get_updates else "" name = prefix + "request" + timeouts = ["connect_timeout", "read_timeout", "write_timeout", "pool_timeout"] + if not get_updates: + timeouts.append("media_write_timeout") + # Code below tests if it's okay to set a Request object. Only okay if no other request args # or instances containing a Request were set previously - for attr in ("connect_timeout", "read_timeout", "write_timeout", "pool_timeout"): + for attr in timeouts: if not isinstance(getattr(self, f"_{prefix}{attr}"), DefaultValue): raise RuntimeError(_TWO_ARGS_REQ.format(name, attr)) @@ -617,6 +628,26 @@ def write_timeout(self: BuilderType, write_timeout: Optional[float]) -> BuilderT self._write_timeout = write_timeout return self + def media_write_timeout( + self: BuilderType, media_write_timeout: Optional[float] + ) -> BuilderType: + """Sets the media write operation timeout for the + :paramref:`~telegram.request.HTTPXRequest.media_write_timeout` parameter of + :attr:`telegram.Bot.request`. Defaults to ``20``. + + .. versionadded:: NEXT.VERSION + + Args: + media_write_timeout (:obj:`float`): See + :paramref:`telegram.request.HTTPXRequest.media_write_timeout` for more information. + + Returns: + :class:`ApplicationBuilder`: The same builder with the updated argument. + """ + self._request_param_check(name="media_write_timeout", get_updates=False) + self._media_write_timeout = media_write_timeout + return self + def pool_timeout(self: BuilderType, pool_timeout: Optional[float]) -> BuilderType: """Sets the connection pool's connection freeing timeout for the :paramref:`~telegram.request.HTTPXRequest.pool_timeout` parameter of diff --git a/telegram/request/_httpxrequest.py b/telegram/request/_httpxrequest.py index 7ca54c5c534..8c18d063012 100644 --- a/telegram/request/_httpxrequest.py +++ b/telegram/request/_httpxrequest.py @@ -64,6 +64,10 @@ class HTTPXRequest(BaseRequest): a network socket; i.e. POSTing a request or uploading a file). This value is used unless a different value is passed to :meth:`do_request`. Defaults to ``5``. + + Hint: + This timeout is used for all requests except for those that upload media/files. + For the latter, :paramref:`media_write_timeout` is used. connect_timeout (:obj:`float` | :obj:`None`, optional): If passed, specifies the maximum amount of time (in seconds) to wait for a connection attempt to a server to succeed. This value is used unless a different value is passed to @@ -112,10 +116,16 @@ class HTTPXRequest(BaseRequest): .. _the docs of httpx: https://www.python-httpx.org/environment_variables/#proxies .. versionadded:: 20.7 + media_write_timeout (:obj:`float` | :obj:`None`, optional): Like :paramref:`write_timeout`, + but used only for requests that upload media/files. This value is used unless a + different value is passed to :paramref:`do_request.write_timeout` of + :meth:`do_request`. Defaults to ``20`` seconds. + + .. versionadded:: NEXT.VERSION """ - __slots__ = ("_client", "_client_kwargs", "_http_version") + __slots__ = ("_client", "_client_kwargs", "_http_version", "_media_write_timeout") def __init__( self, @@ -128,6 +138,7 @@ def __init__( http_version: HTTPVersion = "1.1", socket_options: Optional[Collection[SocketOpt]] = None, proxy: Optional[Union[str, httpx.Proxy, httpx.URL]] = None, + media_write_timeout: Optional[float] = 20.0, ): if proxy_url is not None and proxy is not None: raise ValueError("The parameters `proxy_url` and `proxy` are mutually exclusive.") @@ -142,6 +153,7 @@ def __init__( ) self._http_version = http_version + self._media_write_timeout = media_write_timeout timeout = httpx.Timeout( connect=connect_timeout, read=read_timeout, @@ -251,11 +263,7 @@ async def do_request( pool_timeout = self._client.timeout.pool if isinstance(write_timeout, DefaultValue): - # Making the networking backend decide on the proper timeout values instead of doing - # it via the default values of the Bot methods was introduced in version 20.7. - # We hard-code the value here for now until we add additional parameters to this - # class to control the media_write_timeout separately. - write_timeout = self._client.timeout.write if not files else 20 + write_timeout = self._client.timeout.write if not files else self._media_write_timeout timeout = httpx.Timeout( connect=connect_timeout, diff --git a/tests/ext/test_applicationbuilder.py b/tests/ext/test_applicationbuilder.py index 89990601bc5..9fcbc140141 100644 --- a/tests/ext/test_applicationbuilder.py +++ b/tests/ext/test_applicationbuilder.py @@ -76,6 +76,9 @@ def test_all_methods_request(self, builder, get_updates): for argument in arguments: if argument == "self": continue + if argument == "media_write_timeout" and get_updates: + # get_updates never makes media requests + continue assert hasattr(builder, prefix + argument), f"missing method {prefix}{argument}" @pytest.mark.parametrize("bot_class", [Bot, ExtBot]) @@ -202,6 +205,7 @@ def test_mutually_exclusive_for_bot(self, builder, method, description): "pool_timeout", "read_timeout", "write_timeout", + "media_write_timeout", "proxy", "proxy_url", "socket_options", @@ -272,6 +276,7 @@ def test_mutually_exclusive_for_get_updates_request(self, builder, method): "pool_timeout", "read_timeout", "write_timeout", + "media_write_timeout", "proxy", "proxy_url", "socket_options", @@ -316,6 +321,7 @@ def test_mutually_exclusive_for_updater(self, builder, method): "pool_timeout", "read_timeout", "write_timeout", + "media_write_timeout", "proxy", "proxy_url", "socket_options", @@ -384,12 +390,20 @@ class Client: http2: object transport: object = None + original_init = HTTPXRequest.__init__ + media_write_timeout = [] + + def init_httpx_request(self_, *args, **kwargs): + media_write_timeout.append(kwargs.get("media_write_timeout")) + original_init(self_, *args, **kwargs) + monkeypatch.setattr(httpx, "AsyncClient", Client) + monkeypatch.setattr(HTTPXRequest, "__init__", init_httpx_request) builder = ApplicationBuilder().token(bot.token) builder.connection_pool_size(1).connect_timeout(2).pool_timeout(3).read_timeout( 4 - ).write_timeout(5).http_version("1.1") + ).write_timeout(5).media_write_timeout(6).http_version("1.1") getattr(builder, proxy_method)("proxy") app = builder.build() client = app.bot.request._client @@ -399,7 +413,9 @@ class Client: assert client.proxy == "proxy" assert client.http1 is True assert client.http2 is False + assert media_write_timeout == [6, None] + media_write_timeout.clear() builder = ApplicationBuilder().token(bot.token) builder.get_updates_connection_pool_size(1).get_updates_connect_timeout( 2 @@ -417,6 +433,7 @@ class Client: assert client.proxy == "get_updates_proxy" assert client.http1 is True assert client.http2 is False + assert media_write_timeout == [None, None] def test_custom_socket_options(self, builder, monkeypatch, bot): httpx_request_kwargs = [] diff --git a/tests/request/test_request.py b/tests/request/test_request.py index 8dddd0e3f7a..47e7d2125f6 100644 --- a/tests/request/test_request.py +++ b/tests/request/test_request.py @@ -738,6 +738,39 @@ async def request(_, **kwargs): # other than HTTPXRequest assert len(recwarn) == 0 + @pytest.mark.parametrize("init", [True, False]) + async def test_setting_media_write_timeout( + self, monkeypatch, init, input_media_photo, recwarn # noqa: F811 + ): + httpx_request = HTTPXRequest(media_write_timeout=42) if init else HTTPXRequest() + + async def request(_, **kwargs): + self.test_flag = kwargs["timeout"].write + return httpx.Response(HTTPStatus.OK, content=b'{"ok": "True", "result": {}}') + + monkeypatch.setattr(httpx.AsyncClient, "request", request) + + data = {"string": "string", "int": 1, "float": 1.0, "media": input_media_photo} + request_data = RequestData( + parameters=[RequestParameter.from_input(key, value) for key, value in data.items()], + ) + + # First make sure that custom timeouts are always respected + await httpx_request.post( + "url", + request_data, + write_timeout=43, + ) + assert self.test_flag == 43 + + # Now also ensure that the init value is respected + await httpx_request.post("url", request_data) + assert self.test_flag == 42 if init else 20 + + # Just for double-checking, since warnings are issued for implementations of BaseRequest + # other than HTTPXRequest + assert len(recwarn) == 0 + async def test_socket_opts(self, monkeypatch): transport_kwargs = {} transport_init = AsyncHTTPTransport.__init__ From 26f943771b23a83798e4fb880dad7a358f886259 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:11:03 +0100 Subject: [PATCH 07/17] Apply `pre-commit` Checks More Widely (#4135) --- .pre-commit-config.yaml | 6 +-- README_RAW.rst | 4 +- docs/__init__.py | 0 docs/auxil/__init__.py | 0 docs/auxil/admonition_inserter.py | 59 +++++++++++---------- docs/auxil/kwargs_insertion.py | 6 +-- docs/auxil/link_code.py | 8 +-- docs/auxil/sphinx_hooks.py | 14 ++--- docs/auxil/tg_const_role.py | 3 +- docs/source/conf.py | 9 ++-- pyproject.toml | 1 + setup.cfg | 2 +- setup.py | 88 +++++++++++++++---------------- setup-raw.py => setup_raw.py | 0 telegram/_utils/enum.py | 2 +- telegram/constants.py | 2 +- tests/test_meta.py | 2 +- 17 files changed, 105 insertions(+), 101 deletions(-) create mode 100644 docs/__init__.py create mode 100644 docs/auxil/__init__.py rename setup-raw.py => setup_raw.py (100%) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 890060ec7f0..3e7f3bfa914 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,6 @@ repos: hooks: - id: ruff name: ruff - files: ^(telegram|examples|tests)/.*\.py$ additional_dependencies: - httpx~=0.27.0 - tornado~=6.4 @@ -32,7 +31,7 @@ repos: rev: v3.0.3 hooks: - id: pylint - files: ^(telegram|examples)/.*\.py$ + files: ^(?!(tests|docs)).*\.py$ additional_dependencies: - httpx~=0.27.0 - tornado~=6.4 @@ -45,7 +44,7 @@ repos: hooks: - id: mypy name: mypy-ptb - files: ^telegram/.*\.py$ + files: ^(?!(tests|examples|docs)).*\.py$ additional_dependencies: - types-pytz - types-cryptography @@ -71,7 +70,6 @@ repos: rev: v3.15.0 hooks: - id: pyupgrade - files: ^(telegram|examples|tests|docs)/.*\.py$ args: - --py38-plus - repo: https://github.com/pycqa/isort diff --git a/README_RAW.rst b/README_RAW.rst index f3428cefbe5..d61101d7cb7 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -108,12 +108,12 @@ You can also install ``python-telegram-bot-raw`` from source, though this is usu $ git clone https://github.com/python-telegram-bot/python-telegram-bot $ cd python-telegram-bot - $ python setup-raw.py install + $ python setup_raw.py install Note ---- -Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup-raw.py`` instead of ``setup.py``. +Installing the ``.tar.gz`` archive available on PyPi directly via ``pip`` will *not* work as expected, as ``pip`` does not recognize that it should use ``setup_raw.py`` instead of ``setup.py``. Verifying Releases ------------------ diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/auxil/__init__.py b/docs/auxil/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/auxil/admonition_inserter.py b/docs/auxil/admonition_inserter.py index 9b1ddc98a43..4227a845382 100644 --- a/docs/auxil/admonition_inserter.py +++ b/docs/auxil/admonition_inserter.py @@ -64,7 +64,7 @@ class AdmonitionInserter: ForwardRef('DefaultValue[DVValueType]') """ - METHOD_NAMES_FOR_BOT_AND_APPBUILDER: dict[type, str] = { + METHOD_NAMES_FOR_BOT_AND_APPBUILDER: typing.ClassVar[dict[type, str]] = { cls: tuple(m[0] for m in _iter_own_public_methods(cls)) # m[0] means we take only names for cls in (telegram.Bot, telegram.ext.ApplicationBuilder) } @@ -159,7 +159,7 @@ def _create_available_in(self) -> dict[type, str]: telegram.ext, inspect.isclass ) - for class_name, inspected_class in classes_to_inspect: + for _class_name, inspected_class in classes_to_inspect: # We need to make "" into # "telegram.StickerSet" because that's the way the classes are mentioned in # docstrings. @@ -197,8 +197,8 @@ def _create_available_in(self) -> dict[type, str]: "Error generating Sphinx 'Available in' admonition " f"(admonition_inserter.py). Class {name_of_class_in_attr} present in " f"attribute {target_attr} of class {name_of_inspected_class_in_docstr}" - f" could not be resolved. {str(e)}" - ) + f" could not be resolved. {e!s}" + ) from e # Properties need to be parsed separately because they act like attributes but not # listed as attributes. @@ -240,8 +240,8 @@ def _create_available_in(self) -> dict[type, str]: "Error generating Sphinx 'Available in' admonition " f"(admonition_inserter.py). Class {name_of_class_in_prop} present in " f"property {prop_name} of class {name_of_inspected_class_in_docstr}" - f" could not be resolved. {str(e)}" - ) + f" could not be resolved. {e!s}" + ) from e return self._generate_admonitions(attrs_for_class, admonition_type="available_in") @@ -271,8 +271,8 @@ def _create_returned_in(self) -> dict[type, str]: raise NotImplementedError( "Error generating Sphinx 'Returned in' admonition " f"(admonition_inserter.py). {cls}, method {method_name}. " - f"Couldn't resolve type hint in return annotation {ret_annot}. {str(e)}" - ) + f"Couldn't resolve type hint in return annotation {ret_annot}. {e!s}" + ) from e return self._generate_admonitions(methods_for_class, admonition_type="returned_in") @@ -297,7 +297,7 @@ def _create_shortcuts(self) -> dict[collections.abc.Callable, str]: # inspect methods of all telegram classes for return statements that indicate # that this given method is a shortcut for a Bot method - for class_name, cls in inspect.getmembers(telegram, predicate=inspect.isclass): + for _class_name, cls in inspect.getmembers(telegram, predicate=inspect.isclass): # no need to inspect Bot's own methods, as Bot can't have shortcuts in Bot if cls is telegram.Bot: continue @@ -344,8 +344,8 @@ def _create_use_in(self) -> dict[type, str]: raise NotImplementedError( "Error generating Sphinx 'Use in' admonition " f"(admonition_inserter.py). {cls}, method {method_name}, parameter " - f"{param}: Couldn't resolve type hint {param.annotation}. {str(e)}" - ) + f"{param}: Couldn't resolve type hint {param.annotation}. {e!s}" + ) from e return self._generate_admonitions(methods_for_class, admonition_type="use_in") @@ -359,17 +359,19 @@ def _find_insert_pos_for_admonition(lines: list[str]) -> int: If no key phrases are found, the admonition will be inserted at the very end. """ for idx, value in list(enumerate(lines)): - if ( - value.startswith(".. seealso:") - # The docstring contains heading "Examples:", but Sphinx will have it converted - # to ".. admonition: Examples": - or value.startswith(".. admonition:: Examples") - or value.startswith(".. version") - # The space after ":param" is important because docstring can contain ":paramref:" - # in its plain text in the beginning of a line (e.g. ExtBot): - or value.startswith(":param ") - # some classes (like "Credentials") have no params, so insert before attrs: - or value.startswith(".. attribute::") + if value.startswith( + ( + ".. seealso:", + # The docstring contains heading "Examples:", but Sphinx will have it converted + # to ".. admonition: Examples": + ".. admonition:: Examples", + ".. version", + # The space after ":param" is important because docstring can contain + # ":paramref:" in its plain text in the beginning of a line (e.g. ExtBot): + ":param ", + # some classes (like "Credentials") have no params, so insert before attrs: + ".. attribute::", + ) ): return idx return len(lines) - 1 @@ -411,7 +413,7 @@ def _generate_admonitions( # so its page needs no admonitions. continue - attrs = sorted(attrs) + sorted_attrs = sorted(attrs) # e.g. for admonition type "use_in" the title will be "Use in" and CSS class "use-in". admonition = f""" @@ -419,11 +421,11 @@ def _generate_admonitions( .. admonition:: {admonition_type.title().replace("_", " ")} :class: {admonition_type.replace("_", "-")} """ - if len(attrs) > 1: - for target_attr in attrs: + if len(sorted_attrs) > 1: + for target_attr in sorted_attrs: admonition += "\n * " + target_attr else: - admonition += f"\n {attrs[0]}" + admonition += f"\n {sorted_attrs[0]}" admonition += "\n " # otherwise an unexpected unindent warning will be issued admonition_for_class[cls] = admonition @@ -516,12 +518,12 @@ def _resolve_arg(self, arg: Any) -> Iterator[Union[type, None]]: # If it isn't resolved, we'll have the program throw an exception to be sure. try: cls = self._resolve_class(m.group("class_name")) - except AttributeError: + except AttributeError as exc: # skip known ForwardRef's that need not be resolved to a Telegram class if self.FORWARD_REF_SKIP_PATTERN.match(str(arg)): pass else: - raise NotImplementedError(f"Could not process ForwardRef: {arg}") + raise NotImplementedError(f"Could not process ForwardRef: {arg}") from exc else: yield cls @@ -587,6 +589,7 @@ def _resolve_class(name: str) -> Union[type, None]: # If neither option works, this is not a PTB class. except (NameError, AttributeError): continue + return None if __name__ == "__main__": diff --git a/docs/auxil/kwargs_insertion.py b/docs/auxil/kwargs_insertion.py index a67d542f4f8..ffb2ada137a 100644 --- a/docs/auxil/kwargs_insertion.py +++ b/docs/auxil/kwargs_insertion.py @@ -16,6 +16,7 @@ # 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 inspect +from typing import List keyword_args = [ "Keyword Arguments:", @@ -84,13 +85,12 @@ ] -def find_insert_pos_for_kwargs(lines: list[str]) -> int: +def find_insert_pos_for_kwargs(lines: List[str]) -> int: """Finds the correct position to insert the keyword arguments and returns the index.""" for idx, value in reversed(list(enumerate(lines))): # reversed since :returns: is at the end if value.startswith("Returns"): return idx - else: - return False + return False def check_timeout_and_api_kwargs_presence(obj: object) -> int: diff --git a/docs/auxil/link_code.py b/docs/auxil/link_code.py index f54479e01f1..8c20f34b4af 100644 --- a/docs/auxil/link_code.py +++ b/docs/auxil/link_code.py @@ -20,6 +20,8 @@ https://github.com/sphinx-doc/sphinx/issues/1556 is closed """ import subprocess +from pathlib import Path +from typing import Dict, Tuple from sphinx.util import logging @@ -30,7 +32,7 @@ # must be a module-level variable so that it can be written to by the `autodoc-process-docstring` # event handler in `sphinx_hooks.py` -LINE_NUMBERS = {} +LINE_NUMBERS: Dict[str, Tuple[Path, int, int]] = {} def _git_branch() -> str: @@ -52,7 +54,7 @@ def _git_branch() -> str: base_url = "https://github.com/python-telegram-bot/python-telegram-bot/blob/" -def linkcode_resolve(_, info): +def linkcode_resolve(_, info) -> str: """See www.sphinx-doc.org/en/master/usage/extensions/linkcode.html""" combined = ".".join((info["module"], info["fullname"])) # special casing for ExtBot which is due to the special structure of extbot.rst @@ -71,7 +73,7 @@ def linkcode_resolve(_, info): line_info = LINE_NUMBERS.get(info["module"]) if not line_info: - return + return None file, start_line, end_line = line_info return f"{base_url}{git_branch}/{file}#L{start_line}-L{end_line}" diff --git a/docs/auxil/sphinx_hooks.py b/docs/auxil/sphinx_hooks.py index c9bd8bbe4fa..3074ac7afb3 100644 --- a/docs/auxil/sphinx_hooks.py +++ b/docs/auxil/sphinx_hooks.py @@ -67,9 +67,9 @@ def autodoc_skip_member(app, what, name, obj, skip, options): return True break - if name == "filter" and obj.__module__ == "telegram.ext.filters": - if not included_in_obj: - return True # return True to exclude from docs. + if name == "filter" and obj.__module__ == "telegram.ext.filters" and not included_in_obj: + return True # return True to exclude from docs. + return None def autodoc_process_docstring( @@ -118,7 +118,7 @@ def autodoc_process_docstring( ): effective_insert: list[str] = media_write_timeout_deprecation elif get_updates and to_insert.lstrip().startswith("read_timeout"): - effective_insert = [to_insert] + get_updates_read_timeout_addition + effective_insert = [to_insert, *get_updates_read_timeout_addition] else: effective_insert = [to_insert] @@ -166,11 +166,11 @@ def autodoc_process_docstring( autodoc_process_docstring(app, "method", f"{name}.__init__", obj.__init__, options, lines) -def autodoc_process_bases(app, name, obj, option, bases: list): +def autodoc_process_bases(app, name, obj, option, bases: list) -> None: """Here we fine tune how the base class's classes are displayed.""" - for idx, base in enumerate(bases): + for idx, raw_base in enumerate(bases): # let's use a string representation of the object - base = str(base) + base = str(raw_base) # Special case for abstract context managers which are wrongly resoled for some reason if base.startswith("typing.AbstractAsyncContextManager"): diff --git a/docs/auxil/tg_const_role.py b/docs/auxil/tg_const_role.py index 35c8bf3b1dd..d4d5961ad7f 100644 --- a/docs/auxil/tg_const_role.py +++ b/docs/auxil/tg_const_role.py @@ -81,11 +81,12 @@ def process_link( ): return repr(value), target sphinx_logger.warning( - f"%s:%d: WARNING: Did not convert reference %s. :{CONSTANTS_ROLE}: is not supposed" + "%s:%d: WARNING: Did not convert reference %s. :%s: is not supposed" " to be used with this type of target.", refnode.source, refnode.line, refnode.rawsource, + CONSTANTS_ROLE, ) return title, target except Exception as exc: diff --git a/docs/source/conf.py b/docs/source/conf.py index 5d3f3556780..c890a4af460 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,4 +1,3 @@ -import os import re import sys from pathlib import Path @@ -8,7 +7,7 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. from sphinx.application import Sphinx -sys.path.insert(0, os.path.abspath("../..")) +sys.path.insert(0, str(Path("../..").resolve().absolute())) # -- General configuration ------------------------------------------------ # General information about the project. @@ -310,13 +309,13 @@ # Due to Sphinx behaviour, these imports only work when imported here, not at top of module. # Not used but must be imported for the linkcode extension to find it -from docs.auxil.link_code import linkcode_resolve -from docs.auxil.sphinx_hooks import ( +from docs.auxil.link_code import linkcode_resolve # noqa: E402, F401 +from docs.auxil.sphinx_hooks import ( # noqa: E402 autodoc_process_bases, autodoc_process_docstring, autodoc_skip_member, ) -from docs.auxil.tg_const_role import CONSTANTS_ROLE, TGConstXRefRole +from docs.auxil.tg_const_role import CONSTANTS_ROLE, TGConstXRefRole # noqa: E402 def setup(app: Sphinx): diff --git a/pyproject.toml b/pyproject.toml index 233af8fecb4..b941a244486 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET [tool.ruff.lint.per-file-ignores] "tests/*.py" = ["B018"] "tests/**.py" = ["RUF012", "ASYNC101"] +"docs/**.py" = ["INP001"] # PYLINT: [tool.pylint."messages control"] diff --git a/setup.cfg b/setup.cfg index 2067f25afef..278056b06d2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,4 +5,4 @@ license_files = LICENSE, LICENSE.dual, LICENSE.lesser max-line-length = 99 ignore = W503, W605 extend-ignore = E203, E704 -exclude = setup.py, setup-raw.py docs/source/conf.py +exclude = setup.py, setup_raw.py docs/source/conf.py diff --git a/setup.py b/setup.py index 01ec10e84cc..ef619d2ef67 100644 --- a/setup.py +++ b/setup.py @@ -4,15 +4,16 @@ import sys from collections import defaultdict from pathlib import Path +from typing import Any, Dict, List, Tuple from setuptools import find_packages, setup -def get_requirements(): +def get_requirements() -> List[str]: """Build the requirements list for this project""" requirements_list = [] - with Path("requirements.txt").open() as reqs: + with Path("requirements.txt").open(encoding="utf-8") as reqs: for install in reqs: if install.startswith("#"): continue @@ -21,7 +22,7 @@ def get_requirements(): return requirements_list -def get_packages_requirements(raw=False): +def get_packages_requirements(raw: bool = False) -> Tuple[List[str], List[str]]: """Build the package & requirements list for this project""" reqs = get_requirements() @@ -34,68 +35,69 @@ def get_packages_requirements(raw=False): return packs, reqs -def get_optional_requirements(raw=False): +def get_optional_requirements(raw: bool = False) -> Dict[str, List[str]]: """Build the optional dependencies""" requirements = defaultdict(list) - with Path("requirements-opts.txt").open() as reqs: + with Path("requirements-opts.txt").open(encoding="utf-8") as reqs: for line in reqs: - line = line.strip() - if not line or line.startswith("#"): + effective_line = line.strip() + if not effective_line or effective_line.startswith("#"): continue - dependency, names = line.split("#") + dependency, names = effective_line.split("#") dependency = dependency.strip() for name in names.split(","): - name = name.strip() - if name.endswith("!ext"): + effective_name = name.strip() + if effective_name.endswith("!ext"): if raw: continue - else: - name = name[:-4] - requirements["ext"].append(dependency) - requirements[name].append(dependency) + effective_name = effective_name[:-4] + requirements["ext"].append(dependency) + requirements[effective_name].append(dependency) requirements["all"].append(dependency) return requirements -def get_setup_kwargs(raw=False): +def get_setup_kwargs(raw: bool = False) -> Dict[str, Any]: """Builds a dictionary of kwargs for the setup function""" packages, requirements = get_packages_requirements(raw=raw) raw_ext = "-raw" if raw else "" readme = Path(f'README{"_RAW" if raw else ""}.rst') - version_file = Path("telegram/_version.py").read_text() + version_file = Path("telegram/_version.py").read_text(encoding="utf-8") first_part = version_file.split("# SETUP.PY MARKER")[0] - exec(first_part) - - kwargs = dict( - script_name=f"setup{raw_ext}.py", - name=f"python-telegram-bot{raw_ext}", - version=locals()["__version__"], - author="Leandro Toledo", - author_email="devs@python-telegram-bot.org", - license="LGPLv3", - url="https://python-telegram-bot.org/", - # Keywords supported by PyPI can be found at https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/warehouse/templates/packaging/detail.html#L20-L58 - project_urls={ + exec(first_part) # pylint: disable=exec-used + + return { + "script_name": f"setup{raw_ext}.py", + "name": f"python-telegram-bot{raw_ext}", + "version": locals()["__version__"], + "author": "Leandro Toledo", + "author_email": "devs@python-telegram-bot.org", + "license": "LGPLv3", + "url": "https://python-telegram-bot.org/", + # Keywords supported by PyPI can be found at + # https://github.com/pypa/warehouse/blob/aafc5185e57e67d43487ce4faa95913dd4573e14/ + # warehouse/templates/packaging/detail.html#L20-L58 + "project_urls": { "Documentation": "https://docs.python-telegram-bot.org", "Bug Tracker": "https://github.com/python-telegram-bot/python-telegram-bot/issues", "Source Code": "https://github.com/python-telegram-bot/python-telegram-bot", "News": "https://t.me/pythontelegrambotchannel", "Changelog": "https://docs.python-telegram-bot.org/en/stable/changelog.html", }, - download_url=f"https://pypi.org/project/python-telegram-bot{raw_ext}/", - keywords="python telegram bot api wrapper", - description="We have made you a wrapper you can't refuse", - long_description=readme.read_text(), - long_description_content_type="text/x-rst", - packages=packages, - install_requires=requirements, - extras_require=get_optional_requirements(raw=raw), - include_package_data=True, - classifiers=[ + "download_url": f"https://pypi.org/project/python-telegram-bot{raw_ext}/", + "keywords": "python telegram bot api wrapper", + "description": "We have made you a wrapper you can't refuse", + "long_description": readme.read_text(encoding="utf-8"), + "long_description_content_type": "text/x-rst", + "packages": packages, + "install_requires": requirements, + "extras_require": get_optional_requirements(raw=raw), + "include_package_data": True, + "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)", @@ -111,16 +113,14 @@ def get_setup_kwargs(raw=False): "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ], - python_requires=">=3.8", - ) + "python_requires": ">=3.8", + } - return kwargs - -def main(): +def main() -> None: # If we're building, build ptb-raw as well if set(sys.argv[1:]) in [{"bdist_wheel"}, {"sdist"}, {"sdist", "bdist_wheel"}]: - args = ["python", "setup-raw.py"] + args = ["python", "setup_raw.py"] args.extend(sys.argv[1:]) subprocess.run(args, check=True, capture_output=True) diff --git a/setup-raw.py b/setup_raw.py similarity index 100% rename from setup-raw.py rename to setup_raw.py diff --git a/telegram/_utils/enum.py b/telegram/_utils/enum.py index 20a045c02fe..aa370cbd44a 100644 --- a/telegram/_utils/enum.py +++ b/telegram/_utils/enum.py @@ -60,7 +60,7 @@ def __str__(self) -> str: # Apply the __repr__ modification and __str__ fix to IntEnum -class IntEnum(_enum.IntEnum): # pylint: disable=invalid-slots +class IntEnum(_enum.IntEnum): """Helper class for int enums where ``str(member)`` prints the value, but ``repr(member)`` gives ``EnumName.MEMBER_NAME``. """ diff --git a/telegram/constants.py b/telegram/constants.py index d78dd8280a7..01cab88d072 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -29,7 +29,7 @@ * Most of the constants in this module are grouped into enums. """ # TODO: Remove this when https://github.com/PyCQA/pylint/issues/6887 is resolved. -# pylint: disable=invalid-enum-extension,invalid-slots +# pylint: disable=invalid-enum-extension __all__ = [ "BOT_API_VERSION", diff --git a/tests/test_meta.py b/tests/test_meta.py index 077f9ae0544..fd698585dbb 100644 --- a/tests/test_meta.py +++ b/tests/test_meta.py @@ -40,4 +40,4 @@ def test_build(): @skip_disabled def test_build_raw(): - assert os.system("python setup-raw.py bdist_dumb") == 0 # pragma: no cover + assert os.system("python setup_raw.py bdist_dumb") == 0 # pragma: no cover From 099ab5d9faca96725b9a77fcb2a257287e1dae4a Mon Sep 17 00:00:00 2001 From: Poolitzer Date: Sat, 2 Mar 2024 10:56:15 +0100 Subject: [PATCH 08/17] API 7.1 (#4118) Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com> --- .github/workflows/docs.yml | 7 +- .github/workflows/test_official.yml | 5 +- .github/workflows/type_completeness.yml | 4 +- .github/workflows/unit_tests.yml | 7 +- README.rst | 4 +- README_RAW.rst | 4 +- docs/source/telegram.at-tree.rst | 1 + docs/source/telegram.chatboostadded.rst | 6 ++ docs/substitutions/global.rst | 2 + telegram/__init__.py | 2 + telegram/_bot.py | 14 ++-- telegram/_chat.py | 26 ++++++++ telegram/_chatadministratorrights.py | 58 +++++++++++------ telegram/_chatboost.py | 33 ++++++++++ telegram/_chatmember.py | 59 +++++++++++------ telegram/_message.py | 38 ++++++++++- telegram/_story.py | 51 +++++++++++++-- telegram/constants.py | 17 ++++- telegram/ext/filters.py | 36 ++++++++++ tests/ext/test_filters.py | 21 ++++++ tests/test_chat.py | 10 +++ tests/test_chatadministratorrights.py | 87 +++++++++++++++++++++++-- tests/test_chatboost.py | 40 ++++++++++++ tests/test_chatmember.py | 25 ++++++- tests/test_chatmemberupdated.py | 32 ++++++++- tests/test_keyboardbuttonrequest.py | 24 ++++++- tests/test_message.py | 9 ++- tests/test_official/exceptions.py | 9 ++- tests/test_story.py | 47 ++++++++++--- 29 files changed, 580 insertions(+), 98 deletions(-) create mode 100644 docs/source/telegram.chatboostadded.rst diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 70f83574d35..ea1173d6986 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,13 +1,12 @@ name: Test Documentation Build on: pull_request: - branches: - - master - - doc-fixes + paths: + - telegram/** + - docs/** push: branches: - master - - doc-fixes jobs: test-sphinx-build: diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index 9b972694616..d4853781142 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -1,8 +1,9 @@ name: Bot API Tests on: pull_request: - branches: - - master + paths: + - telegram/** + - tests/** push: branches: - master diff --git a/.github/workflows/type_completeness.yml b/.github/workflows/type_completeness.yml index 14e84d4d3e1..ac3b9934e9b 100644 --- a/.github/workflows/type_completeness.yml +++ b/.github/workflows/type_completeness.yml @@ -1,8 +1,8 @@ name: Check Type Completeness on: pull_request: - branches: - - master + paths: + - telegram/** push: branches: - master diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 1f45f0ab895..682ceead685 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -1,13 +1,12 @@ name: Unit Tests on: pull_request: - branches: - - master - + paths: + - telegram/** + - tests/** push: branches: - master - schedule: # Run monday and friday morning at 03:07 - odd time to spread load on GitHub Actions - cron: '7 3 * * 1,5' diff --git a/README.rst b/README.rst index 993e7239689..07dca0d2cf7 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.0-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -93,7 +93,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.0** are supported. +All types and methods of the Telegram Bot API **7.1** are supported. Installing ========== diff --git a/README_RAW.rst b/README_RAW.rst index d61101d7cb7..75dec821cba 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -14,7 +14,7 @@ :target: https://pypi.org/project/python-telegram-bot-raw/ :alt: Supported Python versions -.. image:: https://img.shields.io/badge/Bot%20API-7.0-blue?logo=telegram +.. image:: https://img.shields.io/badge/Bot%20API-7.1-blue?logo=telegram :target: https://core.telegram.org/bots/api-changelog :alt: Supported Bot API versions @@ -89,7 +89,7 @@ Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conju Telegram API support ==================== -All types and methods of the Telegram Bot API **7.0** are supported. +All types and methods of the Telegram Bot API **7.1** are supported. Installing ========== diff --git a/docs/source/telegram.at-tree.rst b/docs/source/telegram.at-tree.rst index ed71b5f6760..ffa7107b89e 100644 --- a/docs/source/telegram.at-tree.rst +++ b/docs/source/telegram.at-tree.rst @@ -22,6 +22,7 @@ Available Types telegram.chat telegram.chatadministratorrights telegram.chatboost + telegram.chatboostadded telegram.chatboostremoved telegram.chatboostsource telegram.chatboostsourcegiftcode diff --git a/docs/source/telegram.chatboostadded.rst b/docs/source/telegram.chatboostadded.rst new file mode 100644 index 00000000000..b4551e75b84 --- /dev/null +++ b/docs/source/telegram.chatboostadded.rst @@ -0,0 +1,6 @@ +ChatBoostAdded +============== + +.. autoclass:: telegram.ChatBoostAdded + :members: + :show-inheritance: \ No newline at end of file diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 228bd459bac..050a6d52b9e 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -77,3 +77,5 @@ .. |reply_quote| replace:: If set to :obj:`True`, the reply is sent as an actual reply to this message. If ``reply_to_message_id`` is passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. .. |do_quote| replace:: If set to :obj:`True`, the replied message is quoted. For a dict, it must be the output of :meth:`~telegram.Message.build_reply_arguments` to specify exact ``reply_parameters``. If ``reply_to_message_id`` or ``reply_parameters`` are passed, this parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. + +.. |non_optional_story_argument| replace:: As of this version, this argument is now required. In accordance with our `stability policy `__, the signature will be kept as optional for now, though they are mandatory and an error will be raised if you don't pass it. diff --git a/telegram/__init__.py b/telegram/__init__.py index 8e58edb33e8..162ba3d0edb 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -40,6 +40,7 @@ "Chat", "ChatAdministratorRights", "ChatBoost", + "ChatBoostAdded", "ChatBoostRemoved", "ChatBoostSource", "ChatBoostSourceGiftCode", @@ -242,6 +243,7 @@ from ._chatadministratorrights import ChatAdministratorRights from ._chatboost import ( ChatBoost, + ChatBoostAdded, ChatBoostRemoved, ChatBoostSource, ChatBoostSourceGiftCode, diff --git a/telegram/_bot.py b/telegram/_bot.py index 4ca0ff267b7..dc6c66aab7c 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -5250,10 +5250,10 @@ async def promote_chat_member( user_id (:obj:`int`): Unique identifier of the target user. is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence in the chat is hidden. - can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - access the chat event log, chat statistics, boost list in channels, see channel - members, report spam messages, see anonymous administrators in supergroups and - ignore slow mode. Implied by any other administrator privilege. + can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + access the chat event log, get boost list, see hidden supergroup and channel + members, report spam messages and ignore slow mode. Implied by any other + administrator privilege. .. versionadded:: 13.4 @@ -5285,15 +5285,15 @@ async def promote_chat_member( .. versionadded:: 20.0 can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - post stories in the channel; channels only. + post stories to the chat. .. versionadded:: 20.6 can_edit_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit stories posted by other users; channels only. + edit stories posted by other users. .. versionadded:: 20.6 can_delete_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - delete stories posted by other users; channels only. + delete stories posted by other users. .. versionadded:: 20.6 diff --git a/telegram/_chat.py b/telegram/_chat.py index e830e83c2f2..d308cc0f265 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -219,6 +219,16 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + unrestrict_boost_count (:obj:`int`, optional): For supergroups, the minimum number of + boosts that a non-administrator user needs to add in order to ignore slow mode and chat + permissions. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION + custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the + group's custom emoji sticker set. Custom emoji from this set can be used by all users + and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION Attributes: id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits @@ -352,6 +362,16 @@ class Chat(TelegramObject): :meth:`telegram.Bot.get_chat`. .. versionadded:: 20.0 + unrestrict_boost_count (:obj:`int`): Optional. For supergroups, the minimum number of + boosts that a non-administrator user needs to add in order to ignore slow mode and chat + permissions. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION + custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the + group's custom emoji sticker set. Custom emoji from this set can be used by all users + and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. + + .. versionadded:: NEXT.VERSION .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups .. _accent colors: https://core.telegram.org/bots/api#accent-colors @@ -364,6 +384,7 @@ class Chat(TelegramObject): "background_custom_emoji_id", "bio", "can_set_sticker_set", + "custom_emoji_sticker_set_name", "description", "emoji_status_custom_emoji_id", "emoji_status_expiration_date", @@ -392,6 +413,7 @@ class Chat(TelegramObject): "sticker_set_name", "title", "type", + "unrestrict_boost_count", "username", ) @@ -446,6 +468,8 @@ def __init__( profile_accent_color_id: Optional[int] = None, profile_background_custom_emoji_id: Optional[str] = None, has_visible_history: Optional[bool] = None, + unrestrict_boost_count: Optional[int] = None, + custom_emoji_sticker_set_name: Optional[str] = None, *, api_kwargs: Optional[JSONDict] = None, ): @@ -493,6 +517,8 @@ def __init__( self.background_custom_emoji_id: Optional[str] = background_custom_emoji_id self.profile_accent_color_id: Optional[int] = profile_accent_color_id self.profile_background_custom_emoji_id: Optional[str] = profile_background_custom_emoji_id + self.unrestrict_boost_count: Optional[int] = unrestrict_boost_count + self.custom_emoji_sticker_set_name: Optional[str] = custom_emoji_sticker_set_name self._id_attrs = (self.id,) diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index a6ec888ecfe..35e1adaac0d 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -47,9 +47,8 @@ class ChatAdministratorRights(TelegramObject): Args: is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video @@ -70,18 +69,24 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post - stories in the channel; channels only. + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -90,9 +95,8 @@ class ChatAdministratorRights(TelegramObject): Attributes: is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the administrator can manage video @@ -113,18 +117,24 @@ class ChatAdministratorRights(TelegramObject): messages of other users. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - stories in the channel; channels only. + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -179,13 +189,19 @@ def __init__( self.can_promote_members: bool = can_promote_members self.can_change_info: bool = can_change_info self.can_invite_users: bool = can_invite_users + # Not actually optionals but because of backwards compatability we pretend they are + if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: + raise TypeError( + "As of vNEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories" + " must be set in order to create this object." + ) + self.can_post_stories: bool = can_post_stories + self.can_edit_stories: bool = can_edit_stories + self.can_delete_stories: bool = can_delete_stories # Optionals self.can_post_messages: Optional[bool] = can_post_messages self.can_edit_messages: Optional[bool] = can_edit_messages self.can_pin_messages: Optional[bool] = can_pin_messages - self.can_post_stories: Optional[bool] = can_post_stories - self.can_edit_stories: Optional[bool] = can_edit_stories - self.can_delete_stories: Optional[bool] = can_delete_stories self.can_manage_topics: Optional[bool] = can_manage_topics self._id_attrs = ( diff --git a/telegram/_chatboost.py b/telegram/_chatboost.py index 71d299de0b3..f16cf9db0eb 100644 --- a/telegram/_chatboost.py +++ b/telegram/_chatboost.py @@ -34,6 +34,39 @@ from telegram import Bot +class ChatBoostAdded(TelegramObject): + """ + This object represents a service message about a user boosting a chat. + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`boost_count` are equal. + + .. versionadded:: NEXT.VERSION + + Args: + boost_count (:obj:`int`): Number of boosts added by the user. + + Attributes: + boost_count (:obj:`int`): Number of boosts added by the user. + + """ + + __slots__ = ("boost_count",) + + def __init__( + self, + boost_count: int, + *, + api_kwargs: Optional[JSONDict] = None, + ) -> None: + super().__init__(api_kwargs=api_kwargs) + self.boost_count: int = boost_count + self._id_attrs = (self.boost_count,) + + self._freeze() + + class ChatBoostSource(TelegramObject): """ Base class for Telegram ChatBoostSource objects. It can be one of: diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index 301130b7d79..6d2d35ce3f4 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -197,9 +197,8 @@ class ChatMemberAdministrator(ChatMember): is allowed to edit administrator privileges of that user. is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. - can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator - can access the chat event log, chat statistics, message statistics in - channels, see channel members, see anonymous administrators in supergroups + can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event + log, get boost list, see hidden supergroup and channel members, report spam messages and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. @@ -225,18 +224,24 @@ class ChatMemberAdministrator(ChatMember): messages; channels only. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can post - stories in the channel; channels only. + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`, optional): :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only. @@ -252,9 +257,8 @@ class ChatMemberAdministrator(ChatMember): is_anonymous (:obj:`bool`): :obj:`True`, if the user's presence in the chat is hidden. can_manage_chat (:obj:`bool`): :obj:`True`, if the administrator can access the chat event - log, chat statistics, boost list in channels, see channel members, report spam - messages, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. + log, get boost list, see hidden supergroup and channel members, report spam messages + and ignore slow mode. Implied by any other administrator privilege. can_delete_messages (:obj:`bool`): :obj:`True`, if the administrator can delete messages of other users. can_manage_video_chats (:obj:`bool`): :obj:`True`, if the @@ -279,18 +283,24 @@ class ChatMemberAdministrator(ChatMember): messages; channels only. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin messages; groups and supergroups only. - can_post_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - stories in the channel; channels only. + can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post + stories to the chat. .. versionadded:: 20.6 - can_edit_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit + stories posted by other users. .. versionadded:: 20.6 - can_delete_stories (:obj:`bool`): Optional. :obj:`True`, if the administrator can delete - stories posted by other users; channels only. + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| + can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete + stories posted by other users. .. versionadded:: 20.6 + .. versionchanged:: NEXT.VERSION + |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; supergroups only @@ -352,14 +362,21 @@ def __init__( self.can_promote_members: bool = can_promote_members self.can_change_info: bool = can_change_info self.can_invite_users: bool = can_invite_users + # Not actually optionals but because of backwards compatability we pretend they are + if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: + raise TypeError( + "As of NEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories " + "must be set in order to create this object." + ) + self.can_post_stories: bool = can_post_stories + self.can_edit_stories: bool = can_edit_stories + self.can_delete_stories: bool = can_delete_stories + # Optionals self.can_post_messages: Optional[bool] = can_post_messages self.can_edit_messages: Optional[bool] = can_edit_messages self.can_pin_messages: Optional[bool] = can_pin_messages self.can_manage_topics: Optional[bool] = can_manage_topics self.custom_title: Optional[str] = custom_title - self.can_post_stories: Optional[bool] = can_post_stories - self.can_edit_stories: Optional[bool] = can_edit_stories - self.can_delete_stories: Optional[bool] = can_delete_stories class ChatMemberMember(ChatMember): diff --git a/telegram/_message.py b/telegram/_message.py index b94210a5efa..c8662a12123 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, TypedDict, Union from telegram._chat import Chat +from telegram._chatboost import ChatBoostAdded from telegram._dice import Dice from telegram._files.animation import Animation from telegram._files.audio import Audio @@ -521,6 +522,18 @@ class Message(MaybeInaccessibleMessage): message for forwarded messages .. versionadded:: 20.8 + reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original + story. + + .. versionadded:: NEXT.VERSION + boost_added (:class:`telegram.ChatBoostAdded`, optional): Service message: user boosted + the chat. + + .. versionadded:: NEXT.VERSION + sender_boost_count (:obj:`int`, optional): If the sender of the + message boosted the chat, the number of boosts added by the user. + + .. versionadded:: NEXT.VERSION Attributes: message_id (:obj:`int`): Unique message identifier inside this chat. @@ -787,10 +800,22 @@ class Message(MaybeInaccessibleMessage): message, the quoted part of the message. .. versionadded:: 20.8 - forward_origin (:class:`telegram.MessageOrigin`, optional): Information about the original + forward_origin (:class:`telegram.MessageOrigin`): Optional. Information about the original message for forwarded messages .. versionadded:: 20.8 + reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original + story. + + .. versionadded:: NEXT.VERSION + boost_added (:class:`telegram.ChatBoostAdded`): Optional. Service message: user boosted + the chat. + + .. versionadded:: NEXT.VERSION + sender_boost_count (:obj:`int`): Optional. If the sender of the + message boosted the chat, the number of boosts added by the user. + + .. versionadded:: NEXT.VERSION .. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a @@ -807,6 +832,7 @@ class Message(MaybeInaccessibleMessage): "animation", "audio", "author_signature", + "boost_added", "caption", "caption_entities", "channel_chat_created", @@ -857,6 +883,8 @@ class Message(MaybeInaccessibleMessage): "quote", "reply_markup", "reply_to_message", + "reply_to_story", + "sender_boost_count", "sender_chat", "sticker", "story", @@ -953,6 +981,9 @@ def __init__( external_reply: Optional["ExternalReplyInfo"] = None, quote: Optional["TextQuote"] = None, forward_origin: Optional["MessageOrigin"] = None, + reply_to_story: Optional[Story] = None, + boost_added: Optional[ChatBoostAdded] = None, + sender_boost_count: Optional[int] = None, *, api_kwargs: Optional[JSONDict] = None, ): @@ -1045,6 +1076,9 @@ def __init__( self.external_reply: Optional[ExternalReplyInfo] = external_reply self.quote: Optional[TextQuote] = quote self.forward_origin: Optional[MessageOrigin] = forward_origin + self.reply_to_story: Optional[Story] = reply_to_story + self.boost_added: Optional[ChatBoostAdded] = boost_added + self.sender_boost_count: Optional[int] = sender_boost_count self._effective_attachment = DEFAULT_NONE @@ -1185,6 +1219,8 @@ def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Message"]: data["external_reply"] = ExternalReplyInfo.de_json(data.get("external_reply"), bot) data["quote"] = TextQuote.de_json(data.get("quote"), bot) data["forward_origin"] = MessageOrigin.de_json(data.get("forward_origin"), bot) + data["reply_to_story"] = Story.de_json(data.get("reply_to_story"), bot) + data["boost_added"] = ChatBoostAdded.de_json(data.get("boost_added"), bot) api_kwargs = {} # This is a deprecated field that TG still returns for backwards compatibility diff --git a/telegram/_story.py b/telegram/_story.py index cdf6dd6ad11..42e4ae06d5e 100644 --- a/telegram/_story.py +++ b/telegram/_story.py @@ -18,24 +18,65 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object related to a Telegram Story.""" -from typing import Optional +from typing import TYPE_CHECKING, Optional +from telegram._chat import Chat from telegram._telegramobject import TelegramObject from telegram._utils.types import JSONDict +if TYPE_CHECKING: + from telegram import Bot + class Story(TelegramObject): """ - This object represents a message about a forwarded story in the chat. Currently holds no - information. + This object represents a story. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`chat` and :attr:`id` are equal. .. versionadded:: 20.5 + .. versionchanged:: NEXT.VERSION + Added attributes :attr:`chat` and :attr:`id` and equality based on them. + + Args: + chat (:class:`telegram.Chat`): Chat that posted the story. + id (:obj:`int`): Unique identifier for the story in the chat. + + Attributes: + chat (:class:`telegram.Chat`): Chat that posted the story. + id (:obj:`int`): Unique identifier for the story in the chat. + """ - __slots__ = () + __slots__ = ( + "chat", + "id", + ) - def __init__(self, *, api_kwargs: Optional[JSONDict] = None) -> None: + def __init__( + self, + chat: Chat, + id: int, # pylint: disable=redefined-builtin + *, + api_kwargs: Optional[JSONDict] = None, + ) -> None: super().__init__(api_kwargs=api_kwargs) + self.chat: Chat = chat + self.id: int = id + + self._id_attrs = (self.chat, self.id) self._freeze() + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: "Bot") -> Optional["Story"]: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data["chat"] = Chat.de_json(data.get("chat", {}), bot) + return super().de_json(data=data, bot=bot) diff --git a/telegram/constants.py b/telegram/constants.py index 01cab88d072..ec5723d33e9 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -142,7 +142,7 @@ class _AccentColor(NamedTuple): #: :data:`telegram.__bot_api_version_info__`. #: #: .. versionadded:: 20.0 -BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=0) +BOT_API_VERSION_INFO: Final[_BotAPIVersion] = _BotAPIVersion(major=7, minor=1) #: :obj:`str`: Telegram Bot API #: version supported by this version of `python-telegram-bot`. Also available as #: :data:`telegram.__bot_api_version__`. @@ -1705,6 +1705,11 @@ class MessageType(StringEnum): """:obj:`str`: Messages with :attr:`telegram.Message.animation`.""" AUDIO = "audio" """:obj:`str`: Messages with :attr:`telegram.Message.audio`.""" + BOOST_ADDED = "boost_added" + """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. + + .. versionadded:: NEXT.VERSION + """ CHANNEL_CHAT_CREATED = "channel_chat_created" """:obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`.""" CHAT_SHARED = "chat_shared" @@ -1802,6 +1807,16 @@ class MessageType(StringEnum): """:obj:`str`: Messages with :attr:`telegram.Message.poll`.""" PROXIMITY_ALERT_TRIGGERED = "proximity_alert_triggered" """:obj:`str`: Messages with :attr:`telegram.Message.proximity_alert_triggered`.""" + REPLY_TO_STORY = "reply_to_story" + """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. + + .. versionadded:: NEXT.VERSION + """ + SENDER_BOOST_COUNT = "sender_boost_count" + """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. + + .. versionadded:: NEXT.VERSION + """ STICKER = "sticker" """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" STORY = "story" diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index d78fa0d979f..9754569dcef 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -41,6 +41,7 @@ "ANIMATION", "ATTACHMENT", "AUDIO", + "BOOST_ADDED", "CAPTION", "CHAT", "COMMAND", @@ -60,6 +61,8 @@ "POLL", "PREMIUM_USER", "REPLY", + "REPLY_TO_STORY", + "SENDER_BOOST_COUNT", "STORY", "SUCCESSFUL_PAYMENT", "TEXT", @@ -2789,3 +2792,36 @@ def filter(self, message: Message) -> bool: VOICE = _Voice("filters.VOICE") """Messages that contain :attr:`telegram.Message.voice`.""" + + +class _ReplyToStory(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.reply_to_story) + + +REPLY_TO_STORY = _ReplyToStory(name="filters.REPLY_TO_STORY") +"""Messages that contain :attr:`telegram.Message.reply_to_story`.""" + + +class _BoostAdded(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.boost_added) + + +BOOST_ADDED = _BoostAdded(name="filters.BOOST_ADDED") +"""Messages that contain :attr:`telegram.Message.boost_added`.""" + + +class _SenderBoostCount(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + return bool(message.sender_boost_count) + + +SENDER_BOOST_COUNT = _SenderBoostCount(name="filters.SENDER_BOOST_COUNT") +"""Messages that contain :attr:`telegram.Message.sender_boost_count`.""" diff --git a/tests/ext/test_filters.py b/tests/ext/test_filters.py index 3a0f860d81b..bcd1980914e 100644 --- a/tests/ext/test_filters.py +++ b/tests/ext/test_filters.py @@ -2700,3 +2700,24 @@ def test_filters_giveaway_winners(self, update): update.message.giveaway_winners = "test" assert filters.GIVEAWAY_WINNERS.check_update(update) assert str(filters.GIVEAWAY_WINNERS) == "filters.GIVEAWAY_WINNERS" + + def test_filters_reply_to_story(self, update): + assert not filters.REPLY_TO_STORY.check_update(update) + + update.message.reply_to_story = "test" + assert filters.REPLY_TO_STORY.check_update(update) + assert str(filters.REPLY_TO_STORY) == "filters.REPLY_TO_STORY" + + def test_filters_boost_added(self, update): + assert not filters.BOOST_ADDED.check_update(update) + + update.message.boost_added = "test" + assert filters.BOOST_ADDED.check_update(update) + assert str(filters.BOOST_ADDED) == "filters.BOOST_ADDED" + + def test_filters_sender_boost_count(self, update): + assert not filters.SENDER_BOOST_COUNT.check_update(update) + + update.message.sender_boost_count = "test" + assert filters.SENDER_BOOST_COUNT.check_update(update) + assert str(filters.SENDER_BOOST_COUNT) == "filters.SENDER_BOOST_COUNT" diff --git a/tests/test_chat.py b/tests/test_chat.py index 514b5f4e7b0..2755853e1f7 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -72,6 +72,8 @@ def chat(bot): background_custom_emoji_id=TestChatBase.background_custom_emoji_id, profile_accent_color_id=TestChatBase.profile_accent_color_id, profile_background_custom_emoji_id=TestChatBase.profile_background_custom_emoji_id, + unrestrict_boost_count=TestChatBase.unrestrict_boost_count, + custom_emoji_sticker_set_name=TestChatBase.custom_emoji_sticker_set_name, ) chat.set_bot(bot) chat._unfreeze() @@ -115,6 +117,8 @@ class TestChatBase: background_custom_emoji_id = "background_custom_emoji_id" profile_accent_color_id = 2 profile_background_custom_emoji_id = "profile_background_custom_emoji_id" + unrestrict_boost_count = 100 + custom_emoji_sticker_set_name = "custom_emoji_sticker_set_name" class TestChatWithoutRequest(TestChatBase): @@ -156,6 +160,8 @@ def test_de_json(self, bot): "background_custom_emoji_id": self.background_custom_emoji_id, "profile_accent_color_id": self.profile_accent_color_id, "profile_background_custom_emoji_id": self.profile_background_custom_emoji_id, + "unrestrict_boost_count": self.unrestrict_boost_count, + "custom_emoji_sticker_set_name": self.custom_emoji_sticker_set_name, } chat = Chat.de_json(json_dict, bot) @@ -194,6 +200,8 @@ def test_de_json(self, bot): assert chat.background_custom_emoji_id == self.background_custom_emoji_id assert chat.profile_accent_color_id == self.profile_accent_color_id assert chat.profile_background_custom_emoji_id == self.profile_background_custom_emoji_id + assert chat.unrestrict_boost_count == self.unrestrict_boost_count + assert chat.custom_emoji_sticker_set_name == self.custom_emoji_sticker_set_name def test_de_json_localization(self, bot, raw_bot, tz_bot): json_dict = { @@ -257,6 +265,8 @@ def test_to_dict(self, chat): chat_dict["profile_background_custom_emoji_id"] == chat.profile_background_custom_emoji_id ) + assert chat_dict["custom_emoji_sticker_set_name"] == chat.custom_emoji_sticker_set_name + assert chat_dict["unrestrict_boost_count"] == chat.unrestrict_boost_count def test_always_tuples_attributes(self): chat = Chat( diff --git a/tests/test_chatadministratorrights.py b/tests/test_chatadministratorrights.py index 4b49792b098..c7b30be9237 100644 --- a/tests/test_chatadministratorrights.py +++ b/tests/test_chatadministratorrights.py @@ -95,11 +95,42 @@ def test_to_dict(self, chat_admin_rights): assert admin_rights_dict["can_delete_stories"] == car.can_delete_stories def test_equality(self): - a = ChatAdministratorRights(True, *((False,) * 11)) - b = ChatAdministratorRights(True, *((False,) * 11)) - c = ChatAdministratorRights(*(False,) * 12) - d = ChatAdministratorRights(True, True, *((False,) * 10)) - e = ChatAdministratorRights(True, True, *((False,) * 10)) + a = ChatAdministratorRights( + True, + *((False,) * 11), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + b = ChatAdministratorRights( + True, + *((False,) * 11), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + c = ChatAdministratorRights( + *(False,) * 12, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + d = ChatAdministratorRights( + True, + True, + *((False,) * 10), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) + e = ChatAdministratorRights( + True, + True, + *((False,) * 10), + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) assert a == b assert hash(a) == hash(b) @@ -115,7 +146,20 @@ def test_equality(self): assert hash(d) == hash(e) def test_all_rights(self): - f = ChatAdministratorRights(True, True, True, True, True, True, True, True, True) + f = ChatAdministratorRights( + True, + True, + True, + True, + True, + True, + True, + True, + True, + can_post_stories=True, + can_edit_stories=True, + can_delete_stories=True, + ) t = ChatAdministratorRights.all_rights() # if the dirs are the same, the attributes will all be there assert dir(f) == dir(t) @@ -127,7 +171,20 @@ def test_all_rights(self): assert f != t def test_no_rights(self): - f = ChatAdministratorRights(False, False, False, False, False, False, False, False, False) + f = ChatAdministratorRights( + False, + False, + False, + False, + False, + False, + False, + False, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, + ) t = ChatAdministratorRights.no_rights() # if the dirs are the same, the attributes will all be there assert dir(f) == dir(t) @@ -137,3 +194,19 @@ def test_no_rights(self): assert t[key] is False # and as a finisher, make sure the default is different. assert f != t + + def test_depreciation_typeerror(self): + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights( + *(False,) * 12, + ) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_edit_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_delete_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_edit_stories=True, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatAdministratorRights(*(False,) * 12, can_delete_stories=True, can_post_stories=True) diff --git a/tests/test_chatboost.py b/tests/test_chatboost.py index ee0a5c9e3c3..bc33e1fe21e 100644 --- a/tests/test_chatboost.py +++ b/tests/test_chatboost.py @@ -24,6 +24,7 @@ from telegram import ( Chat, ChatBoost, + ChatBoostAdded, ChatBoostRemoved, ChatBoostSource, ChatBoostSourceGiftCode, @@ -542,3 +543,42 @@ class TestUserChatBoostsWithRequest(ChatBoostDefaults): async def test_get_user_chat_boosts(self, bot, channel_id, chat_id): chat_boosts = await bot.get_user_chat_boosts(channel_id, chat_id) assert isinstance(chat_boosts, UserChatBoosts) + + +class TestChatBoostAddedWithoutRequest: + boost_count = 100 + + def test_slot_behaviour(self): + action = ChatBoostAdded(8) + for attr in action.__slots__: + assert getattr(action, attr, "err") != "err", f"got extra slot '{attr}'" + assert len(mro_slots(action)) == len(set(mro_slots(action))), "duplicate slot" + + def test_de_json(self): + json_dict = {"boost_count": self.boost_count} + chat_boost_added = ChatBoostAdded.de_json(json_dict, None) + assert chat_boost_added.api_kwargs == {} + + assert chat_boost_added.boost_count == self.boost_count + + def test_to_dict(self): + chat_boost_added = ChatBoostAdded(self.boost_count) + chat_boost_added_dict = chat_boost_added.to_dict() + + assert isinstance(chat_boost_added_dict, dict) + assert chat_boost_added_dict["boost_count"] == self.boost_count + + def test_equality(self): + a = ChatBoostAdded(100) + b = ChatBoostAdded(100) + c = ChatBoostAdded(50) + d = Chat(1, "") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != d + assert hash(a) != hash(d) diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py index 643f0e3b018..90ea90294b7 100644 --- a/tests/test_chatmember.py +++ b/tests/test_chatmember.py @@ -150,8 +150,13 @@ def make_json_dict(instance: ChatMember, include_optional_args: bool = False) -> val = val.to_dict() json_dict[param.name] = val - # If we want to test all args (for de_json)- - elif param.default is not inspect.Parameter.empty and include_optional_args: + # If we want to test all args (for de_json) + # or if the param is optional but for backwards compatability + elif ( + param.default is not inspect.Parameter.empty + and include_optional_args + or param.name in ["can_delete_stories", "can_post_stories", "can_edit_stories"] + ): json_dict[param.name] = val return json_dict @@ -297,3 +302,19 @@ def test_equality(self, chat_member_type): assert c != e assert hash(c) != hash(e) + + def test_deprecation_typeerror(self, chat_member_type): + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator( + *(False,) * 12, + ) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_edit_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_delete_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_edit_stories=True, can_post_stories=True) + with pytest.raises(TypeError, match="must be set in order"): + ChatMemberAdministrator(*(False,) * 12, can_delete_stories=True, can_post_stories=True) diff --git a/tests/test_chatmemberupdated.py b/tests/test_chatmemberupdated.py index 4e73526d0e0..8f9c405c06d 100644 --- a/tests/test_chatmemberupdated.py +++ b/tests/test_chatmemberupdated.py @@ -64,6 +64,9 @@ def new_chat_member(user): True, True, True, + can_post_stories=True, + can_edit_stories=True, + can_delete_stories=True, ) @@ -264,10 +267,19 @@ def test_difference_required(self, user, chat): @pytest.mark.parametrize( "optional_attribute", # This gives the names of all optional arguments of ChatMember + # skipping stories names because they aren't optional even though we pretend they are [ name for name, param in inspect.signature(ChatMemberAdministrator).parameters.items() - if name not in ["self", "api_kwargs"] and param.default != inspect.Parameter.empty + if name + not in [ + "self", + "api_kwargs", + "can_delete_stories", + "can_post_stories", + "can_edit_stories", + ] + and param.default != inspect.Parameter.empty ], ) def test_difference_optionals(self, optional_attribute, user, chat): @@ -276,8 +288,22 @@ def test_difference_optionals(self, optional_attribute, user, chat): old_value = "old_value" new_value = "new_value" trues = tuple(True for _ in range(9)) - old_chat_member = ChatMemberAdministrator(user, *trues, **{optional_attribute: old_value}) - new_chat_member = ChatMemberAdministrator(user, *trues, **{optional_attribute: new_value}) + old_chat_member = ChatMemberAdministrator( + user, + *trues, + **{optional_attribute: old_value}, + can_delete_stories=True, + can_edit_stories=True, + can_post_stories=True, + ) + new_chat_member = ChatMemberAdministrator( + user, + *trues, + **{optional_attribute: new_value}, + can_delete_stories=True, + can_edit_stories=True, + can_post_stories=True, + ) chat_member_updated = ChatMemberUpdated( chat, user, datetime.datetime.utcnow(), old_chat_member, new_chat_member ) diff --git a/tests/test_keyboardbuttonrequest.py b/tests/test_keyboardbuttonrequest.py index c8f620ff5d8..8678fd08d8e 100644 --- a/tests/test_keyboardbuttonrequest.py +++ b/tests/test_keyboardbuttonrequest.py @@ -106,10 +106,30 @@ class TestKeyboardButtonRequestChatBase: chat_has_username = True chat_is_created = False user_administrator_rights = ChatAdministratorRights( - True, False, True, False, True, False, True, False + True, + False, + True, + False, + True, + False, + True, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, ) bot_administrator_rights = ChatAdministratorRights( - True, False, True, False, True, False, True, False + True, + False, + True, + False, + True, + False, + True, + False, + can_post_stories=False, + can_edit_stories=False, + can_delete_stories=False, ) bot_is_member = True diff --git a/tests/test_message.py b/tests/test_message.py index f79505035b2..b98f36b4577 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -26,6 +26,7 @@ Audio, Bot, Chat, + ChatBoostAdded, ChatShared, Contact, Dice, @@ -129,7 +130,7 @@ def message(bot): }, {"photo": [PhotoSize("photo_id", "unique_id", 50, 50)], "caption": "photo_file"}, {"sticker": Sticker("sticker_id", "unique_id", 50, 50, True, False, Sticker.REGULAR)}, - {"story": Story()}, + {"story": Story(Chat(1, Chat.PRIVATE), 0)}, {"video": Video("video_id", "unique_id", 12, 12, 12), "caption": "video_file"}, {"voice": Voice("voice_id", "unique_id", 5)}, {"video_note": VideoNote("video_note_id", "unique_id", 20, 12)}, @@ -259,6 +260,9 @@ def message(bot): }, {"quote": TextQuote("a text quote", 1)}, {"forward_origin": MessageOriginChat(datetime.utcnow(), Chat(1, Chat.PRIVATE))}, + {"reply_to_story": Story(Chat(1, Chat.PRIVATE), 0)}, + {"boost_added": ChatBoostAdded(100)}, + {"sender_boost_count": 1}, ], ids=[ "reply", @@ -321,6 +325,9 @@ def message(bot): "external_reply", "quote", "forward_origin", + "reply_to_story", + "boost_added", + "sender_boost_count", ], ) def message_params(bot, request): diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index 7807a02784a..6f83e9ca74e 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -132,6 +132,9 @@ def ptb_extra_params(object_name: str) -> set[str]: # Mostly due to the value being fixed anyway PTB_IGNORED_PARAMS = { r"InlineQueryResult\w+": {"type"}, + # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, + r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, r"ChatMember\w+": {"status"}, r"PassportElementError\w+": {"source"}, "ForceReply": {"force_reply"}, @@ -166,7 +169,11 @@ def ignored_param_requirements(object_name: str) -> set[str]: # Arguments that are optional arguments for now for backwards compatibility -BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = {} +BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { + # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, + r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, +} def backwards_compat_kwargs(object_name: str) -> set[str]: diff --git a/tests/test_story.py b/tests/test_story.py index 99524ec7937..b521bebc5c5 100644 --- a/tests/test_story.py +++ b/tests/test_story.py @@ -18,28 +18,55 @@ import pytest -from telegram import Story +from telegram import Chat, Story from tests.auxil.slots import mro_slots @pytest.fixture(scope="module") def story(): - return Story() + return Story(TestStoryBase.chat, TestStoryBase.id) -class TestStoryWithoutRequest: - def test_slot_behaviour(self): - story = Story() +class TestStoryBase: + chat = Chat(1, "") + id = 0 + + +class TestStoryWithoutRequest(TestStoryBase): + def test_slot_behaviour(self, story): for attr in story.__slots__: assert getattr(story, attr, "err") != "err", f"got extra slot '{attr}'" assert len(mro_slots(story)) == len(set(mro_slots(story))), "duplicate slot" - def test_de_json(self): - story = Story.de_json({}, None) + def test_de_json(self, bot): + json_dict = {"chat": self.chat.to_dict(), "id": self.id} + story = Story.de_json(json_dict, bot) assert story.api_kwargs == {} + assert story.chat == self.chat + assert story.id == self.id assert isinstance(story, Story) + assert Story.de_json(None, bot) is None - def test_to_dict(self): - story = Story() + def test_to_dict(self, story): story_dict = story.to_dict() - assert story_dict == {} + assert story_dict["chat"] == self.chat.to_dict() + assert story_dict["id"] == self.id + + def test_equality(self): + a = Story(Chat(1, ""), 0) + b = Story(Chat(1, ""), 0) + c = Story(Chat(1, ""), 1) + d = Story(Chat(2, ""), 0) + e = Chat(1, "") + + assert a == b + assert hash(a) == hash(b) + + assert a != c + assert hash(a) != hash(c) + + assert a != d + assert hash(a) != hash(d) + + assert a != e + assert hash(a) != hash(e) From 5d11d7fd427cd39570b8c6b022eb0e3dad0152a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Mar 2024 11:34:03 +0100 Subject: [PATCH 09/17] Update `cachetools` requirement from ~=5.3.2 to ~=5.3.3 (#4141) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> --- .pre-commit-config.yaml | 8 ++++---- README.rst | 2 +- requirements-opts.txt | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e7f3bfa914..7ee1a16d6f3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - - cachetools~=5.3.2 + - cachetools~=5.3.3 - aiolimiter~=1.1.0 - repo: https://github.com/psf/black-pre-commit-mirror rev: 24.1.1 @@ -36,7 +36,7 @@ repos: - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - - cachetools~=5.3.2 + - cachetools~=5.3.3 - aiolimiter~=1.1.0 - . # this basically does `pip install -e .` - repo: https://github.com/pre-commit/mirrors-mypy @@ -52,7 +52,7 @@ repos: - httpx~=0.27.0 - tornado~=6.4 - APScheduler~=3.10.4 - - cachetools~=5.3.2 + - cachetools~=5.3.3 - aiolimiter~=1.1.0 - . # this basically does `pip install -e .` - id: mypy @@ -64,7 +64,7 @@ repos: additional_dependencies: - tornado~=6.4 - APScheduler~=3.10.4 - - cachetools~=5.3.2 + - cachetools~=5.3.3 - . # this basically does `pip install -e .` - repo: https://github.com/asottile/pyupgrade rev: v3.15.0 diff --git a/README.rst b/README.rst index 07dca0d2cf7..ed85b062695 100644 --- a/README.rst +++ b/README.rst @@ -153,7 +153,7 @@ PTB can be installed with optional dependencies: * ``pip install "python-telegram-bot[http2]"`` installs `httpx[http2] `_. Use this, if you want to use HTTP/2. * ``pip install "python-telegram-bot[rate-limiter]"`` installs `aiolimiter~=1.1.0 `_. Use this, if you want to use ``telegram.ext.AIORateLimiter``. * ``pip install "python-telegram-bot[webhooks]"`` installs the `tornado~=6.4 `_ library. Use this, if you want to use ``telegram.ext.Updater.start_webhook``/``telegram.ext.Application.run_webhook``. -* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools~=5.3.2 `_ library. Use this, if you want to use `arbitrary callback_data `_. +* ``pip install "python-telegram-bot[callback-data]"`` installs the `cachetools~=5.3.3 `_ library. Use this, if you want to use `arbitrary callback_data `_. * ``pip install "python-telegram-bot[job-queue]"`` installs the `APScheduler~=3.10.4 `_ library and enforces `pytz>=2018.6 `_, where ``pytz`` is a dependency of ``APScheduler``. Use this, if you want to use the ``telegram.ext.JobQueue``. To install multiple optional dependencies, separate them by commas, e.g. ``pip install "python-telegram-bot[socks,webhooks]"``. diff --git a/requirements-opts.txt b/requirements-opts.txt index 35e13191afe..05ac0d8c718 100644 --- a/requirements-opts.txt +++ b/requirements-opts.txt @@ -20,7 +20,7 @@ tornado~=6.4 # webhooks!ext # Cachetools and APS don't have a strict stability policy. # Let's be cautious for now. -cachetools~=5.3.2 # callback-data!ext +cachetools~=5.3.3 # callback-data!ext APScheduler~=3.10.4 # job-queue!ext # pytz is required by APS and just needs the lower bound due to #2120 From bd9b0bd1264cf181e295f9402d5cc4110cf2ed1a Mon Sep 17 00:00:00 2001 From: Harshil <37377066+harshil21@users.noreply.github.com> Date: Sun, 3 Mar 2024 13:22:26 -0500 Subject: [PATCH 10/17] Handle Properties in `TelegramObject.__setstate__` (#4134) Co-authored-by: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> --- telegram/_telegramobject.py | 23 +++++++++++-- tests/test_telegramobject.py | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/telegram/_telegramobject.py b/telegram/_telegramobject.py index 772863efd61..2f61dace88e 100644 --- a/telegram/_telegramobject.py +++ b/telegram/_telegramobject.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """Base class for Telegram Objects.""" +import contextlib import datetime import inspect import json @@ -312,7 +313,20 @@ def __setstate__(self, state: Dict[str, object]) -> None: try: setattr(self, key, val) except AttributeError: - # catch cases when old attributes are removed from new versions + # So an attribute was deprecated and removed from the class. Let's handle this: + # 1) Is the attribute now a property with no setter? Let's check that: + if isinstance(getattr(self.__class__, key, None), property): + # It is, so let's try to set the "private attribute" instead + try: + setattr(self, f"_{key}", val) + # If this fails as well, guess we've completely removed it. Let's add it to + # api_kwargs as fallback + except AttributeError: + api_kwargs[key] = val + + # 2) The attribute is a private attribute, i.e. it went through case 1) in the past + elif key.startswith("_"): + continue # skip adding this to api_kwargs, the attribute is lost forever. api_kwargs[key] = val # add it to api_kwargs as fallback # For api_kwargs we first apply any kwargs that are already attributes of the object @@ -490,7 +504,12 @@ def _apply_api_kwargs(self, api_kwargs: JSONDict) -> None: """ # we convert to list to ensure that the list doesn't change length while we loop for key in list(api_kwargs.keys()): - if getattr(self, key, True) is None: + # property attributes are not settable, so we need to set the private attribute + if isinstance(getattr(self.__class__, key, None), property): + # if setattr fails, we'll just leave the value in api_kwargs: + with contextlib.suppress(AttributeError): + setattr(self, f"_{key}", api_kwargs.pop(key)) + elif getattr(self, key, True) is None: setattr(self, key, api_kwargs.pop(key)) def _get_attrs_names(self, include_private: bool) -> Iterator[str]: diff --git a/tests/test_telegramobject.py b/tests/test_telegramobject.py index a22912d9d24..c97db1adaea 100644 --- a/tests/test_telegramobject.py +++ b/tests/test_telegramobject.py @@ -358,6 +358,68 @@ async def test_pickle_backwards_compatibility(self): chat.id = 7 assert chat.id == 7 + def test_pickle_handle_properties(self): + # Very hard to properly test, can't use a pickle file since newer versions of the library + # will stop having the property. + # The code below uses exec statements to simulate library changes. There is no other way + # to test this. + # Original class: + v1 = """ +class PicklePropertyTest(TelegramObject): + __slots__ = ("forward_from", "to_be_removed", "forward_date") + def __init__(self, forward_from=None, forward_date=None, api_kwargs=None): + super().__init__(api_kwargs=api_kwargs) + self.forward_from = forward_from + self.forward_date = forward_date + self.to_be_removed = "to_be_removed" +""" + exec(v1, globals(), None) + old = PicklePropertyTest("old_val", "date", api_kwargs={"new_attr": 1}) # noqa: F821 + pickled_v1 = pickle.dumps(old) + + # After some API changes: + v2 = """ +class PicklePropertyTest(TelegramObject): + __slots__ = ("_forward_from", "_date", "_new_attr") + def __init__(self, forward_from=None, f_date=None, new_attr=None, api_kwargs=None): + super().__init__(api_kwargs=api_kwargs) + self._forward_from = forward_from + self.f_date = f_date + self._new_attr = new_attr + @property + def forward_from(self): + return self._forward_from + @property + def forward_date(self): + return self.f_date + @property + def new_attr(self): + return self._new_attr + """ + exec(v2, globals(), None) + v2_unpickle = pickle.loads(pickled_v1) + assert v2_unpickle.forward_from == "old_val" == v2_unpickle._forward_from + with pytest.raises(AttributeError): + # New attribute should not be available either as is always the case for pickle + v2_unpickle.forward_date + assert v2_unpickle.new_attr == 1 == v2_unpickle._new_attr + assert not hasattr(v2_unpickle, "to_be_removed") + assert v2_unpickle.api_kwargs == {"to_be_removed": "to_be_removed"} + pickled_v2 = pickle.dumps(v2_unpickle) + + # After PTB removes the property and the attribute: + v3 = """ +class PicklePropertyTest(TelegramObject): + __slots__ = () + def __init__(self, api_kwargs=None): + super().__init__(api_kwargs=api_kwargs) +""" + exec(v3, globals(), None) + v3_unpickle = pickle.loads(pickled_v2) + assert v3_unpickle.api_kwargs == {"to_be_removed": "to_be_removed"} + assert not hasattr(v3_unpickle, "_forward_from") + assert not hasattr(v3_unpickle, "_new_attr") + def test_deepcopy_telegram_obj(self, bot): chat = Chat(2, Chat.PRIVATE) user = User(3, "first_name", False) From 20e0f87f6b60cb5f4859dab5149e379325f15850 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:22:42 +0100 Subject: [PATCH 11/17] Make `Updater.stop` Independent of `CancelledError` (#4126) --- telegram/ext/_updater.py | 84 +++++++++++++++++++++++------------ tests/ext/test_application.py | 11 ++++- tests/ext/test_updater.py | 19 ++++---- 3 files changed, 76 insertions(+), 38 deletions(-) diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 70fb650a27f..000176288ae 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -104,6 +104,7 @@ class Updater(AsyncContextManager["Updater"]): "__lock", "__polling_cleanup_cb", "__polling_task", + "__polling_task_stop_event", "_httpd", "_initialized", "_last_update_id", @@ -126,6 +127,7 @@ def __init__( self._httpd: Optional[WebhookServer] = None self.__lock = asyncio.Lock() self.__polling_task: Optional[asyncio.Task] = None + self.__polling_task_stop_event: asyncio.Event = asyncio.Event() self.__polling_cleanup_cb: Optional[Callable[[], Coroutine[Any, Any, None]]] = None async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 @@ -417,6 +419,7 @@ def default_error_callback(exc: TelegramError) -> None: on_err_cb=error_callback or default_error_callback, description="getting Updates", interval=poll_interval, + stop_event=self.__polling_task_stop_event, ), name="Updater:start_polling:polling_task", ) @@ -693,6 +696,7 @@ async def _network_loop_retry( on_err_cb: Callable[[TelegramError], None], description: str, interval: float, + stop_event: Optional[asyncio.Event], ) -> None: """Perform a loop calling `action_cb`, retrying after network errors. @@ -706,39 +710,58 @@ async def _network_loop_retry( description (:obj:`str`): Description text to use for logs and exception raised. interval (:obj:`float` | :obj:`int`): Interval to sleep between each call to `action_cb`. + stop_event (:class:`asyncio.Event` | :obj:`None`): Event to wait on for stopping the + loop. Setting the event will make the loop exit even if `action_cb` is currently + running. """ + + async def do_action() -> bool: + if not stop_event: + return await action_cb() + + action_cb_task = asyncio.create_task(action_cb()) + stop_task = asyncio.create_task(stop_event.wait()) + done, pending = await asyncio.wait( + (action_cb_task, stop_task), return_when=asyncio.FIRST_COMPLETED + ) + with contextlib.suppress(asyncio.CancelledError): + for task in pending: + task.cancel() + + if stop_task in done: + _LOGGER.debug("Network loop retry %s was cancelled", description) + return False + + return action_cb_task.result() + _LOGGER.debug("Start network loop retry %s", description) cur_interval = interval - try: - while self.running: - try: - if not await action_cb(): - break - except RetryAfter as exc: - _LOGGER.info("%s", exc) - cur_interval = 0.5 + exc.retry_after - except TimedOut as toe: - _LOGGER.debug("Timed out %s: %s", description, toe) - # If failure is due to timeout, we should retry asap. - cur_interval = 0 - except InvalidToken as pex: - _LOGGER.error("Invalid token; aborting") - raise pex - except TelegramError as telegram_exc: - _LOGGER.error("Error while %s: %s", description, telegram_exc) - on_err_cb(telegram_exc) - - # increase waiting times on subsequent errors up to 30secs - cur_interval = 1 if cur_interval == 0 else min(30, 1.5 * cur_interval) - else: - cur_interval = interval - - if cur_interval: - await asyncio.sleep(cur_interval) + while self.running: + try: + if not await do_action(): + break + except RetryAfter as exc: + _LOGGER.info("%s", exc) + cur_interval = 0.5 + exc.retry_after + except TimedOut as toe: + _LOGGER.debug("Timed out %s: %s", description, toe) + # If failure is due to timeout, we should retry asap. + cur_interval = 0 + except InvalidToken as pex: + _LOGGER.error("Invalid token; aborting") + raise pex + except TelegramError as telegram_exc: + _LOGGER.error("Error while %s: %s", description, telegram_exc) + on_err_cb(telegram_exc) + + # increase waiting times on subsequent errors up to 30secs + cur_interval = 1 if cur_interval == 0 else min(30, 1.5 * cur_interval) + else: + cur_interval = interval - except asyncio.CancelledError: - _LOGGER.debug("Network loop retry %s was cancelled", description) + if cur_interval: + await asyncio.sleep(cur_interval) async def _bootstrap( self, @@ -804,6 +827,7 @@ def bootstrap_on_err_cb(exc: Exception) -> None: bootstrap_on_err_cb, "bootstrap del webhook", bootstrap_interval, + stop_event=None, ) # Reset the retries counter for the next _network_loop_retry call @@ -817,6 +841,7 @@ def bootstrap_on_err_cb(exc: Exception) -> None: bootstrap_on_err_cb, "bootstrap set webhook", bootstrap_interval, + stop_event=None, ) async def stop(self) -> None: @@ -852,7 +877,7 @@ async def _stop_polling(self) -> None: """Stops the polling task by awaiting it.""" if self.__polling_task: _LOGGER.debug("Waiting background polling task to finish up.") - self.__polling_task.cancel() + self.__polling_task_stop_event.set() with contextlib.suppress(asyncio.CancelledError): await self.__polling_task @@ -860,6 +885,7 @@ async def _stop_polling(self) -> None: # after start_polling(), but lets better be safe than sorry ... self.__polling_task = None + self.__polling_task_stop_event.clear() if self.__polling_cleanup_cb: await self.__polling_cleanup_cb() diff --git a/tests/ext/test_application.py b/tests/ext/test_application.py index 3f80bc40bb2..04df441206f 100644 --- a/tests/ext/test_application.py +++ b/tests/ext/test_application.py @@ -1432,6 +1432,7 @@ async def callback(update, context): ) def test_run_polling_basic(self, app, monkeypatch, caplog): exception_event = threading.Event() + exception_testing_done = threading.Event() update_event = threading.Event() exception = TelegramError("This is a test error") assertions = {} @@ -1439,8 +1440,14 @@ def test_run_polling_basic(self, app, monkeypatch, caplog): async def get_updates(*args, **kwargs): if exception_event.is_set(): raise exception + # This makes sure that other coroutines have a chance of running as well - await asyncio.sleep(0) + if exception_testing_done.is_set() and app.updater.running: + # the longer sleep makes sure that we can exit also while get_updates is running + await asyncio.sleep(20) + else: + await asyncio.sleep(0.01) + update_event.set() return [self.message_update] @@ -1466,10 +1473,12 @@ def thread_target(): exception_event.set() time.sleep(0.05) assertions["exception_handling"] = self.received == exception.message + exception_testing_done.set() # So that the get_updates call on shutdown doesn't fail exception_event.clear() + time.sleep(1) os.kill(os.getpid(), signal.SIGINT) time.sleep(0.1) diff --git a/tests/ext/test_updater.py b/tests/ext/test_updater.py index 9e0b7754773..0c81144aedd 100644 --- a/tests/ext/test_updater.py +++ b/tests/ext/test_updater.py @@ -234,7 +234,7 @@ async def get_updates(*args, **kwargs): updates.task_done() return [next_update] - await asyncio.sleep(0) + await asyncio.sleep(0.1) return [] orig_del_webhook = updater.bot.delete_webhook @@ -520,10 +520,13 @@ async def test_start_polling_exceptions_and_error_callback( ): raise_exception = True get_updates_event = asyncio.Event() + second_get_updates_event = asyncio.Event() async def get_updates(*args, **kwargs): # So that the main task has a chance to be called await asyncio.sleep(0) + if get_updates_event.is_set(): + second_get_updates_event.set() if not raise_exception: return [] @@ -548,6 +551,9 @@ async def get_updates(*args, **kwargs): # Also makes sure that the error handler was called await get_updates_event.wait() + # wait for get_updates to be called a second time - only now we can expect that + # all error handling for the previous call has finished + await second_get_updates_event.wait() if callback_should_be_called: # Make sure that the error handler was called @@ -588,17 +594,14 @@ async def get_updates(*args, **kwargs): async def test_start_polling_unexpected_shutdown(self, updater, monkeypatch, caplog): update_queue = asyncio.Queue() await update_queue.put(Update(update_id=1)) - await update_queue.put(Update(update_id=2)) first_update_event = asyncio.Event() second_update_event = asyncio.Event() async def get_updates(*args, **kwargs): self.message_count = kwargs.get("offset") update = await update_queue.get() - if update.update_id == 1: - first_update_event.set() - else: - await second_update_event.wait() + first_update_event.set() + await second_update_event.wait() return [update] monkeypatch.setattr(updater.bot, "get_updates", get_updates) @@ -611,8 +614,8 @@ async def get_updates(*args, **kwargs): # Unfortunately we need to use the private attribute here to produce the problem updater._running = False second_update_event.set() + await asyncio.sleep(1) - await asyncio.sleep(0.1) assert caplog.records assert any( "Updater stopped unexpectedly." in record.getMessage() @@ -621,7 +624,7 @@ async def get_updates(*args, **kwargs): ) # Make sure that the update_id offset wasn't increased - assert self.message_count == 2 + assert self.message_count < 1 async def test_start_polling_not_running_after_failure(self, updater, monkeypatch): # Unfortunately we have to use some internal logic to trigger an exception From d30ba3d1efa8c3808a3839a942103df9304763f1 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:27:21 +0100 Subject: [PATCH 12/17] Run Unit Tests in PRs on Requirements Changes (#4144) --- .github/workflows/type_completeness.yml | 2 ++ .github/workflows/unit_tests.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/type_completeness.yml b/.github/workflows/type_completeness.yml index ac3b9934e9b..b2ebd45e303 100644 --- a/.github/workflows/type_completeness.yml +++ b/.github/workflows/type_completeness.yml @@ -3,6 +3,8 @@ on: pull_request: paths: - telegram/** + - requirements.txt + - requirements-opts.txt push: branches: - master diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 682ceead685..a6160efff84 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -4,6 +4,8 @@ on: paths: - telegram/** - tests/** + - requirements.txt + - requirements-opts.txt push: branches: - master From 1b98e440fa425bad952c5c23653c95cb82dfebaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:28:06 +0100 Subject: [PATCH 13/17] Bump `test-summary/action` from 2.2 to 2.3 (#4142) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] Co-authored-by: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> --- .github/workflows/test_official.yml | 2 +- .github/workflows/unit_tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_official.yml b/.github/workflows/test_official.yml index d4853781142..0510d334f3f 100644 --- a/.github/workflows/test_official.yml +++ b/.github/workflows/test_official.yml @@ -42,7 +42,7 @@ jobs: - name: Test Summary id: test_summary - uses: test-summary/action@v2.2 + uses: test-summary/action@v2.3 if: always() # always run, even if tests fail with: paths: .test_report_official.xml diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index a6160efff84..7528af1f9d7 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -82,7 +82,7 @@ jobs: - name: Test Summary id: test_summary - uses: test-summary/action@v2.2 + uses: test-summary/action@v2.3 if: always() # always run, even if tests fail with: paths: | From 437261f7162755683f9dde3d3b881268f87e3e3f Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:16:14 +0100 Subject: [PATCH 14/17] Improve HTML Download of Documentation (#4146) --- .readthedocs.yml | 76 +++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 51706328d8e..a23c582637d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,46 +7,56 @@ version: 2 # Build documentation in the docs/ directory with Sphinx sphinx: - configuration: docs/source/conf.py + configuration: docs/source/conf.py # Optionally build your docs in additional formats such as PDF formats: - - pdf - - htmlzip + - pdf # Optionally set the version of Python and requirements required to build your docs python: - install: - - method: pip - path: . - - requirements: docs/requirements-docs.txt + install: + - method: pip + path: . + - requirements: docs/requirements-docs.txt build: - os: ubuntu-22.04 - tools: - python: "3" # latest stable cpython version + os: ubuntu-22.04 + tools: + python: "3" # latest stable cpython version + jobs: + post_build: + # Based on https://github.com/readthedocs/readthedocs.org/issues/3242#issuecomment-1410321534 + # This provides a HTML zip file for download, with the same structure as the hosted website + - mkdir --parents $READTHEDOCS_OUTPUT/htmlzip + - cp --recursive $READTHEDOCS_OUTPUT/html $READTHEDOCS_OUTPUT/$READTHEDOCS_PROJECT + # Hide the "other versions" dropdown. This is a workaround for those versions being shown, + # but not being accessible, as they are not built. Also, they hide the actual sidebar menu + # that is relevant only on ReadTheDocs. + - echo "#furo-readthedocs-versions{display:none}" >> $READTHEDOCS_OUTPUT/$READTHEDOCS_PROJECT/_static/styles/furo-extensions.css + - cd $READTHEDOCS_OUTPUT ; zip --recurse-path --symlinks htmlzip/$READTHEDOCS_PROJECT.zip $READTHEDOCS_PROJECT search: - ranking: # bump up rank of commonly searched pages: (default: 0, values range from -10 to 10) - telegram.bot.html: 7 - telegram.message.html: 3 - telegram.update.html: 3 - telegram.user.html: 2 - telegram.chat.html: 2 - telegram.ext.application.html: 3 - telegram.ext.filters.html: 3 - telegram.ext.callbackcontext.html: 2 - telegram.ext.inlinekeyboardbutton.html: 1 - - telegram.passport*.html: -7 - - ignore: - - changelog.html - - coc.html - - bot_methods.html# - - bot_methods.html - # Defaults - - search.html - - search/index.html - - 404.html - - 404/index.html' + ranking: # bump up rank of commonly searched pages: (default: 0, values range from -10 to 10) + telegram.bot.html: 7 + telegram.message.html: 3 + telegram.update.html: 3 + telegram.user.html: 2 + telegram.chat.html: 2 + telegram.ext.application.html: 3 + telegram.ext.filters.html: 3 + telegram.ext.callbackcontext.html: 2 + telegram.ext.inlinekeyboardbutton.html: 1 + + telegram.passport*.html: -7 + + ignore: + - changelog.html + - coc.html + - bot_methods.html# + - bot_methods.html + # Defaults + - search.html + - search/index.html + - 404.html + - 404/index.html' From 2c227d597766de5010f671e50f9954ba28c4315e Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:20:38 +0100 Subject: [PATCH 15/17] Relax Upper Bound for `httpx` Dependency (#4148) --- .pre-commit-config.yaml | 6 +++--- README.rst | 2 +- README_RAW.rst | 2 +- requirements.txt | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7ee1a16d6f3..b5acb00b026 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: - id: ruff name: ruff additional_dependencies: - - httpx~=0.27.0 + - httpx~=0.27 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.3 @@ -33,7 +33,7 @@ repos: - id: pylint files: ^(?!(tests|docs)).*\.py$ additional_dependencies: - - httpx~=0.27.0 + - httpx~=0.27 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.3 @@ -49,7 +49,7 @@ repos: - types-pytz - types-cryptography - types-cachetools - - httpx~=0.27.0 + - httpx~=0.27 - tornado~=6.4 - APScheduler~=3.10.4 - cachetools~=5.3.3 diff --git a/README.rst b/README.rst index ed85b062695..c71b3eb4ea4 100644 --- a/README.rst +++ b/README.rst @@ -135,7 +135,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n Instead, they are listed as optional dependencies. This allows to avoid unnecessary dependency conflicts for users who don't need the optional features. -The only required dependency is `httpx ~= 0.27.0 `_ for +The only required dependency is `httpx ~= 0.27 `_ for ``telegram.request.HTTPXRequest``, the default networking backend. ``python-telegram-bot`` is most useful when used along with additional libraries. diff --git a/README_RAW.rst b/README_RAW.rst index 75dec821cba..0f5810f59ec 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -136,7 +136,7 @@ As these features are *optional*, the corresponding 3rd party dependencies are n Instead, they are listed as optional dependencies. This allows to avoid unnecessary dependency conflicts for users who don't need the optional features. -The only required dependency is `httpx ~= 0.27.0 `_ for +The only required dependency is `httpx ~= 0.27 `_ for ``telegram.request.HTTPXRequest``, the default networking backend. ``python-telegram-bot`` is most useful when used along with additional libraries. diff --git a/requirements.txt b/requirements.txt index 7c24fc990f1..90203e49733 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,5 +5,6 @@ # When dependencies release new versions and tests succeed, we should try to expand the allowed # versions and only increase the lower bound if necessary -# httpx has no stable release yet, so let's be cautious for now -httpx ~= 0.27.0 +# httpx has no stable release yet, but we've had no stability problems since v20.0a0 either +# Since there have been requests to relax the bound a bit, we allow versions < 1.0.0 +httpx ~= 0.27 From ae2858783a95e0bcd2839162116b7df36c15efcf Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:45:50 +0100 Subject: [PATCH 16/17] Documentation Improvements (#4109, #4116) Co-authored-by: Aditya Co-authored-by: Harshil <37377066+harshil21@users.noreply.github.com> Co-authored-by: Maurice Banerjee Palmer <31225563+mbanerjeepalmer@users.noreply.github.com> --- README.rst | 4 -- README_RAW.rst | 4 -- docs/requirements-docs.txt | 2 +- docs/source/telegram.constants.rst | 4 +- examples/deeplinking.py | 12 +++- telegram/_bot.py | 53 ++++++++------- telegram/_chat.py | 2 +- telegram/_chatadministratorrights.py | 18 +++--- telegram/_chatmember.py | 18 +++--- .../_passport/encryptedpassportelement.py | 64 +++++++++---------- telegram/_user.py | 2 +- 11 files changed, 94 insertions(+), 89 deletions(-) diff --git a/README.rst b/README.rst index c71b3eb4ea4..8366a1ff6f0 100644 --- a/README.rst +++ b/README.rst @@ -46,10 +46,6 @@ :target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard :alt: Code quality: Codacy -.. image:: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues - :target: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge - :alt: Code quality: DeepSource - .. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg :target: https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master :alt: pre-commit.ci status diff --git a/README_RAW.rst b/README_RAW.rst index 0f5810f59ec..fae3d516e38 100644 --- a/README_RAW.rst +++ b/README_RAW.rst @@ -46,10 +46,6 @@ :target: https://app.codacy.com/gh/python-telegram-bot/python-telegram-bot/dashboard :alt: Code quality: Codacy -.. image:: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues - :target: https://app.deepsource.com/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge - :alt: Code quality: DeepSource - .. image:: https://results.pre-commit.ci/badge/github/python-telegram-bot/python-telegram-bot/master.svg :target: https://results.pre-commit.ci/latest/github/python-telegram-bot/python-telegram-bot/master :alt: pre-commit.ci status diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 4b4db586ba7..3aa5506bdbf 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ sphinx==7.2.6 furo==2024.1.29 -git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1 +furo-sphinx-search @ git+https://github.com/harshil21/furo-sphinx-search@v0.2.0.1 sphinx-paramlinks==0.6.0 sphinxcontrib-mermaid==0.9.2 sphinx-copybutton==0.5.2 diff --git a/docs/source/telegram.constants.rst b/docs/source/telegram.constants.rst index 78d5af89944..4b5edf51094 100644 --- a/docs/source/telegram.constants.rst +++ b/docs/source/telegram.constants.rst @@ -4,4 +4,6 @@ telegram.constants Module .. automodule:: telegram.constants :members: :show-inheritance: - :inherited-members: Enum, EnumMeta + :no-undoc-members: + :inherited-members: Enum, EnumMeta, str, int + :exclude-members: __format__, __new__, __repr__, __str__ diff --git a/examples/deeplinking.py b/examples/deeplinking.py index bea7098026b..3ac7f9bd0e5 100644 --- a/examples/deeplinking.py +++ b/examples/deeplinking.py @@ -20,7 +20,13 @@ import logging -from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, helpers +from telegram import ( + InlineKeyboardButton, + InlineKeyboardMarkup, + LinkPreviewOptions, + Update, + helpers, +) from telegram.constants import ParseMode from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes, filters @@ -70,7 +76,9 @@ async def deep_linked_level_2(update: Update, context: ContextTypes.DEFAULT_TYPE bot = context.bot url = helpers.create_deep_linked_url(bot.username, USING_ENTITIES) text = f'You can also mask the deep-linked URLs as links: ▶️ CLICK HERE.' - await update.message.reply_text(text, parse_mode=ParseMode.HTML, disable_web_page_preview=True) + await update.message.reply_text( + text, parse_mode=ParseMode.HTML, link_preview_options=LinkPreviewOptions(is_disabled=True) + ) async def deep_linked_level_3(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: diff --git a/telegram/_bot.py b/telegram/_bot.py index dc6c66aab7c..be9c971af39 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -1110,10 +1110,11 @@ async def delete_messages( Args: chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| - message_ids (Sequence[:obj:`int`]): Identifiers of + message_ids (Sequence[:obj:`int`]): A list of :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` messages to delete. - See :meth:`delete_message` for limitations on which messages can be deleted. + :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages + to delete. See :meth:`delete_message` for limitations on which messages can be + deleted. Returns: :obj:`bool`: On success, :obj:`True` is returned. @@ -1225,11 +1226,11 @@ async def forward_messages( chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the original message was sent (or channel username in the format ``@channelusername``). - message_ids (Sequence[:obj:`int`]): Identifiers of + message_ids (Sequence[:obj:`int`]): A list of :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT`- - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` messages in the chat - :paramref:`from_chat_id` to forward. The identifiers must be specified in a - strictly increasing order. + :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages + in the chat :paramref:`from_chat_id` to forward. The identifiers must be specified + in a strictly increasing order. disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| message_thread_id (:obj:`int`, optional): |message_thread_id_arg| @@ -4127,10 +4128,11 @@ async def get_updates( "edited_channel_post", "callback_query"] to only receive updates of these types. See :class:`telegram.Update` for a complete list of available update types. Specify an empty sequence to receive all updates except - :attr:`telegram.Update.chat_member` (default). If not specified, the previous - setting will be used. Please note that this parameter doesn't affect updates - created before the call to the get_updates, so unwanted updates may be received for - a short period of time. + :attr:`telegram.Update.chat_member`, :attr:`telegram.Update.message_reaction` and + :attr:`telegram.Update.message_reaction_count` (default). If not specified, the + previous setting will be used. Please note that this parameter doesn't affect + updates created before the call to the get_updates, so unwanted updates may be + received for a short period of time. .. versionchanged:: 20.0 |sequenceargs| @@ -4268,10 +4270,13 @@ async def set_webhook( "edited_channel_post", "callback_query"] to only receive updates of these types. See :class:`telegram.Update` for a complete list of available update types. Specify an empty sequence to receive all updates except - :attr:`telegram.Update.chat_member` (default). If not specified, the previous - setting will be used. Please note that this parameter doesn't affect updates - created before the call to the set_webhook, so unwanted updates may be received for - a short period of time. + :attr:`telegram.Update.chat_member`, + :attr:`telegram.Update.message_reaction` + and :attr:`telegram.Update.message_reaction_count` (default). If not + specified, the previous setting will be used. Please note that this + parameter doesn't affect + updates created before the call to the set_webhook, so unwanted update + may be received for a short period of time. .. versionchanged:: 20.0 |sequenceargs| @@ -5265,9 +5270,9 @@ async def promote_chat_member( can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can change chat title, photo and other settings. can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - post messages in the channel, or access channel statistics; channels only. + post messages in the channel, or access channel statistics; for channels only. can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit messages of other users and can pin messages, channels only. + edit messages of other users and can pin messages, for channels only. can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can delete messages of other users. can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can @@ -5275,13 +5280,13 @@ async def promote_chat_member( can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can restrict, ban or unban chat members, or access supergroup statistics. can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - pin messages, supergroups only. + pin messages, for supergroups only. can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can add new administrators with a subset of their own privileges or demote administrators that they have promoted, directly or indirectly (promoted by administrators that were appointed by the user). can_manage_topics (:obj:`bool`, optional): Pass :obj:`True`, if the user is - allowed to create, rename, close, and reopen forum topics; supergroups only. + allowed to create, rename, close, and reopen forum topics; for supergroups only. .. versionadded:: 20.0 can_post_stories (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can @@ -7577,11 +7582,11 @@ async def copy_messages( chat_id (:obj:`int` | :obj:`str`): |chat_id_channel| from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the original message was sent (or channel username in the format ``@channelusername``). - message_ids (Sequence[:obj:`int`]): Identifiers of + message_ids (Sequence[:obj:`int`]): A list of :tg-const:`telegram.constants.BulkRequestLimit.MIN_LIMIT` - - :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` messages in the chat. - :paramref:`from_chat_id` to copy. The identifiers must be specified in a strictly - increasing order. + :tg-const:`telegram.constants.BulkRequestLimit.MAX_LIMIT` identifiers of messages + in the chat :paramref:`from_chat_id` to copy. The identifiers must be + specified in a strictly increasing order. disable_notification (:obj:`bool`, optional): |disable_notification| protect_content (:obj:`bool`, optional): |protect_content| message_thread_id (:obj:`int`, optional): |message_thread_id_arg| @@ -8731,7 +8736,7 @@ async def set_message_reaction( media group, the reaction is set to the first non-deleted message in the group instead. reaction (Sequence[:class:`telegram.ReactionType` | :obj:`str`] | \ - :class:`telegram.ReactionType` | :obj:`str`, optional): New list of reaction + :class:`telegram.ReactionType` | :obj:`str`, optional): A list of reaction types to set on the message. Currently, as non-premium users, bots can set up to one reaction per message. A custom emoji reaction can be used if it is either already present on the message or explicitly allowed by chat administrators. diff --git a/telegram/_chat.py b/telegram/_chat.py index d308cc0f265..8115c60566e 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -2583,7 +2583,7 @@ async def copy_message( .. seealso:: :meth:`send_copy`, :meth:`send_copies`, :meth:`copy_messages`. Returns: - :class:`telegram.Message`: On success, instance representing the message posted. + :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. """ return await self.get_bot().copy_message( diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index 35e1adaac0d..f5bbb7e568a 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -60,15 +60,15 @@ class ChatAdministratorRights(TelegramObject): that they have promoted, directly or indirectly (promoted by administrators that were appointed by the user). can_change_info (:obj:`bool`): :obj:`True`, if the user is allowed to change the chat title - ,photo and other settings. + , photo and other settings. can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to the chat. can_post_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can post - messages in the channel, or access channel statistics; channels only. + messages in the channel, or access channel statistics; for channels only. can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can edit - messages of other users. + messages of other users and can pin messages; for channels only. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin - messages; groups and supergroups only. + messages; for groups and supergroups only. can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. @@ -88,7 +88,7 @@ class ChatAdministratorRights(TelegramObject): .. versionchanged:: NEXT.VERSION |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; supergroups only. + to create, rename, close, and reopen forum topics; for supergroups only. .. versionadded:: 20.0 @@ -112,11 +112,11 @@ class ChatAdministratorRights(TelegramObject): can_invite_users (:obj:`bool`): :obj:`True`, if the user is allowed to invite new users to the chat. can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can post - messages in the channel, or access channel statistics; channels only. + messages in the channel, or access channel statistics; for channels only. can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit - messages of other users. + messages of other users and can pin messages; for channels only. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin - messages; groups and supergroups only. + messages; for groups and supergroups only. can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. @@ -136,7 +136,7 @@ class ChatAdministratorRights(TelegramObject): .. versionchanged:: NEXT.VERSION |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; supergroups only. + to create, rename, close, and reopen forum topics; for supergroups only. .. versionadded:: 20.0 """ diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index 6d2d35ce3f4..c251e23c620 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -217,13 +217,13 @@ class ChatMemberAdministrator(ChatMember): can_invite_users (:obj:`bool`): :obj:`True`, if the user can invite new users to the chat. can_post_messages (:obj:`bool`, optional): :obj:`True`, if the - administrator can post messages in the channel, or access channel statistics; channels - only. + administrator can post messages in the channel, or access channel statistics; + for channels only. can_edit_messages (:obj:`bool`, optional): :obj:`True`, if the administrator can edit messages of other users and can pin - messages; channels only. + messages; for channels only. can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to pin messages; groups and supergroups only. + to pin messages; for groups and supergroups only. can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. @@ -243,7 +243,7 @@ class ChatMemberAdministrator(ChatMember): .. versionchanged:: NEXT.VERSION |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; supergroups only. + to create, rename, close, and reopen forum topics; for supergroups only. .. versionadded:: 20.0 custom_title (:obj:`str`, optional): Custom title for this user. @@ -277,12 +277,12 @@ class ChatMemberAdministrator(ChatMember): new users to the chat. can_post_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can post messages in the channel or access channel statistics; - channels only. + for channels only. can_edit_messages (:obj:`bool`): Optional. :obj:`True`, if the administrator can edit messages of other users and can pin - messages; channels only. + messages; for channels only. can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to pin messages; groups and supergroups only. + to pin messages; for groups and supergroups only. can_post_stories (:obj:`bool`): :obj:`True`, if the administrator can post stories to the chat. @@ -302,7 +302,7 @@ class ChatMemberAdministrator(ChatMember): .. versionchanged:: NEXT.VERSION |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed - to create, rename, close, and reopen forum topics; supergroups only + to create, rename, close, and reopen forum topics; for supergroups only .. versionadded:: 20.0 custom_title (:obj:`str`): Optional. Custom title for this user. diff --git a/telegram/_passport/encryptedpassportelement.py b/telegram/_passport/encryptedpassportelement.py index 46b7ac15fb2..14d8b63dcf5 100644 --- a/telegram/_passport/encryptedpassportelement.py +++ b/telegram/_passport/encryptedpassportelement.py @@ -53,35 +53,34 @@ class EncryptedPassportElement(TelegramObject): :class:`telegram.PassportElementErrorUnspecified`. data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \ :class:`telegram.ResidentialAddress` | :obj:`str`, optional): - Decrypted or encrypted data, available for "personal_details", "passport", + Decrypted or encrypted data; available only for "personal_details", "passport", "driver_license", "identity_card", "internal_passport" and "address" types. - phone_number (:obj:`str`, optional): User's verified phone number, available only for + phone_number (:obj:`str`, optional): User's verified phone number; available only for "phone_number" type. - email (:obj:`str`, optional): User's verified email address, available only for "email" + email (:obj:`str`, optional): User's verified email address; available only for "email" type. files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted - files - with documents provided by the user, available for "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration" types. + files with documents provided by the user; available only for "utility_bill", + "bank_statement", "rental_agreement", "passport_registration" and + "temporary_registration" types. .. versionchanged:: 20.0 |sequenceclassargs| front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - front side of the document, provided by the user. Available for "passport", + front side of the document, provided by the user; Available only for "passport", "driver_license", "identity_card" and "internal_passport". reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - reverse side of the document, provided by the user. Available for "driver_license" and - "identity_card". + reverse side of the document, provided by the user; Available only for + "driver_license" and "identity_card". selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available for "passport", - "driver_license", "identity_card" and "internal_passport". + selfie of the user holding a document, provided by the user; available if requested for + "passport", "driver_license", "identity_card" and "internal_passport". translation (Sequence[:class:`telegram.PassportFile`], optional): Array of - encrypted/decrypted - files with translated versions of documents provided by the user. Available if - requested for "passport", "driver_license", "identity_card", "internal_passport", - "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. + encrypted/decrypted files with translated versions of documents provided by the user; + available if requested requested for "passport", "driver_license", "identity_card", + "internal_passport", "utility_bill", "bank_statement", "rental_agreement", + "passport_registration" and "temporary_registration" types. .. versionchanged:: 20.0 |sequenceclassargs| @@ -95,16 +94,16 @@ class EncryptedPassportElement(TelegramObject): :class:`telegram.PassportElementErrorUnspecified`. data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \ :class:`telegram.ResidentialAddress` | :obj:`str`): - Optional. Decrypted or encrypted data, available for "personal_details", "passport", - "driver_license", "identity_card", "internal_passport" and "address" types. - phone_number (:obj:`str`): Optional. User's verified phone number, available only for + Optional. Decrypted or encrypted data; available only for "personal_details", + "passport", "driver_license", "identity_card", "internal_passport" and "address" types. + phone_number (:obj:`str`): Optional. User's verified phone number; available only for "phone_number" type. - email (:obj:`str`): Optional. User's verified email address, available only for "email" + email (:obj:`str`): Optional. User's verified email address; available only for "email" type. files (Tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted - files - with documents provided by the user, available for "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration" types. + files with documents provided by the user; available only for "utility_bill", + "bank_statement", "rental_agreement", "passport_registration" and + "temporary_registration" types. .. versionchanged:: 20.0 @@ -112,20 +111,19 @@ class EncryptedPassportElement(TelegramObject): * |alwaystuple| front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - front side of the document, provided by the user. Available for "passport", + front side of the document, provided by the user; available only for "passport", "driver_license", "identity_card" and "internal_passport". reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - reverse side of the document, provided by the user. Available for "driver_license" and - "identity_card". + reverse side of the document, provided by the user; available only for "driver_license" + and "identity_card". selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available for "passport", - "driver_license", "identity_card" and "internal_passport". + selfie of the user holding a document, provided by the user; available if requested for + "passport", "driver_license", "identity_card" and "internal_passport". translation (Tuple[:class:`telegram.PassportFile`]): Optional. Array of - encrypted/decrypted - files with translated versions of documents provided by the user. Available if - requested for "passport", "driver_license", "identity_card", "internal_passport", - "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. + encrypted/decrypted files with translated versions of documents provided by the user; + available if requested for "passport", "driver_license", "identity_card", + "internal_passport", "utility_bill", "bank_statement", "rental_agreement", + "passport_registration" and "temporary_registration" types. .. versionchanged:: 20.0 diff --git a/telegram/_user.py b/telegram/_user.py index 914d7024f5c..eb4227e18ce 100644 --- a/telegram/_user.py +++ b/telegram/_user.py @@ -1588,7 +1588,7 @@ async def copy_message( |user_chat_id_note| Returns: - :class:`telegram.Message`: On success, instance representing the message posted. + :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. """ return await self.get_bot().copy_message( From 22eb434a62eacc2273b15f1644aa18c1acb76b34 Mon Sep 17 00:00:00 2001 From: Hinrich Mahler <22366557+Bibo-Joshi@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:09:47 +0100 Subject: [PATCH 17/17] Bump version to v21.0 --- CHANGES.rst | 48 +++++++++++++ docs/source/conf.py | 4 +- telegram/_bot.py | 76 ++++++++++----------- telegram/_chat.py | 8 +-- telegram/_chatadministratorrights.py | 14 ++-- telegram/_chatboost.py | 2 +- telegram/_chatmember.py | 14 ++-- telegram/_inline/inputtextmessagecontent.py | 2 +- telegram/_keyboardbutton.py | 2 +- telegram/_message.py | 16 ++--- telegram/_story.py | 2 +- telegram/_version.py | 2 +- telegram/constants.py | 6 +- telegram/ext/_applicationbuilder.py | 2 +- telegram/ext/filters.py | 2 +- telegram/request/_httpxrequest.py | 2 +- tests/test_official/exceptions.py | 4 +- 17 files changed, 127 insertions(+), 79 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 39120d902ff..df5bc7a7455 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,54 @@ Changelog ========= +Version 21.0 +============ + +*Released 2024-03-06* + +This is the technical changelog for version 21.0. More elaborate release notes can be found in the news channel `@pythontelegrambotchannel `__. + +Major Changes +------------- + +- Remove Functionality Deprecated in API 7.0 (:pr:`4114` closes :issue:`4099`) +- API 7.1 (:pr:`4118`) + +New Features +------------ + +- Add Parameter ``media_write_timeout`` to ``HTTPXRequest`` and Method ``ApplicationBuilder.media_write_timeout`` (:pr:`4120` closes :issue:`3864`) +- Handle Properties in ``TelegramObject.__setstate__`` (:pr:`4134` closes :issue:`4111`) + +Bug Fixes +--------- + +- Add Missing Slot to ``Updater`` (:pr:`4130` closes :issue:`4127`) + +Documentation Improvements +-------------------------- + +- Improve HTML Download of Documentation (:pr:`4146` closes :issue:`4050`) +- Documentation Improvements (:pr:`4109`, :issue:`4116`) +- Update Copyright to 2024 (:pr:`4121` by `@aelkheir `__ closes :issue:`4041`) + +Internal Changes +---------------- + +- Apply ``pre-commit`` Checks More Widely (:pr:`4135`) +- Refactor and Overhaul ``test_official`` (:pr:`4087` closes :issue:`3874`) +- Run Unit Tests in PRs on Requirements Changes (:pr:`4144`) +- Make ``Updater.stop`` Independent of ``CancelledError`` (:pr:`4126`) + +Dependency Updates +------------------ + +- Relax Upper Bound for ``httpx`` Dependency (:pr:`4148`) +- Bump ``test-summary/action`` from 2.2 to 2.3 (:pr:`4142`) +- Update ``cachetools`` requirement from ~=5.3.2 to ~=5.3.3 (:pr:`4141`) +- Update ``httpx`` requirement from ~=0.26.0 to ~=0.27.0 (:pr:`4131`) + + Version 20.8 ============ diff --git a/docs/source/conf.py b/docs/source/conf.py index c890a4af460..055dc6e75ed 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,9 +20,9 @@ # built documents. # # The short X.Y version. -version = "20.8" # telegram.__version__[:3] +version = "21.0" # telegram.__version__[:3] # The full version, including alpha/beta/rc tags. -release = "20.8" # telegram.__version__ +release = "21.0" # telegram.__version__ # If your documentation needs a minimal Sphinx version, state it here. needs_sphinx = "6.1.3" diff --git a/telegram/_bot.py b/telegram/_bot.py index be9c971af39..df498eb7a3e 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -977,7 +977,7 @@ async def send_message( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -986,7 +986,7 @@ async def send_message( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this message. Convenience parameter for setting :paramref:`link_preview_options`. @@ -997,7 +997,7 @@ async def send_message( argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: @@ -1345,7 +1345,7 @@ async def send_photo( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -1354,7 +1354,7 @@ async def send_photo( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the photo, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -1490,7 +1490,7 @@ async def send_audio( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -1499,7 +1499,7 @@ async def send_audio( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the audio, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -1635,7 +1635,7 @@ async def send_document( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -1644,7 +1644,7 @@ async def send_document( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the document, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -1752,7 +1752,7 @@ async def send_sticker( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -1761,7 +1761,7 @@ async def send_sticker( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: @@ -1898,7 +1898,7 @@ async def send_video( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -1907,7 +1907,7 @@ async def send_video( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -2037,7 +2037,7 @@ async def send_video_note( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2046,7 +2046,7 @@ async def send_video_note( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the video note, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -2184,7 +2184,7 @@ async def send_animation( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2193,7 +2193,7 @@ async def send_animation( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the animation, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -2325,7 +2325,7 @@ async def send_voice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2334,7 +2334,7 @@ async def send_voice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| filename (:obj:`str`, optional): Custom file name for the voice, when uploading a new file. Convenience parameter, useful e.g. when sending files generated by the @@ -2442,7 +2442,7 @@ async def send_media_group( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2451,7 +2451,7 @@ async def send_media_group( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| caption (:obj:`str`, optional): Caption that will be added to the first element of :paramref:`media`, so that it will be used as caption for the @@ -2614,7 +2614,7 @@ async def send_location( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2623,7 +2623,7 @@ async def send_location( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| location (:class:`telegram.Location`, optional): The location to send. @@ -2893,7 +2893,7 @@ async def send_venue( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -2902,7 +2902,7 @@ async def send_venue( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| venue (:class:`telegram.Venue`, optional): The venue to send. @@ -3026,7 +3026,7 @@ async def send_contact( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -3035,7 +3035,7 @@ async def send_contact( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| contact (:class:`telegram.Contact`, optional): The contact to send. @@ -3137,7 +3137,7 @@ async def send_game( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -3146,7 +3146,7 @@ async def send_game( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: @@ -3853,7 +3853,7 @@ async def edit_message_text( argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| @@ -4916,7 +4916,7 @@ async def send_invoice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -4925,7 +4925,7 @@ async def send_invoice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: @@ -6906,7 +6906,7 @@ async def send_poll( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -6915,7 +6915,7 @@ async def send_poll( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: @@ -7066,7 +7066,7 @@ async def send_dice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -7075,7 +7075,7 @@ async def send_dice( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| @@ -7491,7 +7491,7 @@ async def copy_message( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| reply_to_message_id (:obj:`int`, optional): |reply_to_msg_id| Mutually exclusive with :paramref:`reply_parameters`, which this is a convenience @@ -7500,7 +7500,7 @@ async def copy_message( .. versionchanged:: 20.8 Bot API 7.0 introduced :paramref:`reply_parameters` |rtm_aswr_deprecated| - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Returns: diff --git a/telegram/_chat.py b/telegram/_chat.py index 8115c60566e..c304be02def 100644 --- a/telegram/_chat.py +++ b/telegram/_chat.py @@ -223,12 +223,12 @@ class Chat(TelegramObject): boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions. Returned only in :meth:`telegram.Bot.get_chat`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 custom_emoji_sticker_set_name (:obj:`str`, optional): For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be used by all users and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 Attributes: id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits @@ -366,12 +366,12 @@ class Chat(TelegramObject): boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions. Returned only in :meth:`telegram.Bot.get_chat`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 custom_emoji_sticker_set_name (:obj:`str`): Optional. For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be used by all users and bots in the group. Returned only in :meth:`telegram.Bot.get_chat`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 .. _topics: https://telegram.org/blog/topics-in-groups-collectible-usernames#topics-in-groups .. _accent colors: https://core.telegram.org/bots/api#accent-colors diff --git a/telegram/_chatadministratorrights.py b/telegram/_chatadministratorrights.py index f5bbb7e568a..fd6e45596dd 100644 --- a/telegram/_chatadministratorrights.py +++ b/telegram/_chatadministratorrights.py @@ -73,19 +73,19 @@ class ChatAdministratorRights(TelegramObject): stories to the chat. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; for supergroups only. @@ -121,19 +121,19 @@ class ChatAdministratorRights(TelegramObject): stories to the chat. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; for supergroups only. @@ -192,7 +192,7 @@ def __init__( # Not actually optionals but because of backwards compatability we pretend they are if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: raise TypeError( - "As of vNEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories" + "As of v21.0 can_post_stories, can_edit_stories and can_delete_stories" " must be set in order to create this object." ) self.can_post_stories: bool = can_post_stories diff --git a/telegram/_chatboost.py b/telegram/_chatboost.py index f16cf9db0eb..cb7010a3cd4 100644 --- a/telegram/_chatboost.py +++ b/telegram/_chatboost.py @@ -42,7 +42,7 @@ class ChatBoostAdded(TelegramObject): Two objects of this class are considered equal, if their :attr:`boost_count` are equal. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 Args: boost_count (:obj:`int`): Number of boosts added by the user. diff --git a/telegram/_chatmember.py b/telegram/_chatmember.py index c251e23c620..b42866b3a1d 100644 --- a/telegram/_chatmember.py +++ b/telegram/_chatmember.py @@ -228,19 +228,19 @@ class ChatMemberAdministrator(ChatMember): stories to the chat. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_manage_topics (:obj:`bool`, optional): :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; for supergroups only. @@ -287,19 +287,19 @@ class ChatMemberAdministrator(ChatMember): stories to the chat. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_edit_stories (:obj:`bool`): :obj:`True`, if the administrator can edit stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_delete_stories (:obj:`bool`): :obj:`True`, if the administrator can delete stories posted by other users. .. versionadded:: 20.6 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |non_optional_story_argument| can_manage_topics (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to create, rename, close, and reopen forum topics; for supergroups only @@ -365,7 +365,7 @@ def __init__( # Not actually optionals but because of backwards compatability we pretend they are if can_post_stories is None or can_edit_stories is None or can_delete_stories is None: raise TypeError( - "As of NEXT.VERSION can_post_stories, can_edit_stories and can_delete_stories " + "As of 21.0 can_post_stories, can_edit_stories and can_delete_stories " "must be set in order to create this object." ) self.can_post_stories: bool = can_post_stories diff --git a/telegram/_inline/inputtextmessagecontent.py b/telegram/_inline/inputtextmessagecontent.py index 711393da7bf..0e127ce70a7 100644 --- a/telegram/_inline/inputtextmessagecontent.py +++ b/telegram/_inline/inputtextmessagecontent.py @@ -66,7 +66,7 @@ class InputTextMessageContent(InputMessageContent): argument. PTB will automatically convert this argument to that one, but for advanced options, please use :paramref:`link_preview_options` directly. - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 |keyword_only_arg| Attributes: diff --git a/telegram/_keyboardbutton.py b/telegram/_keyboardbutton.py index 1f0ae352915..ad69a176137 100644 --- a/telegram/_keyboardbutton.py +++ b/telegram/_keyboardbutton.py @@ -52,7 +52,7 @@ class KeyboardButton(TelegramObject): versions released after 3 February, 2023. Older clients will display unsupported message. - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 Removed deprecated argument and attribute ``request_user``. .. versionchanged:: 20.0 :attr:`web_app` is considered as well when comparing objects of this type in terms of diff --git a/telegram/_message.py b/telegram/_message.py index c8662a12123..eac0c748486 100644 --- a/telegram/_message.py +++ b/telegram/_message.py @@ -121,7 +121,7 @@ class MaybeInaccessibleMessage(TelegramObject): Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`message_id` and :attr:`chat` are equal - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 ``__bool__`` is no longer overriden and defaults to Pythons standard implementation. .. versionadded:: 20.8 @@ -244,7 +244,7 @@ class Message(MaybeInaccessibleMessage): Note: In Python :keyword:`from` is a reserved word. Use :paramref:`from_user` instead. - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 Removed deprecated arguments and attributes ``user_shared``, ``forward_from``, ``forward_from_chat``, ``forward_from_message_id``, ``forward_signature``, ``forward_sender_name`` and ``forward_date``. @@ -525,15 +525,15 @@ class Message(MaybeInaccessibleMessage): reply_to_story (:class:`telegram.Story`, optional): For replies to a story, the original story. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 boost_added (:class:`telegram.ChatBoostAdded`, optional): Service message: user boosted the chat. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 sender_boost_count (:obj:`int`, optional): If the sender of the message boosted the chat, the number of boosts added by the user. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 Attributes: message_id (:obj:`int`): Unique message identifier inside this chat. @@ -807,15 +807,15 @@ class Message(MaybeInaccessibleMessage): reply_to_story (:class:`telegram.Story`): Optional. For replies to a story, the original story. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 boost_added (:class:`telegram.ChatBoostAdded`): Optional. Service message: user boosted the chat. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 sender_boost_count (:obj:`int`): Optional. If the sender of the message boosted the chat, the number of boosts added by the user. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 .. |custom_emoji_no_md1_support| replace:: Since custom emoji entities are not supported by :attr:`~telegram.constants.ParseMode.MARKDOWN`, this method now raises a diff --git a/telegram/_story.py b/telegram/_story.py index 42e4ae06d5e..4cb4a8454b6 100644 --- a/telegram/_story.py +++ b/telegram/_story.py @@ -37,7 +37,7 @@ class Story(TelegramObject): .. versionadded:: 20.5 - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 Added attributes :attr:`chat` and :attr:`id` and equality based on them. Args: diff --git a/telegram/_version.py b/telegram/_version.py index 89211499cb4..3d5edbd9925 100644 --- a/telegram/_version.py +++ b/telegram/_version.py @@ -51,7 +51,7 @@ def __str__(self) -> str: __version_info__: Final[Version] = Version( - major=20, minor=8, micro=0, releaselevel="final", serial=0 + major=21, minor=0, micro=0, releaselevel="final", serial=0 ) __version__: Final[str] = str(__version_info__) diff --git a/telegram/constants.py b/telegram/constants.py index ec5723d33e9..959e99ac454 100644 --- a/telegram/constants.py +++ b/telegram/constants.py @@ -1708,7 +1708,7 @@ class MessageType(StringEnum): BOOST_ADDED = "boost_added" """:obj:`str`: Messages with :attr:`telegram.Message.boost_added`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 """ CHANNEL_CHAT_CREATED = "channel_chat_created" """:obj:`str`: Messages with :attr:`telegram.Message.channel_chat_created`.""" @@ -1810,12 +1810,12 @@ class MessageType(StringEnum): REPLY_TO_STORY = "reply_to_story" """:obj:`str`: Messages with :attr:`telegram.Message.reply_to_story`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 """ SENDER_BOOST_COUNT = "sender_boost_count" """:obj:`str`: Messages with :attr:`telegram.Message.sender_boost_count`. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 """ STICKER = "sticker" """:obj:`str`: Messages with :attr:`telegram.Message.sticker`.""" diff --git a/telegram/ext/_applicationbuilder.py b/telegram/ext/_applicationbuilder.py index 106c73462b8..783a4985872 100644 --- a/telegram/ext/_applicationbuilder.py +++ b/telegram/ext/_applicationbuilder.py @@ -635,7 +635,7 @@ def media_write_timeout( :paramref:`~telegram.request.HTTPXRequest.media_write_timeout` parameter of :attr:`telegram.Bot.request`. Defaults to ``20``. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 Args: media_write_timeout (:obj:`float`): See diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index 9754569dcef..aad3ad95dc6 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -2158,7 +2158,7 @@ def filter(self, message: Message) -> bool: This will only catch the legacy ``user_shared`` field, not the new :attr:`telegram.Message.users_shared` attribute! - .. versionchanged:: NEXT.VERSION + .. versionchanged:: 21.0 Now relies on :attr:`telegram.TelegramObject.api_kwargs` as the native attribute ``Message.user_shared`` was removed. diff --git a/telegram/request/_httpxrequest.py b/telegram/request/_httpxrequest.py index 8c18d063012..626cce83002 100644 --- a/telegram/request/_httpxrequest.py +++ b/telegram/request/_httpxrequest.py @@ -121,7 +121,7 @@ class HTTPXRequest(BaseRequest): different value is passed to :paramref:`do_request.write_timeout` of :meth:`do_request`. Defaults to ``20`` seconds. - .. versionadded:: NEXT.VERSION + .. versionadded:: 21.0 """ diff --git a/tests/test_official/exceptions.py b/tests/test_official/exceptions.py index 6f83e9ca74e..edb1ed2ab12 100644 --- a/tests/test_official/exceptions.py +++ b/tests/test_official/exceptions.py @@ -132,7 +132,7 @@ def ptb_extra_params(object_name: str) -> set[str]: # Mostly due to the value being fixed anyway PTB_IGNORED_PARAMS = { r"InlineQueryResult\w+": {"type"}, - # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + # TODO: Remove this in v21.0 (API 7.1) when this can stop being optional r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, r"ChatMember\w+": {"status"}, @@ -170,7 +170,7 @@ def ignored_param_requirements(object_name: str) -> set[str]: # Arguments that are optional arguments for now for backwards compatibility BACKWARDS_COMPAT_KWARGS: dict[str, set[str]] = { - # TODO: Remove this in vNEXT.VERSION (API 7.1) when this can stop being optional + # TODO: Remove this in v21.0 (API 7.1) when this can stop being optional r"ChatAdministratorRights": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, r"ChatMemberAdministrator": {"can_post_stories", "can_edit_stories", "can_delete_stories"}, }