Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API 6.1 for V13 #3117

Merged
merged 10 commits into from Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.rst
Expand Up @@ -20,7 +20,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
:target: https://pypi.org/project/python-telegram-bot/
:alt: Supported Python versions

.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.1-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions

Expand Down Expand Up @@ -112,7 +112,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 **6.0** are supported.
All types and methods of the Telegram Bot API **6.1** are supported.

==========
Installing
Expand Down
4 changes: 2 additions & 2 deletions README_RAW.rst
Expand Up @@ -20,7 +20,7 @@ We have a vibrant community of developers helping each other in our `Telegram gr
:target: https://pypi.org/project/python-telegram-bot-raw/
:alt: Supported Python versions

.. image:: https://img.shields.io/badge/Bot%20API-6.0-blue?logo=telegram
.. image:: https://img.shields.io/badge/Bot%20API-6.1-blue?logo=telegram
:target: https://core.telegram.org/bots/api-changelog
:alt: Supported Bot API versions

Expand Down Expand Up @@ -105,7 +105,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 **6.0** are supported.
All types and methods of the Telegram Bot API **6.1** are supported.

==========
Installing
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Expand Up @@ -30,6 +30,7 @@ filterwarnings =
; Unfortunately due to https://github.com/pytest-dev/pytest/issues/8343 we can't have this here
; and instead do a trick directly in tests/conftest.py
; ignore::telegram.utils.deprecate.TelegramDeprecationWarning
markers = dev: If you want to test a specific test, use this
Bibo-Joshi marked this conversation as resolved.
Show resolved Hide resolved

[coverage:run]
branch = True
Expand Down
2 changes: 1 addition & 1 deletion telegram/__main__.py
Expand Up @@ -41,7 +41,7 @@ def print_ver_info() -> None: # skipcq: PY-D0003
git_revision = _git_revision()
print(f'python-telegram-bot {telegram_ver}' + (f' ({git_revision})' if git_revision else ''))
print(f'Bot API {BOT_API_VERSION}')
print(f'certifi {certifi.__version__}') # type: ignore[attr-defined]
print('certifi' + certifi.__version__)
sys_version = sys.version.replace('\n', ' ')
print(f'Python {sys_version}')

Expand Down
146 changes: 143 additions & 3 deletions telegram/bot.py
Expand Up @@ -3080,16 +3080,17 @@ def set_webhook(
api_kwargs: JSONDict = None,
ip_address: str = None,
drop_pending_updates: bool = None,
secret_token: str = None,
) -> bool:
"""
Use this method to specify a url and receive incoming updates via an outgoing webhook.
Whenever there is an update for the bot, Telegram will send an HTTPS POST request to the
specified url, containing a JSON-serialized Update. In case of an unsuccessful request,
Telegram will give up after a reasonable amount of attempts.

If you'd like to make sure that the Webhook request comes from Telegram, Telegram
recommends using a secret path in the URL, e.g. https://www.example.com/<token>. Since
nobody else knows your bot's token, you can be pretty sure it's us.
If you'd like to make sure that the Webhook was set by you, you can specify secret data in
the parameter ``secret_token``. If specified, the request will contain a header
``X-Telegram-Bot-Api-Secret-Token`` with the secret token as content.

Note:
The certificate argument should be a file from disk ``open(filename, 'rb')``.
Expand Down Expand Up @@ -3117,6 +3118,12 @@ def set_webhook(
a short period of time.
drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending
updates.
secret_token (:obj:`str`, optional): A secret token to be sent in a header
``X-Telegram-Bot-Api-Secret-Token`` in every webhook request, 1-256 characters.
Only characters ``A-Z``, ``a-z``, ``0-9``, ``_`` and ``-`` are allowed.
The header is useful to ensure that the request comes from a webhook set by you.

.. versionadded:: 13.13
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
Expand Down Expand Up @@ -3157,6 +3164,8 @@ def set_webhook(
data['ip_address'] = ip_address
if drop_pending_updates:
data['drop_pending_updates'] = drop_pending_updates
if secret_token is not None:
data["secret_token"] = secret_token
Poolitzer marked this conversation as resolved.
Show resolved Hide resolved

result = self._post('setWebhook', data, timeout=timeout, api_kwargs=api_kwargs)

Expand Down Expand Up @@ -5914,6 +5923,135 @@ def get_chat_menu_button(
)
return MenuButton.de_json(result, bot=self) # type: ignore[return-value, arg-type]

@log
def create_invoice_link(
self,
title: str,
description: str,
payload: str,
provider_token: str,
currency: str,
prices: List["LabeledPrice"],
max_tip_amount: int = None,
suggested_tip_amounts: List[int] = None,
provider_data: Union[str, object] = None,
photo_url: str = None,
photo_size: int = None,
photo_width: int = None,
photo_height: int = None,
need_name: bool = None,
need_phone_number: bool = None,
need_email: bool = None,
need_shipping_address: bool = None,
send_phone_number_to_provider: bool = None,
send_email_to_provider: bool = None,
is_flexible: bool = None,
timeout: ODVInput[float] = DEFAULT_NONE,
api_kwargs: JSONDict = None,
) -> str:
"""Use this method to create a link for an invoice.

.. versionadded:: 13.13

Args:
title (:obj:`str`): Product name. 1-32 characters.
description (:obj:`str`): Product description. 1-255 characters.
payload (:obj:`str`): Bot-defined invoice payload. 1-128 bytes. This will not be
displayed to the user, use for your internal processes.
provider_token (:obj:`str`): Payments provider token, obtained via
`@BotFather <https://t.me/BotFather>`_.
currency (:obj:`str`): Three-letter ISO 4217 currency code, see `more on currencies
<https://core.telegram.org/bots/payments#supported-currencies>`_.
prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list
of components (e.g. product price, tax, discount, delivery cost, delivery tax,
bonus, etc.).
max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the
*smallest* units of the currency (integer, **not** float/double). For example, for
a maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in
`currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it
shows the number of digits past the decimal point for each currency (2 for the
majority of currencies). Defaults to ``0``.
suggested_tip_amounts (List[:obj:`int`], optional): An array of
suggested amounts of tips in the *smallest* units of the currency (integer, **not**
float/double). At most 4 suggested tip amounts can be specified. The suggested tip
amounts must be positive, passed in a strictly increased order and must not exceed
``max_tip_amount``.
provider_data (:obj:`str` | :obj:`object`, optional): Data about the
invoice, which will be shared with the payment provider. A detailed description of
required fields should be provided by the payment provider. When an object is
passed, it will be encoded as JSON.
photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a
photo of the goods or a marketing image for a service.
photo_size (:obj:`int`, optional): Photo size in bytes.
photo_width (:obj:`int`, optional): Photo width.
photo_height (:obj:`int`, optional): Photo height.
need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full
name to complete the order.
need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's
phone number to complete the order.
need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email
address to complete the order.
need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the
user's shipping address to complete the order.
send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's
phone number should be sent to provider.
send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email
address should be sent to provider.
is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on
the shipping method.
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
the read timeout from the server (instead of the one specified during creation of
the connection pool).
api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
Telegram API.

Returns:
:class:`str`: On success, the created invoice link is returned.
"""
data: JSONDict = {
"title": title,
"description": description,
"payload": payload,
"provider_token": provider_token,
"currency": currency,
"prices": [p.to_dict() for p in prices],
}
if max_tip_amount is not None:
data["max_tip_amount"] = max_tip_amount
if suggested_tip_amounts is not None:
data["suggested_tip_amounts"] = suggested_tip_amounts
if provider_data is not None:
data["provider_data"] = provider_data
if photo_url is not None:
data["photo_url"] = photo_url
if photo_size is not None:
data["photo_size"] = photo_size
if photo_width is not None:
data["photo_width"] = photo_width
if photo_height is not None:
data["photo_height"] = photo_height
if need_name is not None:
data["need_name"] = need_name
if need_phone_number is not None:
data["need_phone_number"] = need_phone_number
if need_email is not None:
data["need_email"] = need_email
if need_shipping_address is not None:
data["need_shipping_address"] = need_shipping_address
if is_flexible is not None:
data["is_flexible"] = is_flexible
if send_phone_number_to_provider is not None:
data["send_phone_number_to_provider"] = send_phone_number_to_provider
if send_email_to_provider is not None:
data["send_email_to_provider"] = send_email_to_provider

return self._post( # type: ignore[return-value]
"createInvoiceLink",
data,
timeout=timeout,
api_kwargs=api_kwargs,
)

def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`."""
data: JSONDict = {'id': self.id, 'username': self.username, 'first_name': self.first_name}
Expand Down Expand Up @@ -6106,3 +6244,5 @@ def __hash__(self) -> int:
"""Alias for :meth:`get_my_default_administrator_rights`"""
setMyDefaultAdministratorRights = set_my_default_administrator_rights
"""Alias for :meth:`set_my_default_administrator_rights`"""
createInvoiceLink = create_invoice_link
"""Alias for :meth:`create_invoice_link`"""
25 changes: 25 additions & 0 deletions telegram/chat.py
Expand Up @@ -116,6 +116,16 @@ class Chat(TelegramObject):
chats. Returned only in :meth:`telegram.Bot.get_chat`.
location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which
the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`.
join_to_send_messages (:obj:`bool`, optional): :obj:`True`, if users need to join the
supergroup before they can send messages. Returned only in
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.13
join_by_request (:obj:`bool`, optional): :obj:`True`, if all users directly joining the
supergroup need to be approved by supergroup administrators. Returned only in
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.13
**kwargs (:obj:`dict`): Arbitrary keyword arguments.

Attributes:
Expand Down Expand Up @@ -160,7 +170,16 @@ class Chat(TelegramObject):
chats. Returned only in :meth:`telegram.Bot.get_chat`.
location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which
the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`.
join_to_send_messages (:obj:`bool`): Optional. :obj:`True`, if users need to join the
supergroup before they can send messages. Returned only in
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.13
join_by_request (:obj:`bool`): Optional. :obj:`True`, if all users directly joining the
supergroup need to be approved by supergroup administrators. Returned only in
:meth:`telegram.Bot.get_chat`.

.. versionadded:: 13.13
"""

