mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-27 08:50:41 +03:00
Warn on invoke and clean TelegramClient
This commit is contained in:
parent
3e151a1b7a
commit
d76b27058f
|
@ -2,6 +2,7 @@ import asyncio
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import platform
|
import platform
|
||||||
|
import warnings
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
from . import version, errors, utils
|
from . import version, errors, utils
|
||||||
|
@ -418,7 +419,10 @@ class TelegramBareClient:
|
||||||
raise ValueError('Number of retries reached 0')
|
raise ValueError('Number of retries reached 0')
|
||||||
|
|
||||||
# Let people use client.invoke(SomeRequest()) instead client(...)
|
# Let people use client.invoke(SomeRequest()) instead client(...)
|
||||||
invoke = __call__
|
async def invoke(self, *args, **kwargs):
|
||||||
|
warnings.warn('client.invoke(...) is deprecated, '
|
||||||
|
'use client(...) instead')
|
||||||
|
return await self(*args, **kwargs)
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,15 @@ import hashlib
|
||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
from collections import UserList
|
from collections import UserList
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
|
|
||||||
from .crypto import CdnDecrypter
|
from .crypto import CdnDecrypter
|
||||||
from .tl import TLObject
|
|
||||||
from .tl.custom import InputSizedFile
|
from .tl.custom import InputSizedFile
|
||||||
from .tl.functions.help import AcceptTermsOfServiceRequest
|
from .tl.functions.help import AcceptTermsOfServiceRequest
|
||||||
from .tl.functions.updates import GetDifferenceRequest
|
from .tl.functions.updates import GetDifferenceRequest
|
||||||
|
@ -39,14 +36,13 @@ except ImportError:
|
||||||
hachoir = None
|
hachoir = None
|
||||||
|
|
||||||
from . import TelegramBareClient
|
from . import TelegramBareClient
|
||||||
from . import helpers, utils, events
|
from . import helpers, events
|
||||||
from .errors import (
|
from .errors import (
|
||||||
RPCError, UnauthorizedError, PhoneCodeEmptyError, PhoneCodeExpiredError,
|
PhoneCodeEmptyError, PhoneCodeExpiredError,
|
||||||
PhoneCodeHashEmptyError, PhoneCodeInvalidError, LocationInvalidError,
|
PhoneCodeHashEmptyError, PhoneCodeInvalidError, LocationInvalidError,
|
||||||
SessionPasswordNeededError, FileMigrateError, PhoneNumberUnoccupiedError,
|
SessionPasswordNeededError, FileMigrateError, PhoneNumberUnoccupiedError,
|
||||||
PhoneNumberOccupiedError, UsernameNotOccupiedError
|
PhoneNumberOccupiedError
|
||||||
)
|
)
|
||||||
from .network import ConnectionTcpFull
|
|
||||||
from .tl.custom import Draft, Dialog
|
from .tl.custom import Draft, Dialog
|
||||||
from .tl.functions.account import (
|
from .tl.functions.account import (
|
||||||
GetPasswordRequest, UpdatePasswordSettingsRequest
|
GetPasswordRequest, UpdatePasswordSettingsRequest
|
||||||
|
@ -55,13 +51,10 @@ from .tl.functions.auth import (
|
||||||
CheckPasswordRequest, LogOutRequest, SendCodeRequest, SignInRequest,
|
CheckPasswordRequest, LogOutRequest, SendCodeRequest, SignInRequest,
|
||||||
SignUpRequest, ResendCodeRequest, ImportBotAuthorizationRequest
|
SignUpRequest, ResendCodeRequest, ImportBotAuthorizationRequest
|
||||||
)
|
)
|
||||||
from .tl.functions.contacts import (
|
|
||||||
GetContactsRequest, ResolveUsernameRequest
|
|
||||||
)
|
|
||||||
from .tl.functions.messages import (
|
from .tl.functions.messages import (
|
||||||
GetDialogsRequest, GetHistoryRequest, SendMediaRequest,
|
GetDialogsRequest, GetHistoryRequest, SendMediaRequest,
|
||||||
SendMessageRequest, GetChatsRequest, GetAllDraftsRequest,
|
SendMessageRequest, GetAllDraftsRequest,
|
||||||
CheckChatInviteRequest, ReadMentionsRequest, SendMultiMediaRequest,
|
ReadMentionsRequest, SendMultiMediaRequest,
|
||||||
UploadMediaRequest, EditMessageRequest, GetFullChatRequest,
|
UploadMediaRequest, EditMessageRequest, GetFullChatRequest,
|
||||||
ForwardMessagesRequest, SearchRequest
|
ForwardMessagesRequest, SearchRequest
|
||||||
)
|
)
|
||||||
|
@ -69,26 +62,22 @@ from .tl.functions.messages import (
|
||||||
from .tl.functions import channels
|
from .tl.functions import channels
|
||||||
from .tl.functions import messages
|
from .tl.functions import messages
|
||||||
|
|
||||||
from .tl.functions.users import (
|
|
||||||
GetUsersRequest
|
|
||||||
)
|
|
||||||
from .tl.functions.channels import (
|
from .tl.functions.channels import (
|
||||||
GetChannelsRequest, GetFullChannelRequest, GetParticipantsRequest
|
GetFullChannelRequest, GetParticipantsRequest
|
||||||
)
|
)
|
||||||
from .tl.types import (
|
from .tl.types import (
|
||||||
DocumentAttributeAudio, DocumentAttributeFilename,
|
DocumentAttributeAudio, DocumentAttributeFilename,
|
||||||
InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
|
InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
|
||||||
Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
|
Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
|
||||||
InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID,
|
UserProfilePhoto, ChatPhoto, UpdateMessageID,
|
||||||
UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage,
|
UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage,
|
||||||
PeerUser, InputPeerUser, InputPeerChat, InputPeerChannel, MessageEmpty,
|
PeerUser, InputPeerChat, InputPeerChannel, MessageEmpty,
|
||||||
ChatInvite, ChatInviteAlready, Photo, InputPeerSelf,
|
Photo, InputSingleMedia, InputMediaPhoto, InputPhoto, InputFile, InputFileBig,
|
||||||
InputSingleMedia, InputMediaPhoto, InputPhoto, InputFile, InputFileBig,
|
|
||||||
InputDocument, InputMediaDocument, Document, MessageEntityTextUrl,
|
InputDocument, InputMediaDocument, Document, MessageEntityTextUrl,
|
||||||
InputMessageEntityMentionName, DocumentAttributeVideo,
|
InputMessageEntityMentionName, DocumentAttributeVideo,
|
||||||
UpdateEditMessage, UpdateEditChannelMessage, UpdateShort, Updates,
|
UpdateEditMessage, UpdateEditChannelMessage, UpdateShort, Updates,
|
||||||
MessageMediaWebPage, ChannelParticipantsSearch, PhotoSize, PhotoCachedSize,
|
MessageMediaWebPage, ChannelParticipantsSearch, PhotoSize, PhotoCachedSize,
|
||||||
PhotoSizeEmpty, MessageService, ChatParticipants, User, WebPage,
|
PhotoSizeEmpty, MessageService, ChatParticipants, WebPage,
|
||||||
ChannelParticipantsBanned, ChannelParticipantsKicked,
|
ChannelParticipantsBanned, ChannelParticipantsKicked,
|
||||||
InputMessagesFilterEmpty, UpdatesCombined
|
InputMessagesFilterEmpty, UpdatesCombined
|
||||||
)
|
)
|
||||||
|
@ -99,123 +88,21 @@ from .utils import Default
|
||||||
from .extensions import markdown, html
|
from .extensions import markdown, html
|
||||||
|
|
||||||
__log__ = logging.getLogger(__name__)
|
__log__ = logging.getLogger(__name__)
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from . import utils
|
||||||
|
from .errors import RPCError
|
||||||
|
from .tl import TLObject
|
||||||
|
|
||||||
|
|
||||||
class TelegramClient(TelegramBareClient):
|
class TelegramClient(TelegramBareClient):
|
||||||
"""
|
"""
|
||||||
Initializes the Telegram client with the specified API ID and Hash.
|
Initializes the Telegram client with the specified API ID and Hash. This
|
||||||
|
is identical to the `telethon.telegram_bare_client.TelegramBareClient`
|
||||||
Args:
|
but it contains "friendly methods", so please refer to its documentation
|
||||||
session (`str` | `telethon.sessions.abstract.Session`, `None`):
|
to know what parameters you can use when creating a new instance.
|
||||||
The file name of the session file to be used if a string is
|
|
||||||
given (it may be a full path), or the Session instance to be
|
|
||||||
used otherwise. If it's ``None``, the session will not be saved,
|
|
||||||
and you should call :meth:`.log_out()` when you're done.
|
|
||||||
|
|
||||||
Note that if you pass a string it will be a file in the current
|
|
||||||
working directory, although you can also pass absolute paths.
|
|
||||||
|
|
||||||
The session file contains enough information for you to login
|
|
||||||
without re-sending the code, so if you have to enter the code
|
|
||||||
more than once, maybe you're changing the working directory,
|
|
||||||
renaming or removing the file, or using random names.
|
|
||||||
|
|
||||||
api_id (`int` | `str`):
|
|
||||||
The API ID you obtained from https://my.telegram.org.
|
|
||||||
|
|
||||||
api_hash (`str`):
|
|
||||||
The API ID you obtained from https://my.telegram.org.
|
|
||||||
|
|
||||||
connection (`telethon.network.connection.common.Connection`, optional):
|
|
||||||
The connection instance to be used when creating a new connection
|
|
||||||
to the servers. If it's a type, the `proxy` argument will be used.
|
|
||||||
|
|
||||||
Defaults to `telethon.network.connection.tcpfull.ConnectionTcpFull`.
|
|
||||||
|
|
||||||
use_ipv6 (`bool`, optional):
|
|
||||||
Whether to connect to the servers through IPv6 or not.
|
|
||||||
By default this is ``False`` as IPv6 support is not
|
|
||||||
too widespread yet.
|
|
||||||
|
|
||||||
proxy (`tuple` | `dict`, optional):
|
|
||||||
A tuple consisting of ``(socks.SOCKS5, 'host', port)``.
|
|
||||||
See https://github.com/Anorov/PySocks#usage-1 for more.
|
|
||||||
|
|
||||||
update_workers (`int`, optional):
|
|
||||||
If specified, represents how many extra threads should
|
|
||||||
be spawned to handle incoming updates, and updates will
|
|
||||||
be kept in memory until they are processed. Note that
|
|
||||||
you must set this to at least ``0`` if you want to be
|
|
||||||
able to process updates through :meth:`updates.poll()`.
|
|
||||||
|
|
||||||
timeout (`int` | `float` | `timedelta`, optional):
|
|
||||||
The timeout to be used when receiving responses from
|
|
||||||
the network. Defaults to 5 seconds.
|
|
||||||
|
|
||||||
spawn_read_thread (`bool`, optional):
|
|
||||||
Whether to use an extra background thread or not. Defaults
|
|
||||||
to ``True`` so receiving items from the network happens
|
|
||||||
instantly, as soon as they arrive. Can still be disabled
|
|
||||||
if you want to run the library without any additional thread.
|
|
||||||
|
|
||||||
report_errors (`bool`, optional):
|
|
||||||
Whether to report RPC errors or not. Defaults to ``True``,
|
|
||||||
see :ref:`api-status` for more information.
|
|
||||||
|
|
||||||
Kwargs:
|
|
||||||
Some extra parameters are required when establishing the first
|
|
||||||
connection. These are are (along with their default values):
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
device_model = platform.node()
|
|
||||||
system_version = platform.system()
|
|
||||||
app_version = TelegramClient.__version__
|
|
||||||
lang_code = 'en'
|
|
||||||
system_lang_code = lang_code
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# region Initialization
|
|
||||||
|
|
||||||
def __init__(self, session, api_id, api_hash,
|
|
||||||
*,
|
|
||||||
connection=ConnectionTcpFull,
|
|
||||||
use_ipv6=False,
|
|
||||||
proxy=None,
|
|
||||||
update_workers=None,
|
|
||||||
timeout=timedelta(seconds=10),
|
|
||||||
spawn_read_thread=True,
|
|
||||||
report_errors=True,
|
|
||||||
**kwargs):
|
|
||||||
super().__init__(
|
|
||||||
session, api_id, api_hash,
|
|
||||||
connection=connection,
|
|
||||||
use_ipv6=use_ipv6,
|
|
||||||
proxy=proxy,
|
|
||||||
update_workers=update_workers,
|
|
||||||
spawn_read_thread=spawn_read_thread,
|
|
||||||
timeout=timeout,
|
|
||||||
report_errors=report_errors,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
self._event_builders = []
|
|
||||||
self._events_pending_resolve = []
|
|
||||||
|
|
||||||
# Default parse mode
|
|
||||||
self._parse_mode = markdown
|
|
||||||
|
|
||||||
# Some fields to easy signing in. Let {phone: hash} be
|
|
||||||
# a dictionary because the user may change their mind.
|
|
||||||
self._phone_code_hash = {}
|
|
||||||
self._phone = None
|
|
||||||
self._tos = None
|
|
||||||
|
|
||||||
# Sometimes we need to know who we are, cache the self peer
|
|
||||||
self._self_input_peer = None
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region Telegram requests functions
|
# region Telegram requests functions
|
||||||
|
|
||||||
# region Authorization requests
|
# region Authorization requests
|
||||||
|
@ -540,34 +427,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
self._authorized = False
|
self._authorized = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_me(self, input_peer=False):
|
|
||||||
"""
|
|
||||||
Gets "me" (the self user) which is currently authenticated,
|
|
||||||
or None if the request fails (hence, not authenticated).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_peer (`bool`, optional):
|
|
||||||
Whether to return the :tl:`InputPeerUser` version or the normal
|
|
||||||
:tl:`User`. This can be useful if you just need to know the ID
|
|
||||||
of yourself.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Your own :tl:`User`.
|
|
||||||
"""
|
|
||||||
if input_peer and self._self_input_peer:
|
|
||||||
return self._self_input_peer
|
|
||||||
|
|
||||||
try:
|
|
||||||
me = self(GetUsersRequest([InputUserSelf()]))[0]
|
|
||||||
if not self._self_input_peer:
|
|
||||||
self._self_input_peer = utils.get_input_peer(
|
|
||||||
me, allow_self=False
|
|
||||||
)
|
|
||||||
|
|
||||||
return self._self_input_peer if input_peer else me
|
|
||||||
except UnauthorizedError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region Dialogs ("chats") requests
|
# region Dialogs ("chats") requests
|
||||||
|
@ -2648,182 +2507,6 @@ class TelegramClient(TelegramBareClient):
|
||||||
super()._set_connected_and_authorized()
|
super()._set_connected_and_authorized()
|
||||||
self._check_events_pending_resolve()
|
self._check_events_pending_resolve()
|
||||||
|
|
||||||
def get_entity(self, entity):
|
|
||||||
"""
|
|
||||||
Turns the given entity into a valid Telegram user or chat.
|
|
||||||
|
|
||||||
entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`):
|
|
||||||
The entity (or iterable of entities) to be transformed.
|
|
||||||
If it's a string which can be converted to an integer or starts
|
|
||||||
with '+' it will be resolved as if it were a phone number.
|
|
||||||
|
|
||||||
If it doesn't start with '+' or starts with a '@' it will be
|
|
||||||
be resolved from the username. If no exact match is returned,
|
|
||||||
an error will be raised.
|
|
||||||
|
|
||||||
If the entity is an integer or a Peer, its information will be
|
|
||||||
returned through a call to self.get_input_peer(entity).
|
|
||||||
|
|
||||||
If the entity is neither, and it's not a TLObject, an
|
|
||||||
error will be raised.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:tl:`User`, :tl:`Chat` or :tl:`Channel` corresponding to the
|
|
||||||
input entity. A list will be returned if more than one was given.
|
|
||||||
"""
|
|
||||||
single = not utils.is_list_like(entity)
|
|
||||||
if single:
|
|
||||||
entity = (entity,)
|
|
||||||
|
|
||||||
# Group input entities by string (resolve username),
|
|
||||||
# input users (get users), input chat (get chats) and
|
|
||||||
# input channels (get channels) to get the most entities
|
|
||||||
# in the less amount of calls possible.
|
|
||||||
inputs = [
|
|
||||||
x if isinstance(x, str) else self.get_input_entity(x)
|
|
||||||
for x in entity
|
|
||||||
]
|
|
||||||
users = [x for x in inputs
|
|
||||||
if isinstance(x, (InputPeerUser, InputPeerSelf))]
|
|
||||||
chats = [x.chat_id for x in inputs if isinstance(x, InputPeerChat)]
|
|
||||||
channels = [x for x in inputs if isinstance(x, InputPeerChannel)]
|
|
||||||
if users:
|
|
||||||
# GetUsersRequest has a limit of 200 per call
|
|
||||||
tmp = []
|
|
||||||
while users:
|
|
||||||
curr, users = users[:200], users[200:]
|
|
||||||
tmp.extend(self(GetUsersRequest(curr)))
|
|
||||||
users = tmp
|
|
||||||
if chats: # TODO Handle chats slice?
|
|
||||||
chats = self(GetChatsRequest(chats)).chats
|
|
||||||
if channels:
|
|
||||||
channels = self(GetChannelsRequest(channels)).chats
|
|
||||||
|
|
||||||
# Merge users, chats and channels into a single dictionary
|
|
||||||
id_entity = {
|
|
||||||
utils.get_peer_id(x): x
|
|
||||||
for x in itertools.chain(users, chats, channels)
|
|
||||||
}
|
|
||||||
|
|
||||||
# We could check saved usernames and put them into the users,
|
|
||||||
# chats and channels list from before. While this would reduce
|
|
||||||
# the amount of ResolveUsername calls, it would fail to catch
|
|
||||||
# username changes.
|
|
||||||
result = [
|
|
||||||
self._get_entity_from_string(x) if isinstance(x, str)
|
|
||||||
else (
|
|
||||||
id_entity[utils.get_peer_id(x)]
|
|
||||||
if not isinstance(x, InputPeerSelf)
|
|
||||||
else next(u for u in id_entity.values()
|
|
||||||
if isinstance(u, User) and u.is_self)
|
|
||||||
)
|
|
||||||
for x in inputs
|
|
||||||
]
|
|
||||||
return result[0] if single else result
|
|
||||||
|
|
||||||
def _get_entity_from_string(self, string):
|
|
||||||
"""
|
|
||||||
Gets a full entity from the given string, which may be a phone or
|
|
||||||
an username, and processes all the found entities on the session.
|
|
||||||
The string may also be a user link, or a channel/chat invite link.
|
|
||||||
|
|
||||||
This method has the side effect of adding the found users to the
|
|
||||||
session database, so it can be queried later without API calls,
|
|
||||||
if this option is enabled on the session.
|
|
||||||
|
|
||||||
Returns the found entity, or raises TypeError if not found.
|
|
||||||
"""
|
|
||||||
phone = utils.parse_phone(string)
|
|
||||||
if phone:
|
|
||||||
for user in self(GetContactsRequest(0)).users:
|
|
||||||
if user.phone == phone:
|
|
||||||
return user
|
|
||||||
else:
|
|
||||||
username, is_join_chat = utils.parse_username(string)
|
|
||||||
if is_join_chat:
|
|
||||||
invite = self(CheckChatInviteRequest(username))
|
|
||||||
if isinstance(invite, ChatInvite):
|
|
||||||
raise ValueError(
|
|
||||||
'Cannot get entity from a channel (or group) '
|
|
||||||
'that you are not part of. Join the group and retry'
|
|
||||||
)
|
|
||||||
elif isinstance(invite, ChatInviteAlready):
|
|
||||||
return invite.chat
|
|
||||||
elif username:
|
|
||||||
if username in ('me', 'self'):
|
|
||||||
return self.get_me()
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = self(ResolveUsernameRequest(username))
|
|
||||||
except UsernameNotOccupiedError as e:
|
|
||||||
raise ValueError('No user has "{}" as username'
|
|
||||||
.format(username)) from e
|
|
||||||
|
|
||||||
for entity in itertools.chain(result.users, result.chats):
|
|
||||||
if getattr(entity, 'username', None) or ''\
|
|
||||||
.lower() == username:
|
|
||||||
return entity
|
|
||||||
try:
|
|
||||||
# Nobody with this username, maybe it's an exact name/title
|
|
||||||
return self.get_entity(self.session.get_input_entity(string))
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise ValueError(
|
|
||||||
'Cannot find any entity corresponding to "{}"'.format(string)
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_input_entity(self, peer):
|
|
||||||
"""
|
|
||||||
Turns the given peer into its input entity version. Most requests
|
|
||||||
use this kind of InputUser, InputChat and so on, so this is the
|
|
||||||
most suitable call to make for those cases.
|
|
||||||
|
|
||||||
entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`):
|
|
||||||
The integer ID of an user or otherwise either of a
|
|
||||||
:tl:`PeerUser`, :tl:`PeerChat` or :tl:`PeerChannel`, for
|
|
||||||
which to get its ``Input*`` version.
|
|
||||||
|
|
||||||
If this ``Peer`` hasn't been seen before by the library, the top
|
|
||||||
dialogs will be loaded and their entities saved to the session
|
|
||||||
file (unless this feature was disabled explicitly).
|
|
||||||
|
|
||||||
If in the end the access hash required for the peer was not found,
|
|
||||||
a ValueError will be raised.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:tl:`InputPeerUser`, :tl:`InputPeerChat` or :tl:`InputPeerChannel`
|
|
||||||
or :tl:`InputPeerSelf` if the parameter is ``'me'`` or ``'self'``.
|
|
||||||
|
|
||||||
If you need to get the ID of yourself, you should use
|
|
||||||
`get_me` with ``input_peer=True``) instead.
|
|
||||||
"""
|
|
||||||
if peer in ('me', 'self'):
|
|
||||||
return InputPeerSelf()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# First try to get the entity from cache, otherwise figure it out
|
|
||||||
return self.session.get_input_entity(peer)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if isinstance(peer, str):
|
|
||||||
return utils.get_input_peer(self._get_entity_from_string(peer))
|
|
||||||
|
|
||||||
if not isinstance(peer, int) and (not isinstance(peer, TLObject)
|
|
||||||
or peer.SUBCLASS_OF_ID != 0x2d45687):
|
|
||||||
# Try casting the object into an input peer. Might TypeError.
|
|
||||||
# Don't do it if a not-found ID was given (instead ValueError).
|
|
||||||
# Also ignore Peer (0x2d45687 == crc32(b'Peer'))'s, lacking hash.
|
|
||||||
return utils.get_input_peer(peer)
|
|
||||||
|
|
||||||
raise ValueError(
|
|
||||||
'Could not find the input entity for "{}". Please read https://'
|
|
||||||
'telethon.readthedocs.io/en/latest/extra/basic/entities.html to'
|
|
||||||
' find out more details.'
|
|
||||||
.format(peer)
|
|
||||||
)
|
|
||||||
|
|
||||||
def edit_2fa(self, current_password=None, new_password=None, hint='',
|
def edit_2fa(self, current_password=None, new_password=None, hint='',
|
||||||
email=None):
|
email=None):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user