Bot API 5.0 (#454)

* increased Telegram Bot API version

* AIOG-T-64 added logOut method

* AIOG-T-64 added logOut method test

* AIOG-T-64 logOut type annotation fix

* AIOG-T-65 added close (close_bot) method

* AIOG-T-65 old `close` method deprecation warn

* AIOG-T-65 `close_bot` test added

* AIOG-T-67 added ip_address param to set_webhook, updated docs

* updated deprecation text

Co-authored-by: Martin Winks <mpa@snejugal.ru>

* AIOG-T-69 param `drop_pending_updates` added in methods `setWebhook` and `deleteWebhook`

* AIOG-T-71 new `ChatLocation` class

* AIOG-T-70 updated `Chat` class: bio, linked chats, location

* AIOG-T-68 field `ip_address` added to class `WebhookInfo`

* AIOG-T-72 param `only_if_banned` added to `unbanChatMember` method

* AIOG-T-72 updated Chat.unban shortcut

* AIOG-T-73 field `file_name` added to `Audio` and `Video` classes

* AIOG-T-74 param `disable_content_type_detection` added in `sendDocument` method and `InputMediaDocument` class

* AIOG-T-75 Added the ability to pin messages in private chats (docs update)

* AIOG-T-76 Added the parameter message_id to the method unpinChatMessage to allow unpinning of the specific pinned message

* AIOG-T-77 Added the method unpinAllChatMessages, which can be used to unpin all pinned messages in a chat.

* AIOG-T-78 updated send_media_group description; added media qty check

* AIOG-T-80 field `live_period` added to `Location` class

* AIOG-T-81 Added support for live location heading

* AIOG-T-82 added the field proximity_alert_distance to the classes Location, InlineQueryResultLocation, InputLocationMessageContent; fixed heading in InputLocationMessageContent

* AIOG-T-82 added parameter proximity_alert_distance to the methods sendLocation and editMessageLiveLocation

* AIOG-T-83 Added the type ProximityAlertTriggered

* AIOG-T-83 Added field proximity_alert_triggered to the class Message

* AIOG-T-84 Added the field horizontal_accuracy to the classes Location, InlineQueryResultLocation, InputLocationMessageContent

* AIOG-T-84 Added the parameter horizontal_accuracy to the methods sendLocation and editMessageLiveLocation.

* Added live_period to InputLocationMessageContent (missed?)

* AIOG-T-85 Added the field sender_chat to the class Message

* AIOG-T-86 Added `is_anonymous` field to `chatMember` class

* AIOG-T-87 Added the parameter is_anonymous to the method promoteChatMember

* AIOG-T-89 Added the method `copyMessage`

* AIOG-T-90 Poll docs update

* AIOG-T-91 ability to manually specify text entities

* AIOG-T-92 Google Places as a venue API provider

* AIOG-T-93 Added the field allow_sending_without_reply to the methods

* AIOG-T-94 football and slot machine dice

* removed Optional

Co-authored-by: Ramzan Bekbulatov <bekbulatov.ramzan@ya.ru>

* Apply suggestions from code review

removed Optional

Co-authored-by: Ramzan Bekbulatov <bekbulatov.ramzan@ya.ru>

* Don't use deprecated Bot.close method from dispatcher (Replaced by session.close)

* Fix copyMessage method, update alias (with deprecation)
Fix imports

* AIOG-T-79: Easy way to use custom API server

* Update docs

* Bump requirements

* Rollback email

* AIOG-T-93 allow_sending_without_reply to send_message shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_photo shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_video shortcuts

* Union[type, None] -> Optional[type] refactoring

* AIOG-T-93 added allow_sending_without_reply to send_animation shortcuts

* added type hint to reply field

* AIOG-T-93 added allow_sending_without_reply to send_audio shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_document shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_sticker shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_video_note shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_voice shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_location shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_venue shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_contact shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_poll shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_dice shortcuts

* AIOG-T-93 added allow_sending_without_reply to send_media_group shortcuts

* AIOG-T-92 added google_place_ to send_venue shortcuts

* AIOG-T-91 added entities to send_message shortcuts

* AIOG-T-91 added caption_entities to send_photo shortcuts

* AIOG-T-91 added caption_entities to send_video shortcuts

* AIOG-T-91 added caption_entities to send_animation shortcuts

* AIOG-T-91 added caption_entities to send_audio shortcuts

* AIOG-T-91 added caption_entities to send_document shortcuts

* AIOG-T-91 added caption_entities to send_voice shortcuts

* AIOG-T-91 added explanation_parse_mode to send_poll shortcuts

* AIOG-T-91 added entities to edit_message_text shortcuts

* AIOG-T-91 added caption_entities to edit_message_caption shortcuts

* fixed types.MessageEntity -> MessageEntity in docs

Co-authored-by: Martin Winks <mpa@snejugal.ru>
Co-authored-by: Ramzan Bekbulatov <bekbulatov.ramzan@ya.ru>
Co-authored-by: Alex Root Junior <jroot.junior@gmail.com>
This commit is contained in:
Oleg A 2020-11-08 18:51:39 +03:00 committed by GitHub
parent 8c43c209e0
commit 2b060d9ad4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 2847 additions and 1194 deletions

View file

@ -21,7 +21,7 @@ AIOGramBot
:target: https://pypi.python.org/pypi/aiogram
:alt: Supported python versions
.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-4.9-blue.svg?style=flat-square&logo=telegram
.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.0-blue.svg?style=flat-square&logo=telegram
:target: https://core.telegram.org/bots/api
:alt: Telegram Bot API

View file

@ -44,4 +44,4 @@ __all__ = (
)
__version__ = '2.10'
__api_version__ = '4.9'
__api_version__ = '5.0'

View file

@ -1,20 +1,57 @@
import logging
import os
from dataclasses import dataclass
from http import HTTPStatus
import aiohttp
from .. import types
from ..utils import exceptions
from ..utils import json
from ..utils import exceptions, json
from ..utils.helper import Helper, HelperMode, Item
# Main aiogram logger
log = logging.getLogger('aiogram')
# API Url's
API_URL = "https://api.telegram.org/bot{token}/{method}"
FILE_URL = "https://api.telegram.org/file/bot{token}/{path}"
@dataclass(frozen=True)
class TelegramAPIServer:
"""
Base config for API Endpoints
"""
base: str
file: str
def api_url(self, token: str, method: str) -> str:
"""
Generate URL for API methods
:param token: Bot token
:param method: API method name (case insensitive)
:return: URL
"""
return self.base.format(token=token, method=method)
def file_url(self, token: str, path: str) -> str:
"""
Generate URL for downloading files
:param token: Bot token
:param path: file path
:return: URL
"""
return self.file.format(token=token, path=path)
@classmethod
def from_base(cls, base: str) -> 'TelegramAPIServer':
base = base.rstrip("/")
return cls(
base=f"{base}/bot{{token}}/{{method}}",
file=f"{base}/file/bot{{token}}/{{method}}",
)
TELEGRAM_PRODUCTION = TelegramAPIServer.from_base("https://api.telegram.org")
def check_token(token: str) -> bool:
@ -92,11 +129,10 @@ def check_result(method_name: str, content_type: str, status_code: int, body: st
raise exceptions.TelegramAPIError(f"{description} [{status_code}]")
async def make_request(session, token, method, data=None, files=None, **kwargs):
# log.debug(f"Make request: '{method}' with data: {data} and files {files}")
async def make_request(session, server, token, method, data=None, files=None, **kwargs):
log.debug('Make request: "%s" with data: "%r" and files "%r"', method, data, files)
url = Methods.api_url(token=token, method=method)
url = server.api_url(token=token, method=method)
req = compose_data(data, files)
try:
@ -153,7 +189,7 @@ class Methods(Helper):
"""
Helper for Telegram API Methods listed on https://core.telegram.org/bots/api
List is updated to Bot API 4.9
List is updated to Bot API 5.0
"""
mode = HelperMode.lowerCamelCase
@ -165,8 +201,11 @@ class Methods(Helper):
# Available methods
GET_ME = Item() # getMe
LOG_OUT = Item() # logOut
CLOSE = Item() # close
SEND_MESSAGE = Item() # sendMessage
FORWARD_MESSAGE = Item() # forwardMessage
COPY_MESSAGE = Item() # copyMessage
SEND_PHOTO = Item() # sendPhoto
SEND_AUDIO = Item() # sendAudio
SEND_DOCUMENT = Item() # sendDocument
@ -198,6 +237,7 @@ class Methods(Helper):
SET_CHAT_DESCRIPTION = Item() # setChatDescription
PIN_CHAT_MESSAGE = Item() # pinChatMessage
UNPIN_CHAT_MESSAGE = Item() # unpinChatMessage
UNPIN_ALL_CHAT_MESSAGES = Item() # unpinAllChatMessages
LEAVE_CHAT = Item() # leaveChat
GET_CHAT = Item() # getChat
GET_CHAT_ADMINISTRATORS = Item() # getChatAdministrators
@ -242,25 +282,3 @@ class Methods(Helper):
SEND_GAME = Item() # sendGame
SET_GAME_SCORE = Item() # setGameScore
GET_GAME_HIGH_SCORES = Item() # getGameHighScores
@staticmethod
def api_url(token, method):
"""
Generate API URL with included token and method name
:param token:
:param method:
:return:
"""
return API_URL.format(token=token, method=method)
@staticmethod
def file_url(token, path):
"""
Generate File URL with included token and file path
:param token:
:param path:
:return:
"""
return FILE_URL.format(token=token, path=path)

View file

@ -12,9 +12,11 @@ import certifi
from aiohttp.helpers import sentinel
from . import api
from .api import TelegramAPIServer, TELEGRAM_PRODUCTION
from ..types import ParseMode, base
from ..utils import json
from ..utils.auth_widget import check_integrity
from ..utils.deprecated import deprecated
class BaseBot:
@ -33,7 +35,8 @@ class BaseBot:
proxy_auth: Optional[aiohttp.BasicAuth] = None,
validate_token: Optional[base.Boolean] = True,
parse_mode: typing.Optional[base.String] = None,
timeout: typing.Optional[typing.Union[base.Integer, base.Float, aiohttp.ClientTimeout]] = None
timeout: typing.Optional[typing.Union[base.Integer, base.Float, aiohttp.ClientTimeout]] = None,
server: TelegramAPIServer = TELEGRAM_PRODUCTION
):
"""
Instructions how to get Bot token is found here: https://core.telegram.org/bots#3-how-do-i-create-a-bot
@ -54,6 +57,8 @@ class BaseBot:
:type parse_mode: :obj:`str`
:param timeout: Request timeout
:type timeout: :obj:`typing.Optional[typing.Union[base.Integer, base.Float, aiohttp.ClientTimeout]]`
:param server: Telegram Bot API Server endpoint.
:type server: :obj:`TelegramAPIServer`
:raise: when token is invalid throw an :obj:`aiogram.utils.exceptions.ValidationError`
"""
self._main_loop = loop
@ -64,6 +69,7 @@ class BaseBot:
self._token = None
self.__token = token
self.id = int(token.split(sep=':')[0])
self.server = server
self.proxy = proxy
self.proxy_auth = proxy_auth
@ -173,6 +179,8 @@ class BaseBot:
finally:
self._ctx_token.reset(token)
@deprecated("This method's behavior will be changed in aiogram v3.0. "
"More info: https://core.telegram.org/bots/api#close", stacklevel=3)
async def close(self):
"""
Close all client sessions
@ -197,7 +205,7 @@ class BaseBot:
:rtype: Union[List, Dict]
:raise: :obj:`aiogram.exceptions.TelegramApiError`
"""
return await api.make_request(self.session, self.__token, method, data, files,
return await api.make_request(self.session, self.server, self.__token, method, data, files,
proxy=self.proxy, proxy_auth=self.proxy_auth, timeout=self.timeout, **kwargs)
async def download_file(self, file_path: base.String,
@ -237,7 +245,7 @@ class BaseBot:
return dest
def get_file_url(self, file_path):
return api.Methods.file_url(token=self.__token, path=file_path)
return self.server.file_url(token=self.__token, path=file_path)
async def send_file(self, file_type, method, file, payload) -> Union[Dict, base.Boolean]:
"""

File diff suppressed because it is too large Load diff

View file

@ -55,7 +55,7 @@ class RethinkDBStorage(BaseStorage):
self._ssl = ssl or {}
self._loop = loop
self._conn: typing.Union[Connection, None] = None
self._conn: typing.Optional[Connection] = None
async def connect(self) -> Connection:
"""

View file

@ -300,7 +300,7 @@ class FSMContext:
async def update_data(self, data: typing.Dict = None, **kwargs):
await self.storage.update_data(chat=self.chat, user=self.user, data=data, **kwargs)
async def set_state(self, state: typing.Union[typing.AnyStr, None] = None):
async def set_state(self, state: typing.Optional[typing.AnyStr] = None):
await self.storage.set_state(chat=self.chat, user=self.user, state=self._resolve_state(state))
async def set_data(self, data: typing.Dict = None):

View file

@ -939,8 +939,8 @@ class SendMediaGroup(BaseResponse, ReplyToMixin, DisableNotificationMixin):
def __init__(self, chat_id: Union[Integer, String],
media: Union[types.MediaGroup, List] = None,
disable_notification: typing.Union[Boolean, None] = None,
reply_to_message_id: typing.Union[Integer, None] = None):
disable_notification: typing.Optional[Boolean] = None,
reply_to_message_id: typing.Optional[Integer] = None):
"""
Use this method to send a group of photos or videos as an album.
@ -951,9 +951,9 @@ class SendMediaGroup(BaseResponse, ReplyToMixin, DisableNotificationMixin):
:param media: A JSON-serialized array describing photos and videos to be sent
:type media: :obj:`typing.Union[types.MediaGroup, typing.List]`
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
:type disable_notification: :obj:`typing.Optional[base.Boolean]`
:param reply_to_message_id: If the message is a reply, ID of the original message
:type reply_to_message_id: :obj:`typing.Union[base.Integer, None]`
:type reply_to_message_id: :obj:`typing.Optional[base.Integer]`
:return: On success, an array of the sent Messages is returned.
:rtype: typing.List[types.Message]
"""

View file

@ -7,6 +7,7 @@ from .bot_command import BotCommand
from .callback_game import CallbackGame
from .callback_query import CallbackQuery
from .chat import Chat, ChatActions, ChatType
from .chat_location import ChatLocation
from .chat_member import ChatMember, ChatMemberStatus
from .chat_permissions import ChatPermissions
from .chat_photo import ChatPhoto
@ -40,6 +41,7 @@ from .login_url import LoginUrl
from .mask_position import MaskPosition
from .message import ContentType, ContentTypes, Message, ParseMode
from .message_entity import MessageEntity, MessageEntityType
from .message_id import MessageId
from .order_info import OrderInfo
from .passport_data import PassportData
from .passport_element_error import PassportElementError, PassportElementErrorDataField, PassportElementErrorFile, \
@ -49,6 +51,7 @@ from .passport_file import PassportFile
from .photo_size import PhotoSize
from .poll import PollOption, Poll, PollAnswer, PollType
from .pre_checkout_query import PreCheckoutQuery
from .proximity_alert_triggered import ProximityAlertTriggered
from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, KeyboardButtonPollType
from .response_parameters import ResponseParameters
from .shipping_address import ShippingAddress
@ -76,6 +79,7 @@ __all__ = (
'CallbackQuery',
'Chat',
'ChatActions',
'ChatLocation',
'ChatMember',
'ChatMemberStatus',
'ChatPermissions',
@ -141,6 +145,7 @@ __all__ = (
'Message',
'MessageEntity',
'MessageEntityType',
'MessageId',
'OrderInfo',
'ParseMode',
'PassportData',
@ -158,6 +163,7 @@ __all__ = (
'PollOption',
'PollType',
'PreCheckoutQuery',
'ProximityAlertTriggered',
'ReplyKeyboardMarkup',
'ReplyKeyboardRemove',
'ResponseParameters',

View file

@ -15,6 +15,7 @@ class Audio(base.TelegramObject, mixins.Downloadable):
duration: base.Integer = fields.Field()
performer: base.String = fields.Field()
title: base.String = fields.Field()
file_name: base.String = fields.Field()
mime_type: base.String = fields.Field()
file_size: base.Integer = fields.Field()
thumb: PhotoSize = fields.Field(base=PhotoSize)

View file

@ -28,10 +28,10 @@ class CallbackQuery(base.TelegramObject):
data: base.String = fields.Field()
game_short_name: base.String = fields.Field()
async def answer(self, text: typing.Union[base.String, None] = None,
show_alert: typing.Union[base.Boolean, None] = None,
url: typing.Union[base.String, None] = None,
cache_time: typing.Union[base.Integer, None] = None):
async def answer(self, text: typing.Optional[base.String] = None,
show_alert: typing.Optional[base.Boolean] = None,
url: typing.Optional[base.String] = None,
cache_time: typing.Optional[base.Integer] = None):
"""
Use this method to send answers to callback queries sent from inline keyboards.
The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
@ -43,15 +43,15 @@ class CallbackQuery(base.TelegramObject):
Source: https://core.telegram.org/bots/api#answercallbackquery
:param text: Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters
:type text: :obj:`typing.Union[base.String, None]`
:type text: :obj:`typing.Optional[base.String]`
:param show_alert: If true, an alert will be shown by the client instead of a notification
at the top of the chat screen. Defaults to false.
:type show_alert: :obj:`typing.Union[base.Boolean, None]`
:type show_alert: :obj:`typing.Optional[base.Boolean]`
:param url: URL that will be opened by the user's client.
:type url: :obj:`typing.Union[base.String, None]`
:type url: :obj:`typing.Optional[base.String]`
:param cache_time: The maximum amount of time in seconds that the
result of the callback query may be cached client-side.
:type cache_time: :obj:`typing.Union[base.Integer, None]`
:type cache_time: :obj:`typing.Optional[base.Integer]`
:return: On success, True is returned.
:rtype: :obj:`base.Boolean`"""
return await self.bot.answer_callback_query(callback_query_id=self.id,

View file

@ -4,12 +4,13 @@ import asyncio
import datetime
import typing
from ..utils import helper, markdown
from . import base, fields
from .chat_location import ChatLocation
from .chat_member import ChatMember
from .chat_permissions import ChatPermissions
from .chat_photo import ChatPhoto
from .input_file import InputFile
from ..utils import helper, markdown
from ..utils.deprecated import deprecated, DeprecatedReadOnlyClassVar
@ -27,6 +28,7 @@ class Chat(base.TelegramObject):
last_name: base.String = fields.Field()
all_members_are_administrators: base.Boolean = fields.Field()
photo: ChatPhoto = fields.Field(base=ChatPhoto)
bio: base.String = fields.Field()
description: base.String = fields.Field()
invite_link: base.String = fields.Field()
pinned_message: 'Message' = fields.Field(base='Message')
@ -34,6 +36,8 @@ class Chat(base.TelegramObject):
slow_mode_delay: base.Integer = fields.Field()
sticker_set_name: base.String = fields.Field()
can_set_sticker_set: base.Boolean = fields.Field()
linked_chat_id: base.Integer = fields.Field()
location: ChatLocation = fields.Field()
def __hash__(self):
return self.id
@ -48,7 +52,7 @@ class Chat(base.TelegramObject):
return self.title
@property
def mention(self) -> typing.Union[base.String, None]:
def mention(self) -> typing.Optional[base.String]:
"""
Get mention if a Chat has a username, or get full name if this is a Private Chat, otherwise None is returned
"""
@ -175,14 +179,15 @@ class Chat(base.TelegramObject):
Source: https://core.telegram.org/bots/api#setchatdescription
:param description: New chat description, 0-255 characters
:type description: :obj:`typing.Union[base.String, None]`
:type description: :obj:`typing.Optional[base.String]`
:return: Returns True on success.
:rtype: :obj:`base.Boolean`
"""
return await self.bot.set_chat_description(self.id, description)
async def kick(self, user_id: base.Integer,
until_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean:
until_date: typing.Union[
base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean:
"""
Use this method to kick a user from a group, a supergroup or a channel.
In the case of supergroups and channels, the user will not be able to return to the group
@ -199,35 +204,49 @@ class Chat(base.TelegramObject):
:param user_id: Unique identifier of the target user
:type user_id: :obj:`base.Integer`
:param until_date: Date when the user will be unbanned, unix time.
:type until_date: :obj:`typing.Union[base.Integer, None]`
:type until_date: :obj:`typing.Optional[base.Integer]`
:return: Returns True on success.
:rtype: :obj:`base.Boolean`
"""
return await self.bot.kick_chat_member(self.id, user_id=user_id, until_date=until_date)
async def unban(self, user_id: base.Integer) -> base.Boolean:
async def unban(self,
user_id: base.Integer,
only_if_banned: typing.Optional[base.Boolean] = None,
) -> base.Boolean:
"""
Use this method to unban a previously kicked user in a supergroup or channel. `
The user will not return to the group or channel automatically, but will be able to join via link, etc.
The bot must be an administrator for this to work.
Use this method to unban a previously kicked user in a supergroup or channel.
The user will not return to the group or channel automatically, but will be
able to join via link, etc. The bot must be an administrator for this to
work. By default, this method guarantees that after the call the user is not
a member of the chat, but will be able to join it. So if the user is a member
of the chat they will also be removed from the chat. If you don't want this,
use the parameter only_if_banned. Returns True on success.
Source: https://core.telegram.org/bots/api#unbanchatmember
:param user_id: Unique identifier of the target user
:type user_id: :obj:`base.Integer`
:param only_if_banned: Do nothing if the user is not banned
:type only_if_banned: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success.
:rtype: :obj:`base.Boolean`
"""
return await self.bot.unban_chat_member(self.id, user_id=user_id)
return await self.bot.unban_chat_member(
chat_id=self.id,
user_id=user_id,
only_if_banned=only_if_banned,
)
async def restrict(self, user_id: base.Integer,
permissions: typing.Optional[ChatPermissions] = None,
until_date: typing.Union[base.Integer, datetime.datetime, datetime.timedelta, None] = None,
can_send_messages: typing.Union[base.Boolean, None] = None,
can_send_media_messages: typing.Union[base.Boolean, None] = None,
can_send_other_messages: typing.Union[base.Boolean, None] = None,
can_add_web_page_previews: typing.Union[base.Boolean, None] = None) -> base.Boolean:
can_send_messages: typing.Optional[base.Boolean] = None,
can_send_media_messages: typing.Optional[base.Boolean] = None,
can_send_other_messages: typing.Optional[base.Boolean] = None,
can_add_web_page_previews: typing.Optional[base.Boolean] = None) -> base.Boolean:
"""
Use this method to restrict a user in a supergroup.
The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights.
@ -240,18 +259,18 @@ class Chat(base.TelegramObject):
:param permissions: New user permissions
:type permissions: :obj:`ChatPermissions`
:param until_date: Date when restrictions will be lifted for the user, unix time.
:type until_date: :obj:`typing.Union[base.Integer, None]`
:type until_date: :obj:`typing.Optional[base.Integer]`
:param can_send_messages: Pass True, if the user can send text messages, contacts, locations and venues
:type can_send_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_send_messages: :obj:`typing.Optional[base.Boolean]`
:param can_send_media_messages: Pass True, if the user can send audios, documents, photos, videos,
video notes and voice notes, implies can_send_messages
:type can_send_media_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_send_media_messages: :obj:`typing.Optional[base.Boolean]`
:param can_send_other_messages: Pass True, if the user can send animations, games, stickers and
use inline bots, implies can_send_media_messages
:type can_send_other_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_send_other_messages: :obj:`typing.Optional[base.Boolean]`
:param can_add_web_page_previews: Pass True, if the user may add web page previews to their messages,
implies can_send_media_messages
:type can_add_web_page_previews: :obj:`typing.Union[base.Boolean, None]`
:type can_add_web_page_previews: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success.
:rtype: :obj:`base.Boolean`
"""
@ -264,14 +283,14 @@ class Chat(base.TelegramObject):
can_add_web_page_previews=can_add_web_page_previews)
async def promote(self, user_id: base.Integer,
can_change_info: typing.Union[base.Boolean, None] = None,
can_post_messages: typing.Union[base.Boolean, None] = None,
can_edit_messages: typing.Union[base.Boolean, None] = None,
can_delete_messages: typing.Union[base.Boolean, None] = None,
can_invite_users: typing.Union[base.Boolean, None] = None,
can_restrict_members: typing.Union[base.Boolean, None] = None,
can_pin_messages: typing.Union[base.Boolean, None] = None,
can_promote_members: typing.Union[base.Boolean, None] = None) -> base.Boolean:
can_change_info: typing.Optional[base.Boolean] = None,
can_post_messages: typing.Optional[base.Boolean] = None,
can_edit_messages: typing.Optional[base.Boolean] = None,
can_delete_messages: typing.Optional[base.Boolean] = None,
can_invite_users: typing.Optional[base.Boolean] = None,
can_restrict_members: typing.Optional[base.Boolean] = None,
can_pin_messages: typing.Optional[base.Boolean] = None,
can_promote_members: typing.Optional[base.Boolean] = None) -> base.Boolean:
"""
Use this method to promote or demote a user in a supergroup or a channel.
The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
@ -282,23 +301,23 @@ class Chat(base.TelegramObject):
:param user_id: Unique identifier of the target user
:type user_id: :obj:`base.Integer`
:param can_change_info: Pass True, if the administrator can change chat title, photo and other settings
:type can_change_info: :obj:`typing.Union[base.Boolean, None]`
:type can_change_info: :obj:`typing.Optional[base.Boolean]`
:param can_post_messages: Pass True, if the administrator can create channel posts, channels only
:type can_post_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_post_messages: :obj:`typing.Optional[base.Boolean]`
:param can_edit_messages: Pass True, if the administrator can edit messages of other users, channels only
:type can_edit_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_edit_messages: :obj:`typing.Optional[base.Boolean]`
:param can_delete_messages: Pass True, if the administrator can delete messages of other users
:type can_delete_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_delete_messages: :obj:`typing.Optional[base.Boolean]`
:param can_invite_users: Pass True, if the administrator can invite new users to the chat
:type can_invite_users: :obj:`typing.Union[base.Boolean, None]`
:type can_invite_users: :obj:`typing.Optional[base.Boolean]`
:param can_restrict_members: Pass True, if the administrator can restrict, ban or unban chat members
:type can_restrict_members: :obj:`typing.Union[base.Boolean, None]`
:type can_restrict_members: :obj:`typing.Optional[base.Boolean]`
:param can_pin_messages: Pass True, if the administrator can pin messages, supergroups only
:type can_pin_messages: :obj:`typing.Union[base.Boolean, None]`
:type can_pin_messages: :obj:`typing.Optional[base.Boolean]`
:param can_promote_members: Pass True, if the administrator can add new administrators
with a subset of his own privileges or demote administrators that he has promoted,
directly or indirectly (promoted by administrators that were appointed by him)
:type can_promote_members: :obj:`typing.Union[base.Boolean, None]`
:type can_promote_members: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success.
:rtype: :obj:`base.Boolean`
"""
@ -338,36 +357,73 @@ class Chat(base.TelegramObject):
:param custom_title: New custom title for the administrator; 0-16 characters, emoji are not allowed
:return: True on success.
"""
return await self.bot.set_chat_administrator_custom_title(chat_id=self.id, user_id=user_id, custom_title=custom_title)
return await self.bot.set_chat_administrator_custom_title(chat_id=self.id, user_id=user_id,
custom_title=custom_title)
async def pin_message(self, message_id: base.Integer, disable_notification: base.Boolean = False) -> base.Boolean:
async def pin_message(self,
message_id: base.Integer,
disable_notification: typing.Optional[base.Boolean] = False,
) -> base.Boolean:
"""
Use this method to pin a message in a supergroup.
The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
Use this method to add a message to the list of pinned messages in a chat.
If the chat is not a private chat, the bot must be an administrator in the
chat for this to work and must have the 'can_pin_messages' admin right in a
supergroup or 'can_edit_messages' admin right in a channel. Returns True on
success.
Source: https://core.telegram.org/bots/api#pinchatmessage
:param message_id: Identifier of a message to pin
:type message_id: :obj:`base.Integer`
:param disable_notification: Pass True, if it is not necessary to send a notification to
all group members about the new pinned message
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
:return: Returns True on success.
:param disable_notification: Pass True, if it is not necessary to send a
notification to all group members about the new pinned message
:type disable_notification: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success
:rtype: :obj:`base.Boolean`
"""
return await self.bot.pin_chat_message(self.id, message_id, disable_notification)
async def unpin_message(self) -> base.Boolean:
async def unpin_message(self,
message_id: typing.Optional[base.Integer] = None,
) -> base.Boolean:
"""
Use this method to unpin a message in a supergroup chat.
The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
Use this method to remove a message from the list of pinned messages in a
chat. If the chat is not a private chat, the bot must be an administrator in
the chat for this to work and must have the 'can_pin_messages' admin right in
a supergroup or 'can_edit_messages' admin right in a channel. Returns True on
success.
Source: https://core.telegram.org/bots/api#unpinchatmessage
:return: Returns True on success.
:param message_id: Identifier of a message to unpin. If not specified, the
most recent pinned message (by sending date) will be unpinned.
:type message_id: :obj:`typing.Optional[base.Integer]`
:return: Returns True on success
:rtype: :obj:`base.Boolean`
"""
return await self.bot.unpin_chat_message(self.id)
return await self.bot.unpin_chat_message(
chat_id=self.id,
message_id=message_id,
)
async def unpin_all_messages(self):
"""
Use this method to clear the list of pinned messages in a chat. If the chat
is not a private chat, the bot must be an administrator in the chat for this
to work and must have the 'can_pin_messages' admin right in a supergroup or
'can_edit_messages' admin right in a channel. Returns True on success.
Source: https://core.telegram.org/bots/api#unpinallchatmessages
:return: Returns True on success
:rtype: :obj:`base.Boolean`
"""
return await self.bot.unpin_all_chat_messages(
chat_id=self.id,
)
async def leave(self) -> base.Boolean:
"""

View file

@ -0,0 +1,16 @@
from . import base
from . import fields
from .location import Location
class ChatLocation(base.TelegramObject):
"""
Represents a location to which a chat is connected.
https://core.telegram.org/bots/api#chatlocation
"""
location: Location = fields.Field()
address: base.String = fields.Field()
def __init__(self, location: Location, address: base.String):
super().__init__(location=location, address=address)

View file

@ -1,6 +1,4 @@
import datetime
import warnings
from typing import Optional
from . import base
from . import fields
@ -17,6 +15,7 @@ class ChatMember(base.TelegramObject):
user: User = fields.Field(base=User)
status: base.String = fields.Field()
custom_title: base.String = fields.Field()
is_anonymous: base.Boolean = fields.Field()
until_date: datetime.datetime = fields.DateTimeField()
can_be_edited: base.Boolean = fields.Field()
can_change_info: base.Boolean = fields.Field()

View file

@ -17,3 +17,5 @@ class DiceEmoji:
DICE = '🎲'
DART = '🎯'
BASKETBALL = '🏀'
FOOTBALL = ''
SLOT_MACHINE = '🎰'

View file

@ -23,11 +23,11 @@ class InlineQuery(base.TelegramObject):
async def answer(self,
results: typing.List[InlineQueryResult],
cache_time: typing.Union[base.Integer, None] = None,
is_personal: typing.Union[base.Boolean, None] = None,
next_offset: typing.Union[base.String, None] = None,
switch_pm_text: typing.Union[base.String, None] = None,
switch_pm_parameter: typing.Union[base.String, None] = None):
cache_time: typing.Optional[base.Integer] = None,
is_personal: typing.Optional[base.Boolean] = None,
next_offset: typing.Optional[base.String] = None,
switch_pm_text: typing.Optional[base.String] = None,
switch_pm_parameter: typing.Optional[base.String] = None):
"""
Use this method to send answers to an inline query.
No more than 50 results per query are allowed.
@ -38,22 +38,22 @@ class InlineQuery(base.TelegramObject):
:type results: :obj:`typing.List[types.InlineQueryResult]`
:param cache_time: The maximum amount of time in seconds that the result of the
inline query may be cached on the server. Defaults to 300.
:type cache_time: :obj:`typing.Union[base.Integer, None]`
:type cache_time: :obj:`typing.Optional[base.Integer]`
:param is_personal: Pass True, if results may be cached on the server side only
for the user that sent the query. By default, results may be returned to any user who sends the same query
:type is_personal: :obj:`typing.Union[base.Boolean, None]`
:type is_personal: :obj:`typing.Optional[base.Boolean]`
:param next_offset: Pass the offset that a client should send in the
next query with the same text to receive more results.
Pass an empty string if there are no more results or if you dont support pagination.
Offset length cant exceed 64 bytes.
:type next_offset: :obj:`typing.Union[base.String, None]`
:type next_offset: :obj:`typing.Optional[base.String]`
:param switch_pm_text: If passed, clients will display a button with specified text that
switches the user to a private chat with the bot and sends the bot a start message
with the parameter switch_pm_parameter
:type switch_pm_text: :obj:`typing.Union[base.String, None]`
:type switch_pm_text: :obj:`typing.Optional[base.String]`
:param switch_pm_parameter: Deep-linking parameter for the /start message sent to the bot when
user presses the switch button. 1-64 characters, only A-Z, a-z, 0-9, _ and - are allowed.
:type switch_pm_parameter: :obj:`typing.Union[base.String, None]`
:type switch_pm_parameter: :obj:`typing.Optional[base.String]`
:return: On success, True is returned
:rtype: :obj:`base.Boolean`
"""

View file

@ -4,6 +4,7 @@ from . import base
from . import fields
from .inline_keyboard import InlineKeyboardMarkup
from .input_message_content import InputMessageContent
from .message_entity import MessageEntity
class InlineQueryResult(base.TelegramObject):
@ -83,23 +84,29 @@ class InlineQueryResultPhoto(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
photo_url: base.String,
thumb_url: base.String,
photo_width: typing.Optional[base.Integer] = None,
photo_height: typing.Optional[base.Integer] = None,
title: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultPhoto, self).__init__(id=id, photo_url=photo_url, thumb_url=thumb_url,
photo_width=photo_width, photo_height=photo_height, title=title,
description=description, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
photo_url: base.String,
thumb_url: base.String,
photo_width: typing.Optional[base.Integer] = None,
photo_height: typing.Optional[base.Integer] = None,
title: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, photo_url=photo_url, thumb_url=thumb_url,
photo_width=photo_width, photo_height=photo_height, title=title,
description=description, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultGif(InlineQueryResult):
@ -123,23 +130,29 @@ class InlineQueryResultGif(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
gif_url: base.String,
gif_width: typing.Optional[base.Integer] = None,
gif_height: typing.Optional[base.Integer] = None,
gif_duration: typing.Optional[base.Integer] = None,
thumb_url: typing.Optional[base.String] = None,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultGif, self).__init__(id=id, gif_url=gif_url, gif_width=gif_width,
gif_height=gif_height, gif_duration=gif_duration,
thumb_url=thumb_url, title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
gif_url: base.String,
gif_width: typing.Optional[base.Integer] = None,
gif_height: typing.Optional[base.Integer] = None,
gif_duration: typing.Optional[base.Integer] = None,
thumb_url: typing.Optional[base.String] = None,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, gif_url=gif_url, gif_width=gif_width, gif_height=gif_height,
gif_duration=gif_duration, thumb_url=thumb_url, title=title,
caption=caption, parse_mode=parse_mode, reply_markup=reply_markup,
caption_entities=caption_entities,
input_message_content=input_message_content,
)
class InlineQueryResultMpeg4Gif(InlineQueryResult):
@ -163,23 +176,30 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
mpeg4_url: base.String,
thumb_url: base.String,
mpeg4_width: typing.Optional[base.Integer] = None,
mpeg4_height: typing.Optional[base.Integer] = None,
mpeg4_duration: typing.Optional[base.Integer] = None,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultMpeg4Gif, self).__init__(id=id, mpeg4_url=mpeg4_url, mpeg4_width=mpeg4_width,
mpeg4_height=mpeg4_height, mpeg4_duration=mpeg4_duration,
thumb_url=thumb_url, title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
mpeg4_url: base.String,
thumb_url: base.String,
mpeg4_width: typing.Optional[base.Integer] = None,
mpeg4_height: typing.Optional[base.Integer] = None,
mpeg4_duration: typing.Optional[base.Integer] = None,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, mpeg4_url=mpeg4_url, mpeg4_width=mpeg4_width,
mpeg4_height=mpeg4_height, mpeg4_duration=mpeg4_duration,
thumb_url=thumb_url, title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
caption_entities=caption_entities,
input_message_content=input_message_content,
)
class InlineQueryResultVideo(InlineQueryResult):
@ -207,26 +227,32 @@ class InlineQueryResultVideo(InlineQueryResult):
description: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
video_url: base.String,
mime_type: base.String,
thumb_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
video_width: typing.Optional[base.Integer] = None,
video_height: typing.Optional[base.Integer] = None,
video_duration: typing.Optional[base.Integer] = None,
description: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultVideo, self).__init__(id=id, video_url=video_url, mime_type=mime_type,
thumb_url=thumb_url, title=title, caption=caption,
video_width=video_width, video_height=video_height,
video_duration=video_duration, description=description,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
video_url: base.String,
mime_type: base.String,
thumb_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
video_width: typing.Optional[base.Integer] = None,
video_height: typing.Optional[base.Integer] = None,
video_duration: typing.Optional[base.Integer] = None,
description: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, video_url=video_url, mime_type=mime_type, thumb_url=thumb_url,
title=title, caption=caption, video_width=video_width,
video_height=video_height, video_duration=video_duration,
description=description, parse_mode=parse_mode,
reply_markup=reply_markup, caption_entities=caption_entities,
input_message_content=input_message_content,
)
class InlineQueryResultAudio(InlineQueryResult):
@ -248,21 +274,27 @@ class InlineQueryResultAudio(InlineQueryResult):
audio_duration: base.Integer = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
audio_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
performer: typing.Optional[base.String] = None,
audio_duration: typing.Optional[base.Integer] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultAudio, self).__init__(id=id, audio_url=audio_url, title=title,
caption=caption, parse_mode=parse_mode,
performer=performer, audio_duration=audio_duration,
reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
audio_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
performer: typing.Optional[base.String] = None,
audio_duration: typing.Optional[base.Integer] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, audio_url=audio_url, title=title,
caption=caption, parse_mode=parse_mode,
performer=performer, audio_duration=audio_duration,
reply_markup=reply_markup, caption_entities=caption_entities,
input_message_content=input_message_content,
)
class InlineQueryResultVoice(InlineQueryResult):
@ -285,19 +317,25 @@ class InlineQueryResultVoice(InlineQueryResult):
voice_duration: base.Integer = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
voice_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
voice_duration: typing.Optional[base.Integer] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultVoice, self).__init__(id=id, voice_url=voice_url, title=title,
caption=caption, voice_duration=voice_duration,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
voice_url: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
voice_duration: typing.Optional[base.Integer] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, voice_url=voice_url, title=title, caption=caption,
voice_duration=voice_duration, parse_mode=parse_mode,
reply_markup=reply_markup, caption_entities=caption_entities,
input_message_content=input_message_content,
)
class InlineQueryResultDocument(InlineQueryResult):
@ -323,25 +361,31 @@ class InlineQueryResultDocument(InlineQueryResult):
thumb_width: base.Integer = fields.Field()
thumb_height: base.Integer = fields.Field()
def __init__(self, *,
id: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
document_url: typing.Optional[base.String] = None,
mime_type: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
thumb_url: typing.Optional[base.String] = None,
thumb_width: typing.Optional[base.Integer] = None,
thumb_height: typing.Optional[base.Integer] = None):
super(InlineQueryResultDocument, self).__init__(id=id, title=title, caption=caption,
document_url=document_url, mime_type=mime_type,
description=description, reply_markup=reply_markup,
input_message_content=input_message_content,
thumb_url=thumb_url, thumb_width=thumb_width,
thumb_height=thumb_height, parse_mode=parse_mode)
def __init__(
self,
*,
id: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
document_url: typing.Optional[base.String] = None,
mime_type: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
thumb_url: typing.Optional[base.String] = None,
thumb_width: typing.Optional[base.Integer] = None,
thumb_height: typing.Optional[base.Integer] = None,
):
super().__init__(
id=id, title=title, caption=caption, parse_mode=parse_mode,
caption_entities=caption_entities, document_url=document_url,
mime_type=mime_type, description=description, reply_markup=reply_markup,
input_message_content=input_message_content,
thumb_url=thumb_url, thumb_width=thumb_width,
thumb_height=thumb_height,
)
class InlineQueryResultLocation(InlineQueryResult):
@ -352,16 +396,16 @@ class InlineQueryResultLocation(InlineQueryResult):
Alternatively, you can use input_message_content to send a message with the specified content
instead of the location.
Note: This will only work in Telegram versions released after 9 April, 2016.
Older clients will ignore them.
https://core.telegram.org/bots/api#inlinequeryresultlocation
"""
type: base.String = fields.Field(alias='type', default='location')
latitude: base.Float = fields.Field()
longitude: base.Float = fields.Field()
title: base.String = fields.Field()
horizontal_accuracy: typing.Optional[base.Float] = fields.Field()
live_period: base.Integer = fields.Field()
heading: typing.Optional[base.Integer] = fields.Field()
proximity_alert_radius: typing.Optional[base.Integer] = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
thumb_url: base.String = fields.Field()
thumb_width: base.Integer = fields.Field()
@ -372,18 +416,31 @@ class InlineQueryResultLocation(InlineQueryResult):
latitude: base.Float,
longitude: base.Float,
title: base.String,
horizontal_accuracy: typing.Optional[base.Float] = None,
live_period: typing.Optional[base.Integer] = None,
heading: typing.Optional[base.Integer] = None,
proximity_alert_radius: typing.Optional[base.Integer] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
thumb_url: typing.Optional[base.String] = None,
thumb_width: typing.Optional[base.Integer] = None,
thumb_height: typing.Optional[base.Integer] = None):
super(InlineQueryResultLocation, self).__init__(id=id, latitude=latitude, longitude=longitude,
title=title, live_period=live_period,
reply_markup=reply_markup,
input_message_content=input_message_content,
thumb_url=thumb_url, thumb_width=thumb_width,
thumb_height=thumb_height)
thumb_height: typing.Optional[base.Integer] = None,
):
super().__init__(
id=id,
latitude=latitude,
longitude=longitude,
title=title,
horizontal_accuracy=horizontal_accuracy,
live_period=live_period,
heading=heading,
proximity_alert_radius=proximity_alert_radius,
reply_markup=reply_markup,
input_message_content=input_message_content,
thumb_url=thumb_url,
thumb_width=thumb_width,
thumb_height=thumb_height
)
class InlineQueryResultVenue(InlineQueryResult):
@ -404,31 +461,40 @@ class InlineQueryResultVenue(InlineQueryResult):
title: base.String = fields.Field()
address: base.String = fields.Field()
foursquare_id: base.String = fields.Field()
foursquare_type: base.String = fields.Field()
google_place_id: base.String = fields.Field()
google_place_type: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
thumb_url: base.String = fields.Field()
thumb_width: base.Integer = fields.Field()
thumb_height: base.Integer = fields.Field()
foursquare_type: base.String = fields.Field()
def __init__(self, *,
id: base.String,
latitude: base.Float,
longitude: base.Float,
title: base.String,
address: base.String,
foursquare_id: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
thumb_url: typing.Optional[base.String] = None,
thumb_width: typing.Optional[base.Integer] = None,
thumb_height: typing.Optional[base.Integer] = None,
foursquare_type: typing.Optional[base.String] = None):
super(InlineQueryResultVenue, self).__init__(id=id, latitude=latitude, longitude=longitude,
title=title, address=address, foursquare_id=foursquare_id,
reply_markup=reply_markup,
input_message_content=input_message_content, thumb_url=thumb_url,
thumb_width=thumb_width, thumb_height=thumb_height,
foursquare_type=foursquare_type)
def __init__(
self,
*,
id: base.String,
latitude: base.Float,
longitude: base.Float,
title: base.String,
address: base.String,
foursquare_id: typing.Optional[base.String] = None,
foursquare_type: typing.Optional[base.String] = None,
google_place_id: typing.Optional[base.String] = None,
google_place_type: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
thumb_url: typing.Optional[base.String] = None,
thumb_width: typing.Optional[base.Integer] = None,
thumb_height: typing.Optional[base.Integer] = None,
):
super().__init__(
id=id, latitude=latitude, longitude=longitude, title=title,
address=address, foursquare_id=foursquare_id,
foursquare_type=foursquare_type, google_place_id=google_place_id,
google_place_type=google_place_type, reply_markup=reply_markup,
input_message_content=input_message_content, thumb_url=thumb_url,
thumb_width=thumb_width, thumb_height=thumb_height,
)
class InlineQueryResultContact(InlineQueryResult):
@ -510,19 +576,24 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
photo_file_id: base.String,
title: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedPhoto, self).__init__(id=id, photo_file_id=photo_file_id, title=title,
description=description, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
photo_file_id: base.String,
title: typing.Optional[base.String] = None,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, photo_file_id=photo_file_id, title=title, description=description,
caption=caption, parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultCachedGif(InlineQueryResult):
@ -541,18 +612,23 @@ class InlineQueryResultCachedGif(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
gif_file_id: base.String,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedGif, self).__init__(id=id, gif_file_id=gif_file_id,
title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
gif_file_id: base.String,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, gif_file_id=gif_file_id, title=title, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
@ -571,18 +647,23 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
mpeg4_file_id: base.String,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedMpeg4Gif, self).__init__(id=id, mpeg4_file_id=mpeg4_file_id,
title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
mpeg4_file_id: base.String,
title: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, mpeg4_file_id=mpeg4_file_id, title=title, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultCachedSticker(InlineQueryResult):
@ -631,20 +712,25 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
title: base.String,
document_file_id: base.String,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedDocument, self).__init__(id=id, title=title,
document_file_id=document_file_id,
description=description, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
title: base.String,
document_file_id: base.String,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, title=title, document_file_id=document_file_id,
description=description, caption=caption, parse_mode=parse_mode,
caption_entities=caption_entities, reply_markup=reply_markup,
input_message_content=input_message_content,
)
class InlineQueryResultCachedVideo(InlineQueryResult):
@ -664,19 +750,24 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
video_file_id: base.String,
title: base.String,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedVideo, self).__init__(id=id, video_file_id=video_file_id, title=title,
description=description, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
video_file_id: base.String,
title: base.String,
description: typing.Optional[base.String] = None,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, video_file_id=video_file_id, title=title, description=description,
caption=caption, parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultCachedVoice(InlineQueryResult):
@ -697,18 +788,23 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
voice_file_id: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedVoice, self).__init__(id=id, voice_file_id=voice_file_id,
title=title, caption=caption,
parse_mode=parse_mode, reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
voice_file_id: base.String,
title: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, voice_file_id=voice_file_id, title=title, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)
class InlineQueryResultCachedAudio(InlineQueryResult):
@ -729,14 +825,19 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
caption: base.String = fields.Field()
input_message_content: InputMessageContent = fields.Field(base=InputMessageContent)
def __init__(self, *,
id: base.String,
audio_file_id: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None):
super(InlineQueryResultCachedAudio, self).__init__(id=id, audio_file_id=audio_file_id,
caption=caption, parse_mode=parse_mode,
reply_markup=reply_markup,
input_message_content=input_message_content)
def __init__(
self,
*,
id: base.String,
audio_file_id: base.String,
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
reply_markup: typing.Optional[InlineKeyboardMarkup] = None,
input_message_content: typing.Optional[InputMessageContent] = None,
):
super().__init__(
id=id, audio_file_id=audio_file_id, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
reply_markup=reply_markup, input_message_content=input_message_content,
)

View file

@ -5,6 +5,7 @@ import typing
from . import base
from . import fields
from .input_file import InputFile
from .message_entity import MessageEntity
ATTACHMENT_PREFIX = 'attach://'
@ -106,28 +107,48 @@ class InputMediaAnimation(InputMedia):
height: base.Integer = fields.Field()
duration: base.Integer = fields.Field()
def __init__(self, media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None,
parse_mode: base.String = None, **kwargs):
super(InputMediaAnimation, self).__init__(type='animation', media=media, thumb=thumb, caption=caption,
width=width, height=height, duration=duration,
parse_mode=parse_mode, conf=kwargs)
def __init__(
self,
media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
width: base.Integer = None,
height: base.Integer = None,
duration: base.Integer = None,
parse_mode: base.String = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
**kwargs,
):
super().__init__(
type='animation', media=media, thumb=thumb, caption=caption, width=width,
height=height, duration=duration, parse_mode=parse_mode,
caption_entities=caption_entities, conf=kwargs,
)
class InputMediaDocument(InputMedia):
"""
Represents a photo to be sent.
Represents a general file to be sent.
https://core.telegram.org/bots/api#inputmediadocument
"""
def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None, parse_mode: base.String = None, **kwargs):
super(InputMediaDocument, self).__init__(type='document', media=media, thumb=thumb,
caption=caption, parse_mode=parse_mode,
conf=kwargs)
def __init__(
self,
media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String, None] = None,
caption: base.String = None,
parse_mode: base.String = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
disable_content_type_detection: typing.Optional[base.Boolean] = None,
**kwargs,
):
super().__init__(
type='document', media=media, thumb=thumb, caption=caption,
parse_mode=parse_mode, caption_entities=caption_entities,
disable_content_type_detection=disable_content_type_detection,
conf=kwargs,
)
class InputMediaAudio(InputMedia):
@ -141,17 +162,23 @@ class InputMediaAudio(InputMedia):
performer: base.String = fields.Field()
title: base.String = fields.Field()
def __init__(self, media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
duration: base.Integer = None,
performer: base.String = None,
title: base.String = None,
parse_mode: base.String = None, **kwargs):
super(InputMediaAudio, self).__init__(type='audio', media=media, thumb=thumb,
caption=caption, duration=duration,
performer=performer, title=title,
parse_mode=parse_mode, conf=kwargs)
def __init__(
self,
media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
duration: base.Integer = None,
performer: base.String = None,
title: base.String = None,
parse_mode: base.String = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
**kwargs,
):
super().__init__(
type='audio', media=media, thumb=thumb, caption=caption,
duration=duration, performer=performer, title=title,
parse_mode=parse_mode, caption_entities=caption_entities, conf=kwargs,
)
class InputMediaPhoto(InputMedia):
@ -161,11 +188,18 @@ class InputMediaPhoto(InputMedia):
https://core.telegram.org/bots/api#inputmediaphoto
"""
def __init__(self, media: base.InputFile, thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None, parse_mode: base.String = None, **kwargs):
super(InputMediaPhoto, self).__init__(type='photo', media=media, thumb=thumb,
caption=caption, parse_mode=parse_mode,
conf=kwargs)
def __init__(
self,
media: base.InputFile,
caption: base.String = None,
parse_mode: base.String = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
**kwargs,
):
super().__init__(
type='photo', media=media, caption=caption, parse_mode=parse_mode,
caption_entities=caption_entities, conf=kwargs,
)
class InputMediaVideo(InputMedia):
@ -179,16 +213,25 @@ class InputMediaVideo(InputMedia):
duration: base.Integer = fields.Field()
supports_streaming: base.Boolean = fields.Field()
def __init__(self, media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
width: base.Integer = None, height: base.Integer = None, duration: base.Integer = None,
parse_mode: base.String = None,
supports_streaming: base.Boolean = None, **kwargs):
super(InputMediaVideo, self).__init__(type='video', media=media, thumb=thumb, caption=caption,
width=width, height=height, duration=duration,
parse_mode=parse_mode,
supports_streaming=supports_streaming, conf=kwargs)
def __init__(
self,
media: base.InputFile,
thumb: typing.Union[base.InputFile, base.String] = None,
caption: base.String = None,
width: base.Integer = None,
height: base.Integer = None,
duration: base.Integer = None,
parse_mode: base.String = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
supports_streaming: base.Boolean = None,
**kwargs,
):
super().__init__(
type='video', media=media, thumb=thumb, caption=caption,
width=width, height=height, duration=duration,
parse_mode=parse_mode, caption_entities=caption_entities,
supports_streaming=supports_streaming, conf=kwargs
)
class MediaGroup(base.TelegramObject):

View file

@ -2,6 +2,7 @@ import typing
from . import base
from . import fields
from .message_entity import MessageEntity
class InputMessageContent(base.TelegramObject):
@ -40,17 +41,31 @@ class InputLocationMessageContent(InputMessageContent):
"""
Represents the content of a location message to be sent as the result of an inline query.
Note: This will only work in Telegram versions released after 9 April, 2016.
Older clients will ignore them.
https://core.telegram.org/bots/api#inputlocationmessagecontent
"""
latitude: base.Float = fields.Field()
longitude: base.Float = fields.Field()
horizontal_accuracy: typing.Optional[base.Float] = fields.Field()
live_period: typing.Optional[base.Integer] = fields.Field()
heading: typing.Optional[base.Integer] = fields.Field()
proximity_alert_radius: typing.Optional[base.Integer] = fields.Field()
def __init__(self, latitude: base.Float,
longitude: base.Float):
super(InputLocationMessageContent, self).__init__(latitude=latitude, longitude=longitude)
def __init__(self,
latitude: base.Float,
longitude: base.Float,
horizontal_accuracy: typing.Optional[base.Float] = None,
live_period: typing.Optional[base.Integer] = None,
heading: typing.Optional[base.Integer] = None,
proximity_alert_radius: typing.Optional[base.Integer] = None,
):
super().__init__(
latitude=latitude,
longitude=longitude,
horizontal_accuracy=horizontal_accuracy,
live_period=live_period,
heading=heading,
proximity_alert_radius=proximity_alert_radius,
)
class InputTextMessageContent(InputMessageContent):
@ -69,14 +84,21 @@ class InputTextMessageContent(InputMessageContent):
except RuntimeError:
pass
def __init__(self, message_text: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
disable_web_page_preview: typing.Optional[base.Boolean] = None):
def __init__(
self,
message_text: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[MessageEntity]] = None,
disable_web_page_preview: typing.Optional[base.Boolean] = None,
):
if parse_mode is None:
parse_mode = self.safe_get_parse_mode()
super(InputTextMessageContent, self).__init__(message_text=message_text, parse_mode=parse_mode,
disable_web_page_preview=disable_web_page_preview)
super().__init__(
message_text=message_text, parse_mode=parse_mode,
caption_entities=caption_entities,
disable_web_page_preview=disable_web_page_preview,
)
class InputVenueMessageContent(InputMessageContent):
@ -93,11 +115,24 @@ class InputVenueMessageContent(InputMessageContent):
title: base.String = fields.Field()
address: base.String = fields.Field()
foursquare_id: base.String = fields.Field()
foursquare_type: base.String = fields.Field()
google_place_id: base.String = fields.Field()
google_place_type: base.String = fields.Field()
def __init__(self, latitude: typing.Optional[base.Float] = None,
longitude: typing.Optional[base.Float] = None,
title: typing.Optional[base.String] = None,
address: typing.Optional[base.String] = None,
foursquare_id: typing.Optional[base.String] = None):
super(InputVenueMessageContent, self).__init__(latitude=latitude, longitude=longitude, title=title,
address=address, foursquare_id=foursquare_id)
def __init__(
self,
latitude: typing.Optional[base.Float] = None,
longitude: typing.Optional[base.Float] = None,
title: typing.Optional[base.String] = None,
address: typing.Optional[base.String] = None,
foursquare_id: typing.Optional[base.String] = None,
foursquare_type: typing.Optional[base.String] = None,
google_place_id: typing.Optional[base.String] = None,
google_place_type: typing.Optional[base.String] = None,
):
super().__init__(
latitude=latitude, longitude=longitude, title=title,
address=address, foursquare_id=foursquare_id,
foursquare_type=foursquare_type, google_place_id=google_place_id,
google_place_type=google_place_type,
)

View file

@ -1,3 +1,5 @@
import typing
from . import base
from . import fields
@ -10,3 +12,7 @@ class Location(base.TelegramObject):
"""
longitude: base.Float = fields.Field()
latitude: base.Float = fields.Field()
horizontal_accuracy: typing.Optional[base.Float] = fields.Field()
live_period: typing.Optional[base.Integer] = fields.Field()
heading: typing.Optional[base.Integer] = fields.Field()
proximity_alert_radius: typing.Optional[base.Integer] = fields.Field()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
from . import base, fields
class MessageId(base.TelegramObject):
"""
This object represents a unique message identifier.
https://core.telegram.org/bots/api#messageid
"""
message_id: base.String = fields.Field()

View file

@ -0,0 +1,15 @@
from . import base
from . import fields
from .user import User
class ProximityAlertTriggered(base.TelegramObject):
"""
This object represents the content of a service message, sent whenever a user in
the chat triggers a proximity alert set by another user.
https://core.telegram.org/bots/api#proximityalerttriggered
"""
traveler: User = fields.Field()
watcher: User = fields.Field()
distance: base.Integer = fields.Field()

View file

@ -14,3 +14,5 @@ class Venue(base.TelegramObject):
address: base.String = fields.Field()
foursquare_id: base.String = fields.Field()
foursquare_type: base.String = fields.Field()
google_place_id: base.String = fields.Field()
google_place_type: base.String = fields.Field()

View file

@ -16,5 +16,6 @@ class Video(base.TelegramObject, mixins.Downloadable):
height: base.Integer = fields.Field()
duration: base.Integer = fields.Field()
thumb: PhotoSize = fields.Field(base=PhotoSize)
file_name: base.String = fields.Field()
mime_type: base.String = fields.Field()
file_size: base.Integer = fields.Field()

View file

@ -13,6 +13,7 @@ class WebhookInfo(base.TelegramObject):
url: base.String = fields.Field()
has_custom_certificate: base.Boolean = fields.Field()
pending_update_count: base.Integer = fields.Field()
ip_address: base.String = fields.Field()
last_error_date: base.Integer = fields.Field()
last_error_message: base.String = fields.Field()
max_connections: base.Integer = fields.Field()

View file

@ -354,7 +354,7 @@ class Executor:
self.dispatcher.stop_polling()
await self.dispatcher.storage.close()
await self.dispatcher.storage.wait_closed()
await self.dispatcher.bot.close()
await self.dispatcher.bot.session.close()
async def _startup_polling(self):
await self._welcome()

View file

@ -1,28 +1,8 @@
.. Autogenerated file at 2018-10-28 19:31:48.335963
=========================
Advanced executor example
=========================
!/usr/bin/env python3
**This example is outdated**
In this example used ArgumentParser for configuring Your bot.
Provided to start bot with webhook:
python advanced_executor_example.py \
--token TOKEN_HERE \
--host 0.0.0.0 \
--port 8084 \
--host-name example.com \
--webhook-port 443
Or long polling:
python advanced_executor_example.py --token TOKEN_HERE
So... In this example found small trouble:
can't get bot instance in handlers.
If you want to automatic change getting updates method use executor utils (from aiogram.utils.executor)
TODO: Move token to environment variables.
.. literalinclude:: ../../../examples/advanced_executor_example.py
:caption: advanced_executor_example.py
:language: python
:linenos:
:lines: 25-

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.593501
=================
Broadcast example
=================

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.558059
===================
Check user language
===================
@ -10,4 +8,3 @@ Babel is required.
:caption: check_user_language.py
:language: python
:linenos:
:lines: 5-

View file

@ -1,8 +1,7 @@
========
Echo bot
========
Very simple example of the bot which will sent text of the received messages to the sender
.. literalinclude:: ../../../examples/echo_bot.py
:caption: echo_bot.py
:language: python

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.595032
============================
Finite state machine example
============================

View file

@ -1,28 +1,8 @@
.. Autogenerated file at 2018-09-08 02:07:37.591007
============
I18n example
============
Internalize your bot
Step 1: extract texts
# pybabel extract i18n_example.py -o locales/mybot.pot
Step 2: create *.po files. For e.g. create en, ru, uk locales.
# echo {en,ru,uk} | xargs -n1 pybabel init -i locales/mybot.pot -d locales -D mybot -l
Step 3: translate texts
Step 4: compile translations
# pybabel compile -d locales -D mybot
Step 5: When you change the code of your bot you need to update po & mo files.
Step 5.1: regenerate pot file:
command from step 1
Step 5.2: update po files
# pybabel update -d locales -D mybot -i locales/mybot.pot
Step 5.3: update your translations
Step 5.4: compile mo files
command from step 4
.. literalinclude:: ../../../examples/i18n_example.py
:caption: i18n_example.py
:language: python
:linenos:
:lines: 22-

View file

@ -19,3 +19,4 @@ Examples
payments
broadcast_example
media_group
local_server

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.561907
==========
Inline bot
==========

View file

@ -0,0 +1,8 @@
============
Local server
============
.. literalinclude:: ../../../examples/local_server.py
:caption: local_server.py
:language: python
:linenos:

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.566615
===========
Media group
===========

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.560132
========================
Middleware and antiflood
========================

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.579017
========
Payments
========

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.555359
=================
Proxy and emojize
=================

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.568530
==============================
Regexp commands filter example
==============================

View file

@ -1,14 +1,8 @@
.. Autogenerated file at 2018-09-08 02:07:37.563878
=================
Throtling example
=================
Example for throttling manager.
You can use that for flood controlling.
==================
Throttling example
==================
.. literalinclude:: ../../../examples/throttling_example.py
:caption: throttling_example.py
:language: python
:linenos:
:lines: 7-

View file

@ -1,13 +1,8 @@
.. Autogenerated file at 2018-10-28 19:31:48.341172
===============
Webhook example
===============
Example outdated
.. literalinclude:: ../../../examples/webhook_example.py
:caption: webhook_example.py
:language: python
:linenos:
:lines: 5-

View file

@ -1,5 +1,3 @@
.. Autogenerated file at 2018-09-08 02:07:37.576034
===================
Webhook example old
===================

View file

@ -22,7 +22,7 @@ Welcome to aiogram's documentation!
:target: https://pypi.python.org/pypi/aiogram
:alt: Supported python versions
.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-4.9-blue.svg?style=flat-square&logo=telegram
.. image:: https://img.shields.io/badge/Telegram%20Bot%20API-5.0-blue.svg?style=flat-square&logo=telegram
:target: https://core.telegram.org/bots/api
:alt: Telegram Bot API

27
examples/local_server.py Normal file
View file

@ -0,0 +1,27 @@
import logging
from aiogram import Bot, Dispatcher, executor, types
from aiogram.bot.api import TelegramAPIServer
from aiogram.types import ContentType
API_TOKEN = 'BOT TOKEN HERE'
# Configure logging
logging.basicConfig(level=logging.INFO)
# Create private Bot API server endpoints wrapper
local_server = TelegramAPIServer.from_base('http://localhost')
# Initialize bot with using local server
bot = Bot(token=API_TOKEN, server=local_server)
# ... and dispatcher
dp = Dispatcher(bot)
@dp.message_handler(content_types=ContentType.ANY)
async def echo(message: types.Message):
await message.copy_to(message.chat.id)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)

View file

@ -1,3 +1,3 @@
aiohttp>=3.5.4,<4.0.0
Babel>=2.6.0
certifi>=2019.3.9
aiohttp>=3.7.2,<4.0.0
Babel>=2.8.0
certifi>=2020.6.20

View file

@ -57,12 +57,13 @@ setup(
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Topic :: Software Development :: Libraries :: Application Frameworks',
],
install_requires=[
'aiohttp>=3.5.4,<4.0.0',
'Babel>=2.6.0',
'certifi>=2019.3.9',
'aiohttp>=3.7.2,<4.0.0',
'Babel>=2.8.0',
'certifi>=2020.6.20',
],
extras_require={
'proxy': [

View file

@ -24,6 +24,22 @@ async def test_get_me(bot: Bot, event_loop):
assert result == user
async def test_log_out(bot: Bot, event_loop):
""" logOut method test """
async with FakeTelegram(message_data=True, loop=event_loop):
result = await bot.log_out()
assert result is True
async def test_close_bot(bot: Bot, event_loop):
""" close method test """
async with FakeTelegram(message_data=True, loop=event_loop):
result = await bot.close_bot()
assert result is True
async def test_send_message(bot: Bot, event_loop):
""" sendMessage method test """
from .types.dataset import MESSAGE