__slots__ = (
Expand All @@ -186,6 +205,8 @@ class Chat(TelegramObject):
'message_auto_delete_time',
'has_protected_content',
'has_private_forwards',
'join_to_send_messages',
'join_by_request',
'_id_attrs',
)

Expand Down Expand Up @@ -226,6 +247,8 @@ def __init__(
message_auto_delete_time: int = None,
has_private_forwards: bool = None,
has_protected_content: bool = None,
join_to_send_messages: bool = None,
join_by_request: bool = None,
**_kwargs: Any,
):
# Required
Expand Down Expand Up @@ -254,6 +277,8 @@ def __init__(
self.can_set_sticker_set = can_set_sticker_set
self.linked_chat_id = linked_chat_id
self.location = location
self.join_to_send_messages = join_to_send_messages
self.join_by_request = join_by_request

self.bot = bot
self._id_attrs = (self.id,)
Expand Down
4 changes: 2 additions & 2 deletions telegram/constants.py
Expand Up @@ -21,7 +21,7 @@
`Telegram Bots API <https://core.telegram.org/bots/api>`_.
Attributes:
BOT_API_VERSION (:obj:`str`): `6.0`. Telegram Bot API version supported by this
BOT_API_VERSION (:obj:`str`): `6.1`. Telegram Bot API version supported by this
version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``.
.. versionadded:: 13.4
Expand Down Expand Up @@ -247,7 +247,7 @@
"""
from typing import List

BOT_API_VERSION: str = '6.0'
BOT_API_VERSION: str = '6.1'
harshil21 marked this conversation as resolved.
Show resolved Hide resolved
MAX_MESSAGE_LENGTH: int = 4096
MAX_CAPTION_LENGTH: int = 1024
ANONYMOUS_ADMIN_ID: int = 1087968824
Expand Down
32 changes: 32 additions & 0 deletions telegram/ext/filters.py
Expand Up @@ -1004,6 +1004,38 @@ def filter(self, message: Message) -> bool:
location = _Location()
"""Messages that contain :class:`telegram.Location`."""

class _UserAttachment(UpdateFilter):
__slots__ = ()
name = "Filters.user_attachment"

def filter(self, update: Update) -> bool:
return bool(update.effective_user) and bool(
update.effective_user.added_to_attachment_menu
)

user_attachment = _UserAttachment()
"""This filter filters *any* message that have a user who added the bot to their
:attr:`attachment menu <telegram.User.added_to_attachment_menu>` as
:attr:`telegram.Update.effective_user`.

.. versionadded:: 13.13
"""

class _UserPremium(UpdateFilter):
__slots__ = ()
name = "Filters.premium_user"

def filter(self, update: Update) -> bool:
return bool(update.effective_user) and bool(update.effective_user.is_premium)

premium_user = _UserPremium()
"""This filter filters *any* message from a
:attr:`Telegram Premium user <telegram.User.is_premium>` as
:attr:`telegram.Update.effective_user`.

.. versionadded:: 13.13
"""

class _Venue(MessageFilter):
__slots__ = ()
name = 'Filters.venue'
Expand Down
5 changes: 5 additions & 0 deletions telegram/ext/updater.py
Expand Up @@ -463,6 +463,11 @@ def start_webhook(
application. Else, the webhook will be started on
https://listen:port/url_path. Also calls :meth:`telegram.Bot.set_webhook` as required.
Note:
``telegram.Bot.set_webhook.secret_token`` is not checked by this webhook
implementation. If you want to use this new security parameter, either build your own
webhook server or update your code to version 20.0a2+.
.. versionchanged:: 13.4
:meth:`start_webhook` now *always* calls :meth:`telegram.Bot.set_webhook`, so pass
``webhook_url`` instead of calling ``updater.bot.set_webhook(webhook_url)`` manually.
Expand Down