Replace most raw API usage with new location

This commit is contained in:
Lonami Exo 2021-09-12 12:16:02 +02:00
parent a901d43a6d
commit d48649602b
53 changed files with 918 additions and 984 deletions

4
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Generated code # Generated code
/telethon/_tl/functions/ /telethon/_tl/fn/
/telethon/_tl/types/ /telethon/_tl/*.py
/telethon/_tl/alltlobjects.py /telethon/_tl/alltlobjects.py
/telethon/errors/rpcerrorlist.py /telethon/errors/rpcerrorlist.py

View File

@ -55,7 +55,7 @@ METHODS_IN = GENERATOR_DIR / 'data/methods.csv'
FRIENDLY_IN = GENERATOR_DIR / 'data/friendly.csv' FRIENDLY_IN = GENERATOR_DIR / 'data/friendly.csv'
TLOBJECT_IN_TLS = [Path(x) for x in GENERATOR_DIR.glob('data/*.tl')] TLOBJECT_IN_TLS = [Path(x) for x in GENERATOR_DIR.glob('data/*.tl')]
TLOBJECT_OUT = LIBRARY_DIR / 'tl' TLOBJECT_OUT = LIBRARY_DIR / '_tl'
IMPORT_DEPTH = 2 IMPORT_DEPTH = 2
DOCS_IN_RES = GENERATOR_DIR / 'data/html' DOCS_IN_RES = GENERATOR_DIR / 'data/html'

View File

@ -1,8 +1,7 @@
from ._client.telegramclient import TelegramClient from ._client.telegramclient import TelegramClient
from .network import connection from .network import connection
from .tl import types, functions, custom from ._tl import custom
from .tl.custom import Button from ._tl.custom import Button
from .tl import patched as _ # import for its side-effects
from . import version, events, utils, errors from . import version, events, utils, errors
__version__ = version.__version__ __version__ = version.__version__

View File

@ -3,8 +3,7 @@ import inspect
import typing import typing
from .users import _NOT_A_REQUEST from .users import _NOT_A_REQUEST
from .. import helpers, utils from .. import helpers, utils, _tl
from ..tl import functions, TLRequest
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -50,7 +49,7 @@ class _TakeoutClient:
self.__success = exc_type is None self.__success = exc_type is None
if self.__success is not None: if self.__success is not None:
result = await self(functions.account.FinishTakeoutSessionRequest( result = await self(_tl.fn.account.FinishTakeoutSession(
self.__success)) self.__success))
if not result: if not result:
raise ValueError("Failed to finish the takeout.") raise ValueError("Failed to finish the takeout.")
@ -66,10 +65,10 @@ class _TakeoutClient:
requests = ((request,) if single else request) requests = ((request,) if single else request)
wrapped = [] wrapped = []
for r in requests: for r in requests:
if not isinstance(r, TLRequest): if not isinstance(r, _tl.TLRequest):
raise _NOT_A_REQUEST() raise _NOT_A_REQUEST()
await r.resolve(self, utils) await r.resolve(self, utils)
wrapped.append(functions.InvokeWithTakeoutRequest(takeout_id, r)) wrapped.append(_tl.fn.InvokeWithTakeout(takeout_id, r))
return await self.__client( return await self.__client(
wrapped[0] if single else wrapped, ordered=ordered) wrapped[0] if single else wrapped, ordered=ordered)
@ -127,7 +126,7 @@ def takeout(
arg_specified = (arg is not None for arg in request_kwargs.values()) arg_specified = (arg is not None for arg in request_kwargs.values())
if self.session.takeout_id is None or any(arg_specified): if self.session.takeout_id is None or any(arg_specified):
request = functions.account.InitTakeoutSessionRequest( request = _tl.fn.account.InitTakeoutSession(
**request_kwargs) **request_kwargs)
else: else:
request = None request = None

View File

@ -5,8 +5,7 @@ import sys
import typing import typing
import warnings import warnings
from .. import utils, helpers, errors, password as pwd_mod from .. import utils, helpers, errors, password as pwd_mod, _tl
from ..tl import types, functions, custom
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -201,7 +200,7 @@ async def sign_in(
*, *,
password: str = None, password: str = None,
bot_token: str = None, bot_token: str = None,
phone_code_hash: str = None) -> 'typing.Union[types.User, types.auth.SentCode]': phone_code_hash: str = None) -> 'typing.Union[_tl.User, _tl.auth.SentCode]':
me = await self.get_me() me = await self.get_me()
if me: if me:
return me return me
@ -214,16 +213,16 @@ async def sign_in(
# May raise PhoneCodeEmptyError, PhoneCodeExpiredError, # May raise PhoneCodeEmptyError, PhoneCodeExpiredError,
# PhoneCodeHashEmptyError or PhoneCodeInvalidError. # PhoneCodeHashEmptyError or PhoneCodeInvalidError.
request = functions.auth.SignInRequest( request = _tl.fn.auth.SignIn(
phone, phone_code_hash, str(code) phone, phone_code_hash, str(code)
) )
elif password: elif password:
pwd = await self(functions.account.GetPasswordRequest()) pwd = await self(_tl.fn.account.GetPassword())
request = functions.auth.CheckPasswordRequest( request = _tl.fn.auth.CheckPassword(
pwd_mod.compute_check(pwd, password) pwd_mod.compute_check(pwd, password)
) )
elif bot_token: elif bot_token:
request = functions.auth.ImportBotAuthorizationRequest( request = _tl.fn.auth.ImportBotAuthorization(
flags=0, bot_auth_token=bot_token, flags=0, bot_auth_token=bot_token,
api_id=self.api_id, api_hash=self.api_hash api_id=self.api_id, api_hash=self.api_hash
) )
@ -234,7 +233,7 @@ async def sign_in(
) )
result = await self(request) result = await self(request)
if isinstance(result, types.auth.AuthorizationSignUpRequired): if isinstance(result, _tl.auth.AuthorizationSignUpRequired):
# Emulate pre-layer 104 behaviour # Emulate pre-layer 104 behaviour
self._tos = result.terms_of_service self._tos = result.terms_of_service
raise errors.PhoneNumberUnoccupiedError(request=request) raise errors.PhoneNumberUnoccupiedError(request=request)
@ -248,7 +247,7 @@ async def sign_up(
last_name: str = '', last_name: str = '',
*, *,
phone: str = None, phone: str = None,
phone_code_hash: str = None) -> 'types.User': phone_code_hash: str = None) -> '_tl.User':
me = await self.get_me() me = await self.get_me()
if me: if me:
return me return me
@ -281,7 +280,7 @@ async def sign_up(
phone, phone_code_hash = \ phone, phone_code_hash = \
self._parse_phone_and_hash(phone, phone_code_hash) self._parse_phone_and_hash(phone, phone_code_hash)
result = await self(functions.auth.SignUpRequest( result = await self(_tl.fn.auth.SignUp(
phone_number=phone, phone_number=phone,
phone_code_hash=phone_code_hash, phone_code_hash=phone_code_hash,
first_name=first_name, first_name=first_name,
@ -290,7 +289,7 @@ async def sign_up(
if self._tos: if self._tos:
await self( await self(
functions.help.AcceptTermsOfServiceRequest(self._tos.id)) _tl.fn.help.AcceptTermsOfService(self._tos.id))
return self._on_login(result.user) return self._on_login(result.user)
@ -309,20 +308,20 @@ async def send_code_request(
self: 'TelegramClient', self: 'TelegramClient',
phone: str, phone: str,
*, *,
force_sms: bool = False) -> 'types.auth.SentCode': force_sms: bool = False) -> '_tl.auth.SentCode':
result = None result = None
phone = utils.parse_phone(phone) or self._phone phone = utils.parse_phone(phone) or self._phone
phone_hash = self._phone_code_hash.get(phone) phone_hash = self._phone_code_hash.get(phone)
if not phone_hash: if not phone_hash:
try: try:
result = await self(functions.auth.SendCodeRequest( result = await self(_tl.fn.auth.SendCode(
phone, self.api_id, self.api_hash, types.CodeSettings())) phone, self.api_id, self.api_hash, _tl.CodeSettings()))
except errors.AuthRestartError: except errors.AuthRestartError:
return await self.send_code_request(phone, force_sms=force_sms) return await self.send_code_request(phone, force_sms=force_sms)
# If we already sent a SMS, do not resend the code (hash may be empty) # If we already sent a SMS, do not resend the code (hash may be empty)
if isinstance(result.type, types.auth.SentCodeTypeSms): if isinstance(result.type, _tl.auth.SentCodeTypeSms):
force_sms = False force_sms = False
# phone_code_hash may be empty, if it is, do not save it (#1283) # phone_code_hash may be empty, if it is, do not save it (#1283)
@ -335,7 +334,7 @@ async def send_code_request(
if force_sms: if force_sms:
result = await self( result = await self(
functions.auth.ResendCodeRequest(phone, phone_hash)) _tl.fn.auth.ResendCode(phone, phone_hash))
self._phone_code_hash[phone] = result.phone_code_hash self._phone_code_hash[phone] = result.phone_code_hash
@ -348,7 +347,7 @@ async def qr_login(self: 'TelegramClient', ignored_ids: typing.List[int] = None)
async def log_out(self: 'TelegramClient') -> bool: async def log_out(self: 'TelegramClient') -> bool:
try: try:
await self(functions.auth.LogOutRequest()) await self(_tl.fn.auth.LogOut())
except errors.RPCError: except errors.RPCError:
return False return False
@ -375,16 +374,16 @@ async def edit_2fa(
if email and not callable(email_code_callback): if email and not callable(email_code_callback):
raise ValueError('email present without email_code_callback') raise ValueError('email present without email_code_callback')
pwd = await self(functions.account.GetPasswordRequest()) pwd = await self(_tl.fn.account.GetPassword())
pwd.new_algo.salt1 += os.urandom(32) pwd.new_algo.salt1 += os.urandom(32)
assert isinstance(pwd, types.account.Password) assert isinstance(pwd, _tl.account.Password)
if not pwd.has_password and current_password: if not pwd.has_password and current_password:
current_password = None current_password = None
if current_password: if current_password:
password = pwd_mod.compute_check(pwd, current_password) password = pwd_mod.compute_check(pwd, current_password)
else: else:
password = types.InputCheckPasswordEmpty() password = _tl.InputCheckPasswordEmpty()
if new_password: if new_password:
new_password_hash = pwd_mod.compute_digest( new_password_hash = pwd_mod.compute_digest(
@ -393,9 +392,9 @@ async def edit_2fa(
new_password_hash = b'' new_password_hash = b''
try: try:
await self(functions.account.UpdatePasswordSettingsRequest( await self(_tl.fn.account.UpdatePasswordSettings(
password=password, password=password,
new_settings=types.account.PasswordInputSettings( new_settings=_tl.account.PasswordInputSettings(
new_algo=pwd.new_algo, new_algo=pwd.new_algo,
new_password_hash=new_password_hash, new_password_hash=new_password_hash,
hint=hint, hint=hint,
@ -409,6 +408,6 @@ async def edit_2fa(
code = await code code = await code
code = str(code) code = str(code)
await self(functions.account.ConfirmPasswordEmailRequest(code)) await self(_tl.fn.account.ConfirmPasswordEmail(code))
return True return True

View File

@ -1,7 +1,6 @@
import typing import typing
from .. import hints from .. import hints, _tl
from ..tl import types, functions, custom
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -14,14 +13,14 @@ async def inline_query(
*, *,
entity: 'hints.EntityLike' = None, entity: 'hints.EntityLike' = None,
offset: str = None, offset: str = None,
geo_point: 'types.GeoPoint' = None) -> custom.InlineResults: geo_point: '_tl.GeoPoint' = None) -> _tl.custom.InlineResults:
bot = await self.get_input_entity(bot) bot = await self.get_input_entity(bot)
if entity: if entity:
peer = await self.get_input_entity(entity) peer = await self.get_input_entity(entity)
else: else:
peer = types.InputPeerEmpty() peer = _tl.InputPeerEmpty()
result = await self(functions.messages.GetInlineBotResultsRequest( result = await self(_tl.fn.messages.GetInlineBotResults(
bot=bot, bot=bot,
peer=peer, peer=peer,
query=query, query=query,
@ -29,4 +28,4 @@ async def inline_query(
geo_point=geo_point geo_point=geo_point
)) ))
return custom.InlineResults(self, result, entity=peer if entity else None) return _tl.custom.InlineResults(self, result, entity=peer if entity else None)

View File

@ -1,12 +1,11 @@
import typing import typing
from .. import utils, hints from .. import utils, hints, _tl
from ..tl import types, custom
def build_reply_markup( def build_reply_markup(
buttons: 'typing.Optional[hints.MarkupLike]', buttons: 'typing.Optional[hints.MarkupLike]',
inline_only: bool = False) -> 'typing.Optional[types.TypeReplyMarkup]': inline_only: bool = False) -> 'typing.Optional[_tl.TypeReplyMarkup]':
if buttons is None: if buttons is None:
return None return None
@ -31,7 +30,7 @@ def build_reply_markup(
for row in buttons: for row in buttons:
current = [] current = []
for button in row: for button in row:
if isinstance(button, custom.Button): if isinstance(button, _tl.custom.Button):
if button.resize is not None: if button.resize is not None:
resize = button.resize resize = button.resize
if button.single_use is not None: if button.single_use is not None:
@ -40,10 +39,10 @@ def build_reply_markup(
selective = button.selective selective = button.selective
button = button.button button = button.button
elif isinstance(button, custom.MessageButton): elif isinstance(button, _tl.custom.MessageButton):
button = button.button button = button.button
inline = custom.Button._is_inline(button) inline = _tl.custom.Button._is_inline(button)
is_inline |= inline is_inline |= inline
is_normal |= not inline is_normal |= not inline
@ -52,14 +51,14 @@ def build_reply_markup(
current.append(button) current.append(button)
if current: if current:
rows.append(types.KeyboardButtonRow(current)) rows.append(_tl.KeyboardButtonRow(current))
if inline_only and is_normal: if inline_only and is_normal:
raise ValueError('You cannot use non-inline buttons here') raise ValueError('You cannot use non-inline buttons here')
elif is_inline == is_normal and is_normal: elif is_inline == is_normal and is_normal:
raise ValueError('You cannot mix inline with normal buttons') raise ValueError('You cannot mix inline with normal buttons')
elif is_inline: elif is_inline:
return types.ReplyInlineMarkup(rows) return _tl.ReplyInlineMarkup(rows)
# elif is_normal: # elif is_normal:
return types.ReplyKeyboardMarkup( return _tl.ReplyKeyboardMarkup(
rows, resize=resize, single_use=single_use, selective=selective) rows, resize=resize, single_use=single_use, selective=selective)

View File

@ -4,9 +4,8 @@ import itertools
import string import string
import typing import typing
from .. import helpers, utils, hints, errors from .. import helpers, utils, hints, errors, _tl
from ..requestiter import RequestIter from ..requestiter import RequestIter
from ..tl import types, functions, custom
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -18,28 +17,28 @@ _MAX_PROFILE_PHOTO_CHUNK_SIZE = 100
class _ChatAction: class _ChatAction:
_str_mapping = { _str_mapping = {
'typing': types.SendMessageTypingAction(), 'typing': _tl.SendMessageTypingAction(),
'contact': types.SendMessageChooseContactAction(), 'contact': _tl.SendMessageChooseContactAction(),
'game': types.SendMessageGamePlayAction(), 'game': _tl.SendMessageGamePlayAction(),
'location': types.SendMessageGeoLocationAction(), 'location': _tl.SendMessageGeoLocationAction(),
'sticker': types.SendMessageChooseStickerAction(), 'sticker': _tl.SendMessageChooseStickerAction(),
'record-audio': types.SendMessageRecordAudioAction(), 'record-audio': _tl.SendMessageRecordAudioAction(),
'record-voice': types.SendMessageRecordAudioAction(), # alias 'record-voice': _tl.SendMessageRecordAudioAction(), # alias
'record-round': types.SendMessageRecordRoundAction(), 'record-round': _tl.SendMessageRecordRoundAction(),
'record-video': types.SendMessageRecordVideoAction(), 'record-video': _tl.SendMessageRecordVideoAction(),
'audio': types.SendMessageUploadAudioAction(1), 'audio': _tl.SendMessageUploadAudioAction(1),
'voice': types.SendMessageUploadAudioAction(1), # alias 'voice': _tl.SendMessageUploadAudioAction(1), # alias
'song': types.SendMessageUploadAudioAction(1), # alias 'song': _tl.SendMessageUploadAudioAction(1), # alias
'round': types.SendMessageUploadRoundAction(1), 'round': _tl.SendMessageUploadRoundAction(1),
'video': types.SendMessageUploadVideoAction(1), 'video': _tl.SendMessageUploadVideoAction(1),
'photo': types.SendMessageUploadPhotoAction(1), 'photo': _tl.SendMessageUploadPhotoAction(1),
'document': types.SendMessageUploadDocumentAction(1), 'document': _tl.SendMessageUploadDocumentAction(1),
'file': types.SendMessageUploadDocumentAction(1), # alias 'file': _tl.SendMessageUploadDocumentAction(1), # alias
'cancel': types.SendMessageCancelAction() 'cancel': _tl.SendMessageCancelAction()
} }
def __init__(self, client, chat, action, *, delay, auto_cancel): def __init__(self, client, chat, action, *, delay, auto_cancel):
@ -58,7 +57,7 @@ class _ChatAction:
# Since `self._action` is passed by reference we can avoid # Since `self._action` is passed by reference we can avoid
# recreating the request all the time and still modify # recreating the request all the time and still modify
# `self._action.progress` directly in `progress`. # `self._action.progress` directly in `progress`.
self._request = functions.messages.SetTypingRequest( self._request = _tl.fn.messages.SetTyping(
self._chat, self._action) self._chat, self._action)
self._running = True self._running = True
@ -85,8 +84,8 @@ class _ChatAction:
pass pass
except asyncio.CancelledError: except asyncio.CancelledError:
if self._auto_cancel: if self._auto_cancel:
await self._client(functions.messages.SetTypingRequest( await self._client(_tl.fn.messages.SetTyping(
self._chat, types.SendMessageCancelAction())) self._chat, _tl.SendMessageCancelAction()))
def progress(self, current, total): def progress(self, current, total):
if hasattr(self._action, 'progress'): if hasattr(self._action, 'progress'):
@ -96,10 +95,10 @@ class _ChatAction:
class _ParticipantsIter(RequestIter): class _ParticipantsIter(RequestIter):
async def _init(self, entity, filter, search, aggressive): async def _init(self, entity, filter, search, aggressive):
if isinstance(filter, type): if isinstance(filter, type):
if filter in (types.ChannelParticipantsBanned, if filter in (_tl.ChannelParticipantsBanned,
types.ChannelParticipantsKicked, _tl.ChannelParticipantsKicked,
types.ChannelParticipantsSearch, _tl.ChannelParticipantsSearch,
types.ChannelParticipantsContacts): _tl.ChannelParticipantsContacts):
# These require a `q` parameter (support types for convenience) # These require a `q` parameter (support types for convenience)
filter = filter('') filter = filter('')
else: else:
@ -125,23 +124,23 @@ class _ParticipantsIter(RequestIter):
if self.limit <= 0: if self.limit <= 0:
# May not have access to the channel, but getFull can get the .total. # May not have access to the channel, but getFull can get the .total.
self.total = (await self.client( self.total = (await self.client(
functions.channels.GetFullChannelRequest(entity) _tl.fn.channels.GetFullChannel(entity)
)).full_chat.participants_count )).full_chat.participants_count
raise StopAsyncIteration raise StopAsyncIteration
self.seen = set() self.seen = set()
if aggressive and not filter: if aggressive and not filter:
self.requests.extend(functions.channels.GetParticipantsRequest( self.requests.extend(_tl.fn.channels.GetParticipants(
channel=entity, channel=entity,
filter=types.ChannelParticipantsSearch(x), filter=_tl.ChannelParticipantsSearch(x),
offset=0, offset=0,
limit=_MAX_PARTICIPANTS_CHUNK_SIZE, limit=_MAX_PARTICIPANTS_CHUNK_SIZE,
hash=0 hash=0
) for x in (search or string.ascii_lowercase)) ) for x in (search or string.ascii_lowercase))
else: else:
self.requests.append(functions.channels.GetParticipantsRequest( self.requests.append(_tl.fn.channels.GetParticipants(
channel=entity, channel=entity,
filter=filter or types.ChannelParticipantsSearch(search), filter=filter or _tl.ChannelParticipantsSearch(search),
offset=0, offset=0,
limit=_MAX_PARTICIPANTS_CHUNK_SIZE, limit=_MAX_PARTICIPANTS_CHUNK_SIZE,
hash=0 hash=0
@ -149,9 +148,9 @@ class _ParticipantsIter(RequestIter):
elif ty == helpers._EntityType.CHAT: elif ty == helpers._EntityType.CHAT:
full = await self.client( full = await self.client(
functions.messages.GetFullChatRequest(entity.chat_id)) _tl.fn.messages.GetFullChat(entity.chat_id))
if not isinstance( if not isinstance(
full.full_chat.participants, types.ChatParticipants): full.full_chat.participants, _tl.ChatParticipants):
# ChatParticipantsForbidden won't have ``.participants`` # ChatParticipantsForbidden won't have ``.participants``
self.total = 0 self.total = 0
raise StopAsyncIteration raise StopAsyncIteration
@ -160,7 +159,7 @@ class _ParticipantsIter(RequestIter):
users = {user.id: user for user in full.users} users = {user.id: user for user in full.users}
for participant in full.full_chat.participants.participants: for participant in full.full_chat.participants.participants:
if isinstance(participant, types.ChannelParticipantBanned): if isinstance(participant, _tl.ChannelParticipantBanned):
user_id = participant.peer.user_id user_id = participant.peer.user_id
else: else:
user_id = participant.user_id user_id = participant.user_id
@ -202,15 +201,15 @@ class _ParticipantsIter(RequestIter):
if self.total is None: if self.total is None:
f = self.requests[0].filter f = self.requests[0].filter
if len(self.requests) > 1 or ( if len(self.requests) > 1 or (
not isinstance(f, types.ChannelParticipantsRecent) not isinstance(f, _tl.ChannelParticipantsRecent)
and (not isinstance(f, types.ChannelParticipantsSearch) or f.q) and (not isinstance(f, _tl.ChannelParticipantsSearch) or f.q)
): ):
# Only do an additional getParticipants here to get the total # Only do an additional getParticipants here to get the total
# if there's a filter which would reduce the real total number. # if there's a filter which would reduce the real total number.
# getParticipants is cheaper than getFull. # getParticipants is cheaper than getFull.
self.total = (await self.client(functions.channels.GetParticipantsRequest( self.total = (await self.client(_tl.fn.channels.GetParticipants(
channel=self.requests[0].channel, channel=self.requests[0].channel,
filter=types.ChannelParticipantsRecent(), filter=_tl.ChannelParticipantsRecent(),
offset=0, offset=0,
limit=1, limit=1,
hash=0 hash=0
@ -230,8 +229,8 @@ class _ParticipantsIter(RequestIter):
users = {user.id: user for user in participants.users} users = {user.id: user for user in participants.users}
for participant in participants.participants: for participant in participants.participants:
if isinstance(participant, types.ChannelParticipantBanned): if isinstance(participant, _tl.ChannelParticipantBanned):
if not isinstance(participant.peer, types.PeerUser): if not isinstance(participant.peer, _tl.PeerUser):
# May have the entire channel banned. See #3105. # May have the entire channel banned. See #3105.
continue continue
user_id = participant.peer.user_id user_id = participant.peer.user_id
@ -257,7 +256,7 @@ class _AdminLogIter(RequestIter):
if any((join, leave, invite, restrict, unrestrict, ban, unban, if any((join, leave, invite, restrict, unrestrict, ban, unban,
promote, demote, info, settings, pinned, edit, delete, promote, demote, info, settings, pinned, edit, delete,
group_call)): group_call)):
events_filter = types.ChannelAdminLogEventsFilter( events_filter = _tl.ChannelAdminLogEventsFilter(
join=join, leave=leave, invite=invite, ban=restrict, join=join, leave=leave, invite=invite, ban=restrict,
unban=unrestrict, kick=ban, unkick=unban, promote=promote, unban=unrestrict, kick=ban, unkick=unban, promote=promote,
demote=demote, info=info, settings=settings, pinned=pinned, demote=demote, info=info, settings=settings, pinned=pinned,
@ -276,7 +275,7 @@ class _AdminLogIter(RequestIter):
for admin in admins: for admin in admins:
admin_list.append(await self.client.get_input_entity(admin)) admin_list.append(await self.client.get_input_entity(admin))
self.request = functions.channels.GetAdminLogRequest( self.request = _tl.fn.channels.GetAdminLog(
self.entity, q=search or '', min_id=min_id, max_id=max_id, self.entity, q=search or '', min_id=min_id, max_id=max_id,
limit=0, events_filter=events_filter, admins=admin_list or None limit=0, events_filter=events_filter, admins=admin_list or None
) )
@ -290,7 +289,7 @@ class _AdminLogIter(RequestIter):
self.request.max_id = min((e.id for e in r.events), default=0) self.request.max_id = min((e.id for e in r.events), default=0)
for ev in r.events: for ev in r.events:
if isinstance(ev.action, if isinstance(ev.action,
types.ChannelAdminLogEventActionEditMessage): _tl.ChannelAdminLogEventActionEditMessage):
ev.action.prev_message._finish_init( ev.action.prev_message._finish_init(
self.client, entities, self.entity) self.client, entities, self.entity)
@ -298,11 +297,11 @@ class _AdminLogIter(RequestIter):
self.client, entities, self.entity) self.client, entities, self.entity)
elif isinstance(ev.action, elif isinstance(ev.action,
types.ChannelAdminLogEventActionDeleteMessage): _tl.ChannelAdminLogEventActionDeleteMessage):
ev.action.message._finish_init( ev.action.message._finish_init(
self.client, entities, self.entity) self.client, entities, self.entity)
self.buffer.append(custom.AdminLogEvent(ev, entities)) self.buffer.append(_tl.custom.AdminLogEvent(ev, entities))
if len(r.events) < self.request.limit: if len(r.events) < self.request.limit:
return True return True
@ -315,17 +314,17 @@ class _ProfilePhotoIter(RequestIter):
entity = await self.client.get_input_entity(entity) entity = await self.client.get_input_entity(entity)
ty = helpers._entity_type(entity) ty = helpers._entity_type(entity)
if ty == helpers._EntityType.USER: if ty == helpers._EntityType.USER:
self.request = functions.photos.GetUserPhotosRequest( self.request = _tl.fn.photos.GetUserPhotos(
entity, entity,
offset=offset, offset=offset,
max_id=max_id, max_id=max_id,
limit=1 limit=1
) )
else: else:
self.request = functions.messages.SearchRequest( self.request = _tl.fn.messages.Search(
peer=entity, peer=entity,
q='', q='',
filter=types.InputMessagesFilterChatPhotos(), filter=_tl.InputMessagesFilterChatPhotos(),
min_date=None, min_date=None,
max_date=None, max_date=None,
offset_id=0, offset_id=0,
@ -339,9 +338,9 @@ class _ProfilePhotoIter(RequestIter):
if self.limit == 0: if self.limit == 0:
self.request.limit = 1 self.request.limit = 1
result = await self.client(self.request) result = await self.client(self.request)
if isinstance(result, types.photos.Photos): if isinstance(result, _tl.photos.Photos):
self.total = len(result.photos) self.total = len(result.photos)
elif isinstance(result, types.messages.Messages): elif isinstance(result, _tl.messages.Messages):
self.total = len(result.messages) self.total = len(result.messages)
else: else:
# Luckily both photosSlice and messages have a count for total # Luckily both photosSlice and messages have a count for total
@ -351,17 +350,17 @@ class _ProfilePhotoIter(RequestIter):
self.request.limit = min(self.left, _MAX_PROFILE_PHOTO_CHUNK_SIZE) self.request.limit = min(self.left, _MAX_PROFILE_PHOTO_CHUNK_SIZE)
result = await self.client(self.request) result = await self.client(self.request)
if isinstance(result, types.photos.Photos): if isinstance(result, _tl.photos.Photos):
self.buffer = result.photos self.buffer = result.photos
self.left = len(self.buffer) self.left = len(self.buffer)
self.total = len(self.buffer) self.total = len(self.buffer)
elif isinstance(result, types.messages.Messages): elif isinstance(result, _tl.messages.Messages):
self.buffer = [x.action.photo for x in result.messages self.buffer = [x.action.photo for x in result.messages
if isinstance(x.action, types.MessageActionChatEditPhoto)] if isinstance(x.action, _tl.MessageActionChatEditPhoto)]
self.left = len(self.buffer) self.left = len(self.buffer)
self.total = len(self.buffer) self.total = len(self.buffer)
elif isinstance(result, types.photos.PhotosSlice): elif isinstance(result, _tl.photos.PhotosSlice):
self.buffer = result.photos self.buffer = result.photos
self.total = result.count self.total = result.count
if len(self.buffer) < self.request.limit: if len(self.buffer) < self.request.limit:
@ -381,16 +380,16 @@ class _ProfilePhotoIter(RequestIter):
# Unconditionally fetch the full channel to obtain this photo and # Unconditionally fetch the full channel to obtain this photo and
# yield it with the rest (unless it's a duplicate). # yield it with the rest (unless it's a duplicate).
seen_id = None seen_id = None
if isinstance(result, types.messages.ChannelMessages): if isinstance(result, _tl.messages.ChannelMessages):
channel = await self.client(functions.channels.GetFullChannelRequest(self.request.peer)) channel = await self.client(_tl.fn.channels.GetFullChannel(self.request.peer))
photo = channel.full_chat.chat_photo photo = channel.full_chat.chat_photo
if isinstance(photo, types.Photo): if isinstance(photo, _tl.Photo):
self.buffer.append(photo) self.buffer.append(photo)
seen_id = photo.id seen_id = photo.id
self.buffer.extend( self.buffer.extend(
x.action.photo for x in result.messages x.action.photo for x in result.messages
if isinstance(x.action, types.MessageActionChatEditPhoto) if isinstance(x.action, _tl.MessageActionChatEditPhoto)
and x.action.photo.id != seen_id and x.action.photo.id != seen_id
) )
@ -407,7 +406,7 @@ def iter_participants(
limit: float = None, limit: float = None,
*, *,
search: str = '', search: str = '',
filter: 'types.TypeChannelParticipantsFilter' = None, filter: '_tl.TypeChannelParticipantsFilter' = None,
aggressive: bool = False) -> _ParticipantsIter: aggressive: bool = False) -> _ParticipantsIter:
return _ParticipantsIter( return _ParticipantsIter(
self, self,
@ -506,7 +505,7 @@ async def get_profile_photos(
def action( def action(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
action: 'typing.Union[str, types.TypeSendMessageAction]', action: 'typing.Union[str, _tl.TypeSendMessageAction]',
*, *,
delay: float = 4, delay: float = 4,
auto_cancel: bool = True) -> 'typing.Union[_ChatAction, typing.Coroutine]': auto_cancel: bool = True) -> 'typing.Union[_ChatAction, typing.Coroutine]':
@ -516,17 +515,17 @@ def action(
except KeyError: except KeyError:
raise ValueError( raise ValueError(
'No such action "{}"'.format(action)) from None 'No such action "{}"'.format(action)) from None
elif not isinstance(action, types.TLObject) or action.SUBCLASS_OF_ID != 0x20b2cc21: elif not isinstance(action, _tl.TLObject) or action.SUBCLASS_OF_ID != 0x20b2cc21:
# 0x20b2cc21 = crc32(b'SendMessageAction') # 0x20b2cc21 = crc32(b'SendMessageAction')
if isinstance(action, type): if isinstance(action, type):
raise ValueError('You must pass an instance, not the class') raise ValueError('You must pass an instance, not the class')
else: else:
raise ValueError('Cannot use {} as action'.format(action)) raise ValueError('Cannot use {} as action'.format(action))
if isinstance(action, types.SendMessageCancelAction): if isinstance(action, _tl.SendMessageCancelAction):
# ``SetTypingRequest.resolve`` will get input peer of ``entity``. # ``SetTypingRequest.resolve`` will get input peer of ``entity``.
return self(functions.messages.SetTypingRequest( return self(_tl.fn.messages.SetTyping(
entity, types.SendMessageCancelAction())) entity, _tl.SendMessageCancelAction()))
return _ChatAction( return _ChatAction(
self, entity, action, delay=delay, auto_cancel=auto_cancel) self, entity, action, delay=delay, auto_cancel=auto_cancel)
@ -547,7 +546,7 @@ async def edit_admin(
manage_call: bool = None, manage_call: bool = None,
anonymous: bool = None, anonymous: bool = None,
is_admin: bool = None, is_admin: bool = None,
title: str = None) -> types.Updates: title: str = None) -> _tl.Updates:
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
user = await self.get_input_entity(user) user = await self.get_input_entity(user)
ty = helpers._entity_type(user) ty = helpers._entity_type(user)
@ -576,7 +575,7 @@ async def edit_admin(
edit_messages = None edit_messages = None
perms = locals() perms = locals()
return await self(functions.channels.EditAdminRequest(entity, user, types.ChatAdminRights(**{ return await self(_tl.fn.channels.EditAdmin(entity, user, _tl.ChatAdminRights(**{
# A permission is its explicit (not-None) value or `is_admin`. # A permission is its explicit (not-None) value or `is_admin`.
# This essentially makes `is_admin` be the default value. # This essentially makes `is_admin` be the default value.
name: perms[name] if perms[name] is not None else is_admin name: perms[name] if perms[name] is not None else is_admin
@ -589,7 +588,7 @@ async def edit_admin(
if is_admin is None: if is_admin is None:
is_admin = any(locals()[x] for x in perm_names) is_admin = any(locals()[x] for x in perm_names)
return await self(functions.messages.EditChatAdminRequest( return await self(_tl.fn.messages.EditChatAdmin(
entity, user, is_admin=is_admin)) entity, user, is_admin=is_admin))
else: else:
@ -613,13 +612,13 @@ async def edit_permissions(
send_polls: bool = True, send_polls: bool = True,
change_info: bool = True, change_info: bool = True,
invite_users: bool = True, invite_users: bool = True,
pin_messages: bool = True) -> types.Updates: pin_messages: bool = True) -> _tl.Updates:
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
ty = helpers._entity_type(entity) ty = helpers._entity_type(entity)
if ty != helpers._EntityType.CHANNEL: if ty != helpers._EntityType.CHANNEL:
raise ValueError('You must pass either a channel or a supergroup') raise ValueError('You must pass either a channel or a supergroup')
rights = types.ChatBannedRights( rights = _tl.ChatBannedRights(
until_date=until_date, until_date=until_date,
view_messages=not view_messages, view_messages=not view_messages,
send_messages=not send_messages, send_messages=not send_messages,
@ -636,7 +635,7 @@ async def edit_permissions(
) )
if user is None: if user is None:
return await self(functions.messages.EditChatDefaultBannedRightsRequest( return await self(_tl.fn.messages.EditChatDefaultBannedRights(
peer=entity, peer=entity,
banned_rights=rights banned_rights=rights
)) ))
@ -646,10 +645,10 @@ async def edit_permissions(
if ty != helpers._EntityType.USER: if ty != helpers._EntityType.USER:
raise ValueError('You must pass a user entity') raise ValueError('You must pass a user entity')
if isinstance(user, types.InputPeerSelf): if isinstance(user, _tl.InputPeerSelf):
raise ValueError('You cannot restrict yourself') raise ValueError('You cannot restrict yourself')
return await self(functions.channels.EditBannedRequest( return await self(_tl.fn.channels.EditBanned(
channel=entity, channel=entity,
participant=user, participant=user,
banned_rights=rights banned_rights=rights
@ -667,24 +666,24 @@ async def kick_participant(
ty = helpers._entity_type(entity) ty = helpers._entity_type(entity)
if ty == helpers._EntityType.CHAT: if ty == helpers._EntityType.CHAT:
resp = await self(functions.messages.DeleteChatUserRequest(entity.chat_id, user)) resp = await self(_tl.fn.messages.DeleteChatUser(entity.chat_id, user))
elif ty == helpers._EntityType.CHANNEL: elif ty == helpers._EntityType.CHANNEL:
if isinstance(user, types.InputPeerSelf): if isinstance(user, _tl.InputPeerSelf):
# Despite no longer being in the channel, the account still # Despite no longer being in the channel, the account still
# seems to get the service message. # seems to get the service message.
resp = await self(functions.channels.LeaveChannelRequest(entity)) resp = await self(_tl.fn.channels.LeaveChannel(entity))
else: else:
resp = await self(functions.channels.EditBannedRequest( resp = await self(_tl.fn.channels.EditBanned(
channel=entity, channel=entity,
participant=user, participant=user,
banned_rights=types.ChatBannedRights( banned_rights=_tl.ChatBannedRights(
until_date=None, view_messages=True) until_date=None, view_messages=True)
)) ))
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
await self(functions.channels.EditBannedRequest( await self(_tl.fn.channels.EditBanned(
channel=entity, channel=entity,
participant=user, participant=user,
banned_rights=types.ChatBannedRights(until_date=None) banned_rights=_tl.ChatBannedRights(until_date=None)
)) ))
else: else:
raise ValueError('You must pass either a channel or a chat') raise ValueError('You must pass either a channel or a chat')
@ -695,14 +694,14 @@ async def get_permissions(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
user: 'hints.EntityLike' = None user: 'hints.EntityLike' = None
) -> 'typing.Optional[custom.ParticipantPermissions]': ) -> 'typing.Optional[_tl.custom.ParticipantPermissions]':
entity = await self.get_entity(entity) entity = await self.get_entity(entity)
if not user: if not user:
if isinstance(entity, types.Channel): if isinstance(entity, _tl.Channel):
FullChat = await self(functions.channels.GetFullChannelRequest(entity)) FullChat = await self(_tl.fn.channels.GetFullChannel(entity))
elif isinstance(entity, types.Chat): elif isinstance(entity, _tl.Chat):
FullChat = await self(functions.messages.GetFullChatRequest(entity)) FullChat = await self(_tl.fn.messages.GetFullChat(entity))
else: else:
return return
return FullChat.chats[0].default_banned_rights return FullChat.chats[0].default_banned_rights
@ -712,20 +711,20 @@ async def get_permissions(
if helpers._entity_type(user) != helpers._EntityType.USER: if helpers._entity_type(user) != helpers._EntityType.USER:
raise ValueError('You must pass a user entity') raise ValueError('You must pass a user entity')
if helpers._entity_type(entity) == helpers._EntityType.CHANNEL: if helpers._entity_type(entity) == helpers._EntityType.CHANNEL:
participant = await self(functions.channels.GetParticipantRequest( participant = await self(_tl.fn.channels.GetParticipant(
entity, entity,
user user
)) ))
return custom.ParticipantPermissions(participant.participant, False) return _tl.custom.ParticipantPermissions(participant.participant, False)
elif helpers._entity_type(entity) == helpers._EntityType.CHAT: elif helpers._entity_type(entity) == helpers._EntityType.CHAT:
chat = await self(functions.messages.GetFullChatRequest( chat = await self(_tl.fn.messages.GetFullChat(
entity entity
)) ))
if isinstance(user, types.InputPeerSelf): if isinstance(user, _tl.InputPeerSelf):
user = await self.get_me(input_peer=True) user = await self.get_me(input_peer=True)
for participant in chat.full_chat.participants.participants: for participant in chat.full_chat.participants.participants:
if participant.user_id == user.user_id: if participant.user_id == user.user_id:
return custom.ParticipantPermissions(participant, True) return _tl.custom.ParticipantPermissions(participant, True)
raise errors.UserNotParticipantError(None) raise errors.UserNotParticipantError(None)
raise ValueError('You must pass either a channel or a chat') raise ValueError('You must pass either a channel or a chat')
@ -733,7 +732,7 @@ async def get_permissions(
async def get_stats( async def get_stats(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message: 'typing.Union[int, types.Message]' = None, message: 'typing.Union[int, _tl.Message]' = None,
): ):
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
if helpers._entity_type(entity) != helpers._EntityType.CHANNEL: if helpers._entity_type(entity) != helpers._EntityType.CHANNEL:
@ -742,7 +741,7 @@ async def get_stats(
message = utils.get_message_id(message) message = utils.get_message_id(message)
if message is not None: if message is not None:
try: try:
req = functions.stats.GetMessageStatsRequest(entity, message) req = _tl.fn.stats.GetMessageStats(entity, message)
return await self(req) return await self(req)
except errors.StatsMigrateError as e: except errors.StatsMigrateError as e:
dc = e.dc dc = e.dc
@ -751,12 +750,12 @@ async def get_stats(
# try to guess and if it fails we know it's the other one (best case # try to guess and if it fails we know it's the other one (best case
# no extra request, worst just one). # no extra request, worst just one).
try: try:
req = functions.stats.GetBroadcastStatsRequest(entity) req = _tl.fn.stats.GetBroadcastStats(entity)
return await self(req) return await self(req)
except errors.StatsMigrateError as e: except errors.StatsMigrateError as e:
dc = e.dc dc = e.dc
except errors.BroadcastRequiredError: except errors.BroadcastRequiredError:
req = functions.stats.GetMegagroupStatsRequest(entity) req = _tl.fn.stats.GetMegagroupStats(entity)
try: try:
return await self(req) return await self(req)
except errors.StatsMigrateError as e: except errors.StatsMigrateError as e:

View File

@ -3,9 +3,8 @@ import inspect
import itertools import itertools
import typing import typing
from .. import helpers, utils, hints, errors from .. import helpers, utils, hints, errors, _tl
from ..requestiter import RequestIter from ..requestiter import RequestIter
from ..tl import types, functions, custom
_MAX_CHUNK_SIZE = 100 _MAX_CHUNK_SIZE = 100
@ -21,14 +20,14 @@ def _dialog_message_key(peer, message_id):
and the peer ID is required to distinguish between them. But it is not and the peer ID is required to distinguish between them. But it is not
necessary in small group chats and private chats. necessary in small group chats and private chats.
""" """
return (peer.channel_id if isinstance(peer, types.PeerChannel) else None), message_id return (peer.channel_id if isinstance(peer, _tl.PeerChannel) else None), message_id
class _DialogsIter(RequestIter): class _DialogsIter(RequestIter):
async def _init( async def _init(
self, offset_date, offset_id, offset_peer, ignore_pinned, ignore_migrated, folder self, offset_date, offset_id, offset_peer, ignore_pinned, ignore_migrated, folder
): ):
self.request = functions.messages.GetDialogsRequest( self.request = _tl.fn.messages.GetDialogs(
offset_date=offset_date, offset_date=offset_date,
offset_id=offset_id, offset_id=offset_id,
offset_peer=offset_peer, offset_peer=offset_peer,
@ -56,7 +55,7 @@ class _DialogsIter(RequestIter):
entities = {utils.get_peer_id(x): x entities = {utils.get_peer_id(x): x
for x in itertools.chain(r.users, r.chats) for x in itertools.chain(r.users, r.chats)
if not isinstance(x, (types.UserEmpty, types.ChatEmpty))} if not isinstance(x, (_tl.UserEmpty, _tl.ChatEmpty))}
messages = {} messages = {}
for m in r.messages: for m in r.messages:
@ -80,7 +79,7 @@ class _DialogsIter(RequestIter):
# Real world example: https://t.me/TelethonChat/271471 # Real world example: https://t.me/TelethonChat/271471
continue continue
cd = custom.Dialog(self.client, d, entities, message) cd = _tl.custom.Dialog(self.client, d, entities, message)
if cd.dialog.pts: if cd.dialog.pts:
self.client._channel_pts[cd.id] = cd.dialog.pts self.client._channel_pts[cd.id] = cd.dialog.pts
@ -89,7 +88,7 @@ class _DialogsIter(RequestIter):
self.buffer.append(cd) self.buffer.append(cd)
if len(r.dialogs) < self.request.limit\ if len(r.dialogs) < self.request.limit\
or not isinstance(r, types.messages.DialogsSlice): or not isinstance(r, _tl.messages.DialogsSlice):
# Less than we requested means we reached the end, or # Less than we requested means we reached the end, or
# we didn't get a DialogsSlice which means we got all. # we didn't get a DialogsSlice which means we got all.
return True return True
@ -112,15 +111,15 @@ class _DialogsIter(RequestIter):
class _DraftsIter(RequestIter): class _DraftsIter(RequestIter):
async def _init(self, entities, **kwargs): async def _init(self, entities, **kwargs):
if not entities: if not entities:
r = await self.client(functions.messages.GetAllDraftsRequest()) r = await self.client(_tl.fn.messages.GetAllDrafts())
items = r.updates items = r.updates
else: else:
peers = [] peers = []
for entity in entities: for entity in entities:
peers.append(types.InputDialogPeer( peers.append(_tl.InputDialogPeer(
await self.client.get_input_entity(entity))) await self.client.get_input_entity(entity)))
r = await self.client(functions.messages.GetPeerDialogsRequest(peers)) r = await self.client(_tl.fn.messages.GetPeerDialogs(peers))
items = r.dialogs items = r.dialogs
# TODO Maybe there should be a helper method for this? # TODO Maybe there should be a helper method for this?
@ -128,7 +127,7 @@ class _DraftsIter(RequestIter):
for x in itertools.chain(r.users, r.chats)} for x in itertools.chain(r.users, r.chats)}
self.buffer.extend( self.buffer.extend(
custom.Draft(self.client, entities[utils.get_peer_id(d.peer)], d.draft) _tl.custom.Draft(self.client, entities[utils.get_peer_id(d.peer)], d.draft)
for d in items for d in items
) )
@ -142,7 +141,7 @@ def iter_dialogs(
*, *,
offset_date: 'hints.DateLike' = None, offset_date: 'hints.DateLike' = None,
offset_id: int = 0, offset_id: int = 0,
offset_peer: 'hints.EntityLike' = types.InputPeerEmpty(), offset_peer: 'hints.EntityLike' = _tl.InputPeerEmpty(),
ignore_pinned: bool = False, ignore_pinned: bool = False,
ignore_migrated: bool = False, ignore_migrated: bool = False,
folder: int = None, folder: int = None,
@ -192,12 +191,12 @@ async def edit_folder(
folder: typing.Union[int, typing.Sequence[int]] = None, folder: typing.Union[int, typing.Sequence[int]] = None,
*, *,
unpack=None unpack=None
) -> types.Updates: ) -> _tl.Updates:
if (entity is None) == (unpack is None): if (entity is None) == (unpack is None):
raise ValueError('You can only set either entities or unpack, not both') raise ValueError('You can only set either entities or unpack, not both')
if unpack is not None: if unpack is not None:
return await self(functions.folders.DeleteFolderRequest( return await self(_tl.fn.folders.DeleteFolder(
folder_id=unpack folder_id=unpack
)) ))
@ -214,8 +213,8 @@ async def edit_folder(
elif len(entities) != len(folder): elif len(entities) != len(folder):
raise ValueError('Number of folders does not match number of entities') raise ValueError('Number of folders does not match number of entities')
return await self(functions.folders.EditPeerFoldersRequest([ return await self(_tl.fn.folders.EditPeerFolders([
types.InputFolderPeer(x, folder_id=y) _tl.InputFolderPeer(x, folder_id=y)
for x, y in zip(entities, folder) for x, y in zip(entities, folder)
])) ]))
@ -227,7 +226,7 @@ async def delete_dialog(
): ):
# If we have enough information (`Dialog.delete` gives it to us), # If we have enough information (`Dialog.delete` gives it to us),
# then we know we don't have to kick ourselves in deactivated chats. # then we know we don't have to kick ourselves in deactivated chats.
if isinstance(entity, types.Chat): if isinstance(entity, _tl.Chat):
deactivated = entity.deactivated deactivated = entity.deactivated
else: else:
deactivated = False deactivated = False
@ -235,12 +234,12 @@ async def delete_dialog(
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
ty = helpers._entity_type(entity) ty = helpers._entity_type(entity)
if ty == helpers._EntityType.CHANNEL: if ty == helpers._EntityType.CHANNEL:
return await self(functions.channels.LeaveChannelRequest(entity)) return await self(_tl.fn.channels.LeaveChannel(entity))
if ty == helpers._EntityType.CHAT and not deactivated: if ty == helpers._EntityType.CHAT and not deactivated:
try: try:
result = await self(functions.messages.DeleteChatUserRequest( result = await self(_tl.fn.messages.DeleteChatUser(
entity.chat_id, types.InputUserSelf(), revoke_history=revoke entity.chat_id, _tl.InputUserSelf(), revoke_history=revoke
)) ))
except errors.PeerIdInvalidError: except errors.PeerIdInvalidError:
# Happens if we didn't have the deactivated information # Happens if we didn't have the deactivated information
@ -249,6 +248,6 @@ async def delete_dialog(
result = None result = None
if not await self.is_bot(): if not await self.is_bot():
await self(functions.messages.DeleteHistoryRequest(entity, 0, revoke=revoke)) await self(_tl.fn.messages.DeleteHistory(entity, 0, revoke=revoke))
return result return result

View File

@ -8,9 +8,8 @@ import asyncio
from ..crypto import AES from ..crypto import AES
from .. import utils, helpers, errors, hints from .. import utils, helpers, errors, hints, _tl
from ..requestiter import RequestIter from ..requestiter import RequestIter
from ..tl import TLObject, types, functions
try: try:
import aiohttp import aiohttp
@ -31,7 +30,7 @@ class _DirectDownloadIter(RequestIter):
async def _init( async def _init(
self, file, dc_id, offset, stride, chunk_size, request_size, file_size, msg_data self, file, dc_id, offset, stride, chunk_size, request_size, file_size, msg_data
): ):
self.request = functions.upload.GetFileRequest( self.request = _tl.fn.upload.GetFile(
file, offset=offset, limit=request_size) file, offset=offset, limit=request_size)
self.total = file_size self.total = file_size
@ -50,7 +49,7 @@ class _DirectDownloadIter(RequestIter):
self._sender = await self.client._borrow_exported_sender(dc_id) self._sender = await self.client._borrow_exported_sender(dc_id)
except errors.DcIdInvalidError: except errors.DcIdInvalidError:
# Can't export a sender for the ID we are currently in # Can't export a sender for the ID we are currently in
config = await self.client(functions.help.GetConfigRequest()) config = await self.client(_tl.fn.help.GetConfig())
for option in config.dc_options: for option in config.dc_options:
if option.ip_address == self.client.session.server_address: if option.ip_address == self.client.session.server_address:
self.client.session.set_dc( self.client.session.set_dc(
@ -75,7 +74,7 @@ class _DirectDownloadIter(RequestIter):
try: try:
result = await self.client._call(self._sender, self.request) result = await self.client._call(self._sender, self.request)
self._timed_out = False self._timed_out = False
if isinstance(result, types.upload.FileCdnRedirect): if isinstance(result, _tl.upload.FileCdnRedirect):
raise NotImplementedError # TODO Implement raise NotImplementedError # TODO Implement
else: else:
return result.bytes return result.bytes
@ -99,7 +98,7 @@ class _DirectDownloadIter(RequestIter):
except errors.FilerefUpgradeNeededError as e: except errors.FilerefUpgradeNeededError as e:
# Only implemented for documents which are the ones that may take that long to download # Only implemented for documents which are the ones that may take that long to download
if not self._msg_data \ if not self._msg_data \
or not isinstance(self.request.location, types.InputDocumentFileLocation) \ or not isinstance(self.request.location, _tl.InputDocumentFileLocation) \
or self.request.location.thumb_size != '': or self.request.location.thumb_size != '':
raise raise
@ -107,7 +106,7 @@ class _DirectDownloadIter(RequestIter):
chat, msg_id = self._msg_data chat, msg_id = self._msg_data
msg = await self.client.get_messages(chat, ids=msg_id) msg = await self.client.get_messages(chat, ids=msg_id)
if not isinstance(msg.media, types.MessageMediaDocument): if not isinstance(msg.media, _tl.MessageMediaDocument):
raise raise
document = msg.media.document document = msg.media.document
@ -200,7 +199,7 @@ async def download_profile_photo(
ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697) ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697)
# ('InputPeer', 'InputUser', 'InputChannel') # ('InputPeer', 'InputUser', 'InputChannel')
INPUTS = (0xc91c90b6, 0xe669bf46, 0x40f202fd) INPUTS = (0xc91c90b6, 0xe669bf46, 0x40f202fd)
if not isinstance(entity, TLObject) or entity.SUBCLASS_OF_ID in INPUTS: if not isinstance(entity, _tl.TLObject) or entity.SUBCLASS_OF_ID in INPUTS:
entity = await self.get_entity(entity) entity = await self.get_entity(entity)
thumb = -1 if download_big else 0 thumb = -1 if download_big else 0
@ -225,9 +224,9 @@ async def download_profile_photo(
photo = entity.photo photo = entity.photo
if isinstance(photo, (types.UserProfilePhoto, types.ChatPhoto)): if isinstance(photo, (_tl.UserProfilePhoto, _tl.ChatPhoto)):
dc_id = photo.dc_id dc_id = photo.dc_id
loc = types.InputPeerPhotoFileLocation( loc = _tl.InputPeerPhotoFileLocation(
peer=await self.get_input_entity(entity), peer=await self.get_input_entity(entity),
photo_id=photo.photo_id, photo_id=photo.photo_id,
big=download_big big=download_big
@ -253,7 +252,7 @@ async def download_profile_photo(
ie = await self.get_input_entity(entity) ie = await self.get_input_entity(entity)
ty = helpers._entity_type(ie) ty = helpers._entity_type(ie)
if ty == helpers._EntityType.CHANNEL: if ty == helpers._EntityType.CHANNEL:
full = await self(functions.channels.GetFullChannelRequest(ie)) full = await self(_tl.fn.channels.GetFullChannel(ie))
return await self._download_photo( return await self._download_photo(
full.full_chat.chat_photo, file, full.full_chat.chat_photo, file,
date=None, progress_callback=None, date=None, progress_callback=None,
@ -268,7 +267,7 @@ async def download_media(
message: 'hints.MessageLike', message: 'hints.MessageLike',
file: 'hints.FileLike' = None, file: 'hints.FileLike' = None,
*, *,
thumb: 'typing.Union[int, types.TypePhotoSize]' = None, thumb: 'typing.Union[int, _tl.TypePhotoSize]' = None,
progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]: progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]:
# Downloading large documents may be slow enough to require a new file reference # Downloading large documents may be slow enough to require a new file reference
# to be obtained mid-download. Store (input chat, message id) so that the message # to be obtained mid-download. Store (input chat, message id) so that the message
@ -276,7 +275,7 @@ async def download_media(
msg_data = None msg_data = None
# TODO This won't work for messageService # TODO This won't work for messageService
if isinstance(message, types.Message): if isinstance(message, _tl.Message):
date = message.date date = message.date
media = message.media media = message.media
msg_data = (message.input_chat, message.id) if message.input_chat else None msg_data = (message.input_chat, message.id) if message.input_chat else None
@ -287,28 +286,28 @@ async def download_media(
if isinstance(media, str): if isinstance(media, str):
media = utils.resolve_bot_file_id(media) media = utils.resolve_bot_file_id(media)
if isinstance(media, types.MessageService): if isinstance(media, _tl.MessageService):
if isinstance(message.action, if isinstance(message.action,
types.MessageActionChatEditPhoto): _tl.MessageActionChatEditPhoto):
media = media.photo media = media.photo
if isinstance(media, types.MessageMediaWebPage): if isinstance(media, _tl.MessageMediaWebPage):
if isinstance(media.webpage, types.WebPage): if isinstance(media.webpage, _tl.WebPage):
media = media.webpage.document or media.webpage.photo media = media.webpage.document or media.webpage.photo
if isinstance(media, (types.MessageMediaPhoto, types.Photo)): if isinstance(media, (_tl.MessageMediaPhoto, _tl.Photo)):
return await self._download_photo( return await self._download_photo(
media, file, date, thumb, progress_callback media, file, date, thumb, progress_callback
) )
elif isinstance(media, (types.MessageMediaDocument, types.Document)): elif isinstance(media, (_tl.MessageMediaDocument, _tl.Document)):
return await self._download_document( return await self._download_document(
media, file, date, thumb, progress_callback, msg_data media, file, date, thumb, progress_callback, msg_data
) )
elif isinstance(media, types.MessageMediaContact) and thumb is None: elif isinstance(media, _tl.MessageMediaContact) and thumb is None:
return self._download_contact( return self._download_contact(
media, file media, file
) )
elif isinstance(media, (types.WebDocument, types.WebDocumentNoProxy)) and thumb is None: elif isinstance(media, (_tl.WebDocument, _tl.WebDocumentNoProxy)) and thumb is None:
return await self._download_web_document( return await self._download_web_document(
media, file, progress_callback media, file, progress_callback
) )
@ -488,15 +487,15 @@ def _get_thumb(thumbs, thumb):
# last while this is the smallest (layer 116). Ensure we have the # last while this is the smallest (layer 116). Ensure we have the
# sizes sorted correctly with a custom function. # sizes sorted correctly with a custom function.
def sort_thumbs(thumb): def sort_thumbs(thumb):
if isinstance(thumb, types.PhotoStrippedSize): if isinstance(thumb, _tl.PhotoStrippedSize):
return 1, len(thumb.bytes) return 1, len(thumb.bytes)
if isinstance(thumb, types.PhotoCachedSize): if isinstance(thumb, _tl.PhotoCachedSize):
return 1, len(thumb.bytes) return 1, len(thumb.bytes)
if isinstance(thumb, types.PhotoSize): if isinstance(thumb, _tl.PhotoSize):
return 1, thumb.size return 1, thumb.size
if isinstance(thumb, types.PhotoSizeProgressive): if isinstance(thumb, _tl.PhotoSizeProgressive):
return 1, max(thumb.sizes) return 1, max(thumb.sizes)
if isinstance(thumb, types.VideoSize): if isinstance(thumb, _tl.VideoSize):
return 2, thumb.size return 2, thumb.size
# Empty size or invalid should go last # Empty size or invalid should go last
@ -508,7 +507,7 @@ def _get_thumb(thumbs, thumb):
# :tl:`PhotoPathSize` is used for animated stickers preview, and the thumb is actually # :tl:`PhotoPathSize` is used for animated stickers preview, and the thumb is actually
# a SVG path of the outline. Users expect thumbnails to be JPEG files, so pretend this # a SVG path of the outline. Users expect thumbnails to be JPEG files, so pretend this
# thumb size doesn't actually exist (#1655). # thumb size doesn't actually exist (#1655).
if isinstance(thumbs[i], types.PhotoPathSize): if isinstance(thumbs[i], _tl.PhotoPathSize):
thumbs.pop(i) thumbs.pop(i)
if thumb is None: if thumb is None:
@ -517,15 +516,15 @@ def _get_thumb(thumbs, thumb):
return thumbs[thumb] return thumbs[thumb]
elif isinstance(thumb, str): elif isinstance(thumb, str):
return next((t for t in thumbs if t.type == thumb), None) return next((t for t in thumbs if t.type == thumb), None)
elif isinstance(thumb, (types.PhotoSize, types.PhotoCachedSize, elif isinstance(thumb, (_tl.PhotoSize, _tl.PhotoCachedSize,
types.PhotoStrippedSize, types.VideoSize)): _tl.PhotoStrippedSize, _tl.VideoSize)):
return thumb return thumb
else: else:
return None return None
def _download_cached_photo_size(self: 'TelegramClient', size, file): def _download_cached_photo_size(self: 'TelegramClient', size, file):
# No need to download anything, simply write the bytes # No need to download anything, simply write the bytes
if isinstance(size, types.PhotoStrippedSize): if isinstance(size, _tl.PhotoStrippedSize):
data = utils.stripped_photo_to_jpg(size.bytes) data = utils.stripped_photo_to_jpg(size.bytes)
else: else:
data = size.bytes data = size.bytes
@ -548,31 +547,31 @@ def _download_cached_photo_size(self: 'TelegramClient', size, file):
async def _download_photo(self: 'TelegramClient', photo, file, date, thumb, progress_callback): async def _download_photo(self: 'TelegramClient', photo, file, date, thumb, progress_callback):
"""Specialized version of .download_media() for photos""" """Specialized version of .download_media() for photos"""
# Determine the photo and its largest size # Determine the photo and its largest size
if isinstance(photo, types.MessageMediaPhoto): if isinstance(photo, _tl.MessageMediaPhoto):
photo = photo.photo photo = photo.photo
if not isinstance(photo, types.Photo): if not isinstance(photo, _tl.Photo):
return return
# Include video sizes here (but they may be None so provide an empty list) # Include video sizes here (but they may be None so provide an empty list)
size = self._get_thumb(photo.sizes + (photo.video_sizes or []), thumb) size = self._get_thumb(photo.sizes + (photo.video_sizes or []), thumb)
if not size or isinstance(size, types.PhotoSizeEmpty): if not size or isinstance(size, _tl.PhotoSizeEmpty):
return return
if isinstance(size, types.VideoSize): if isinstance(size, _tl.VideoSize):
file = self._get_proper_filename(file, 'video', '.mp4', date=date) file = self._get_proper_filename(file, 'video', '.mp4', date=date)
else: else:
file = self._get_proper_filename(file, 'photo', '.jpg', date=date) file = self._get_proper_filename(file, 'photo', '.jpg', date=date)
if isinstance(size, (types.PhotoCachedSize, types.PhotoStrippedSize)): if isinstance(size, (_tl.PhotoCachedSize, _tl.PhotoStrippedSize)):
return self._download_cached_photo_size(size, file) return self._download_cached_photo_size(size, file)
if isinstance(size, types.PhotoSizeProgressive): if isinstance(size, _tl.PhotoSizeProgressive):
file_size = max(size.sizes) file_size = max(size.sizes)
else: else:
file_size = size.size file_size = size.size
result = await self.download_file( result = await self.download_file(
types.InputPhotoFileLocation( _tl.InputPhotoFileLocation(
id=photo.id, id=photo.id,
access_hash=photo.access_hash, access_hash=photo.access_hash,
file_reference=photo.file_reference, file_reference=photo.file_reference,
@ -589,10 +588,10 @@ def _get_kind_and_names(attributes):
kind = 'document' kind = 'document'
possible_names = [] possible_names = []
for attr in attributes: for attr in attributes:
if isinstance(attr, types.DocumentAttributeFilename): if isinstance(attr, _tl.DocumentAttributeFilename):
possible_names.insert(0, attr.file_name) possible_names.insert(0, attr.file_name)
elif isinstance(attr, types.DocumentAttributeAudio): elif isinstance(attr, _tl.DocumentAttributeAudio):
kind = 'audio' kind = 'audio'
if attr.performer and attr.title: if attr.performer and attr.title:
possible_names.append('{} - {}'.format( possible_names.append('{} - {}'.format(
@ -610,9 +609,9 @@ def _get_kind_and_names(attributes):
async def _download_document( async def _download_document(
self, document, file, date, thumb, progress_callback, msg_data): self, document, file, date, thumb, progress_callback, msg_data):
"""Specialized version of .download_media() for documents.""" """Specialized version of .download_media() for documents."""
if isinstance(document, types.MessageMediaDocument): if isinstance(document, _tl.MessageMediaDocument):
document = document.document document = document.document
if not isinstance(document, types.Document): if not isinstance(document, _tl.Document):
return return
if thumb is None: if thumb is None:
@ -625,11 +624,11 @@ async def _download_document(
else: else:
file = self._get_proper_filename(file, 'photo', '.jpg', date=date) file = self._get_proper_filename(file, 'photo', '.jpg', date=date)
size = self._get_thumb(document.thumbs, thumb) size = self._get_thumb(document.thumbs, thumb)
if isinstance(size, (types.PhotoCachedSize, types.PhotoStrippedSize)): if isinstance(size, (_tl.PhotoCachedSize, _tl.PhotoStrippedSize)):
return self._download_cached_photo_size(size, file) return self._download_cached_photo_size(size, file)
result = await self._download_file( result = await self._download_file(
types.InputDocumentFileLocation( _tl.InputDocumentFileLocation(
id=document.id, id=document.id,
access_hash=document.access_hash, access_hash=document.access_hash,
file_reference=document.file_reference, file_reference=document.file_reference,

View File

@ -2,8 +2,7 @@ import itertools
import re import re
import typing import typing
from .. import helpers, utils from .. import helpers, utils, _tl
from ..tl import types
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -25,7 +24,7 @@ async def _replace_with_mention(self: 'TelegramClient', entities, i, user):
or do nothing if it can't be found. or do nothing if it can't be found.
""" """
try: try:
entities[i] = types.InputMessageEntityMentionName( entities[i] = _tl.InputMessageEntityMentionName(
entities[i].offset, entities[i].length, entities[i].offset, entities[i].length,
await self.get_input_entity(user) await self.get_input_entity(user)
) )
@ -52,15 +51,15 @@ async def _parse_message_text(self: 'TelegramClient', message, parse_mode):
for i in reversed(range(len(msg_entities))): for i in reversed(range(len(msg_entities))):
e = msg_entities[i] e = msg_entities[i]
if isinstance(e, types.MessageEntityTextUrl): if isinstance(e, _tl.MessageEntityTextUrl):
m = re.match(r'^@|\+|tg://user\?id=(\d+)', e.url) m = re.match(r'^@|\+|tg://user\?id=(\d+)', e.url)
if m: if m:
user = int(m.group(1)) if m.group(1) else e.url user = int(m.group(1)) if m.group(1) else e.url
is_mention = await self._replace_with_mention(msg_entities, i, user) is_mention = await self._replace_with_mention(msg_entities, i, user)
if not is_mention: if not is_mention:
del msg_entities[i] del msg_entities[i]
elif isinstance(e, (types.MessageEntityMentionName, elif isinstance(e, (_tl.MessageEntityMentionName,
types.InputMessageEntityMentionName)): _tl.InputMessageEntityMentionName)):
is_mention = await self._replace_with_mention(msg_entities, i, e.user_id) is_mention = await self._replace_with_mention(msg_entities, i, e.user_id)
if not is_mention: if not is_mention:
del msg_entities[i] del msg_entities[i]
@ -76,10 +75,10 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
If ``request.random_id`` is a list, this method returns a list too. If ``request.random_id`` is a list, this method returns a list too.
""" """
if isinstance(result, types.UpdateShort): if isinstance(result, _tl.UpdateShort):
updates = [result.update] updates = [result.update]
entities = {} entities = {}
elif isinstance(result, (types.Updates, types.UpdatesCombined)): elif isinstance(result, (_tl.Updates, _tl.UpdatesCombined)):
updates = result.updates updates = result.updates
entities = {utils.get_peer_id(x): x entities = {utils.get_peer_id(x): x
for x in for x in
@ -90,11 +89,11 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
random_to_id = {} random_to_id = {}
id_to_message = {} id_to_message = {}
for update in updates: for update in updates:
if isinstance(update, types.UpdateMessageID): if isinstance(update, _tl.UpdateMessageID):
random_to_id[update.random_id] = update.id random_to_id[update.random_id] = update.id
elif isinstance(update, ( elif isinstance(update, (
types.UpdateNewChannelMessage, types.UpdateNewMessage)): _tl.UpdateNewChannelMessage, _tl.UpdateNewMessage)):
update.message._finish_init(self, entities, input_chat) update.message._finish_init(self, entities, input_chat)
# Pinning a message with `updatePinnedMessage` seems to # Pinning a message with `updatePinnedMessage` seems to
@ -109,7 +108,7 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
else: else:
return update.message return update.message
elif (isinstance(update, types.UpdateEditMessage) elif (isinstance(update, _tl.UpdateEditMessage)
and helpers._entity_type(request.peer) != helpers._EntityType.CHANNEL): and helpers._entity_type(request.peer) != helpers._EntityType.CHANNEL):
update.message._finish_init(self, entities, input_chat) update.message._finish_init(self, entities, input_chat)
@ -120,26 +119,26 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
elif request.id == update.message.id: elif request.id == update.message.id:
return update.message return update.message
elif (isinstance(update, types.UpdateEditChannelMessage) elif (isinstance(update, _tl.UpdateEditChannelMessage)
and utils.get_peer_id(request.peer) == and utils.get_peer_id(request.peer) ==
utils.get_peer_id(update.message.peer_id)): utils.get_peer_id(update.message.peer_id)):
if request.id == update.message.id: if request.id == update.message.id:
update.message._finish_init(self, entities, input_chat) update.message._finish_init(self, entities, input_chat)
return update.message return update.message
elif isinstance(update, types.UpdateNewScheduledMessage): elif isinstance(update, _tl.UpdateNewScheduledMessage):
update.message._finish_init(self, entities, input_chat) update.message._finish_init(self, entities, input_chat)
# Scheduled IDs may collide with normal IDs. However, for a # Scheduled IDs may collide with normal IDs. However, for a
# single request there *shouldn't* be a mix between "some # single request there *shouldn't* be a mix between "some
# scheduled and some not". # scheduled and some not".
id_to_message[update.message.id] = update.message id_to_message[update.message.id] = update.message
elif isinstance(update, types.UpdateMessagePoll): elif isinstance(update, _tl.UpdateMessagePoll):
if request.media.poll.id == update.poll_id: if request.media.poll.id == update.poll_id:
m = types.Message( m = _tl.Message(
id=request.id, id=request.id,
peer_id=utils.get_peer(request.peer), peer_id=utils.get_peer(request.peer),
media=types.MessageMediaPoll( media=_tl.MessageMediaPoll(
poll=update.poll, poll=update.poll,
results=update.results results=update.results
) )

View File

@ -3,9 +3,8 @@ import itertools
import typing import typing
import warnings import warnings
from .. import helpers, utils, errors, hints from .. import helpers, utils, errors, hints, _tl
from ..requestiter import RequestIter from ..requestiter import RequestIter
from ..tl import types, functions
_MAX_CHUNK_SIZE = 100 _MAX_CHUNK_SIZE = 100
@ -67,31 +66,31 @@ class _MessagesIter(RequestIter):
# If we want to perform global a search with `from_user` we have to perform # If we want to perform global a search with `from_user` we have to perform
# a normal `messages.search`, *but* we can make the entity be `inputPeerEmpty`. # a normal `messages.search`, *but* we can make the entity be `inputPeerEmpty`.
if not self.entity and from_user: if not self.entity and from_user:
self.entity = types.InputPeerEmpty() self.entity = _tl.InputPeerEmpty()
if filter is None: if filter is None:
filter = types.InputMessagesFilterEmpty() filter = _tl.InputMessagesFilterEmpty()
else: else:
filter = filter() if isinstance(filter, type) else filter filter = filter() if isinstance(filter, type) else filter
if not self.entity: if not self.entity:
self.request = functions.messages.SearchGlobalRequest( self.request = _tl.fn.messages.SearchGlobal(
q=search or '', q=search or '',
filter=filter, filter=filter,
min_date=None, min_date=None,
max_date=offset_date, max_date=offset_date,
offset_rate=0, offset_rate=0,
offset_peer=types.InputPeerEmpty(), offset_peer=_tl.InputPeerEmpty(),
offset_id=offset_id, offset_id=offset_id,
limit=1 limit=1
) )
elif scheduled: elif scheduled:
self.request = functions.messages.GetScheduledHistoryRequest( self.request = _tl.fn.messages.GetScheduledHistory(
peer=entity, peer=entity,
hash=0 hash=0
) )
elif reply_to is not None: elif reply_to is not None:
self.request = functions.messages.GetRepliesRequest( self.request = _tl.fn.messages.GetReplies(
peer=self.entity, peer=self.entity,
msg_id=reply_to, msg_id=reply_to,
offset_id=offset_id, offset_id=offset_id,
@ -102,7 +101,7 @@ class _MessagesIter(RequestIter):
min_id=0, min_id=0,
hash=0 hash=0
) )
elif search is not None or not isinstance(filter, types.InputMessagesFilterEmpty) or from_user: elif search is not None or not isinstance(filter, _tl.InputMessagesFilterEmpty) or from_user:
# Telegram completely ignores `from_id` in private chats # Telegram completely ignores `from_id` in private chats
ty = helpers._entity_type(self.entity) ty = helpers._entity_type(self.entity)
if ty == helpers._EntityType.USER: if ty == helpers._EntityType.USER:
@ -114,7 +113,7 @@ class _MessagesIter(RequestIter):
# and set `from_id` to None to avoid checking it locally. # and set `from_id` to None to avoid checking it locally.
self.from_id = None self.from_id = None
self.request = functions.messages.SearchRequest( self.request = _tl.fn.messages.Search(
peer=self.entity, peer=self.entity,
q=search or '', q=search or '',
filter=filter, filter=filter,
@ -136,13 +135,13 @@ class _MessagesIter(RequestIter):
# #
# Even better, using `filter` and `from_id` seems to always # Even better, using `filter` and `from_id` seems to always
# trigger `RPC_CALL_FAIL` which is "internal issues"... # trigger `RPC_CALL_FAIL` which is "internal issues"...
if not isinstance(filter, types.InputMessagesFilterEmpty) \ if not isinstance(filter, _tl.InputMessagesFilterEmpty) \
and offset_date and not search and not offset_id: and offset_date and not search and not offset_id:
async for m in self.client.iter_messages( async for m in self.client.iter_messages(
self.entity, 1, offset_date=offset_date): self.entity, 1, offset_date=offset_date):
self.request.offset_id = m.id + 1 self.request.offset_id = m.id + 1
else: else:
self.request = functions.messages.GetHistoryRequest( self.request = _tl.fn.messages.GetHistory(
peer=self.entity, peer=self.entity,
limit=1, limit=1,
offset_date=offset_date, offset_date=offset_date,
@ -156,7 +155,7 @@ class _MessagesIter(RequestIter):
if self.limit <= 0: if self.limit <= 0:
# No messages, but we still need to know the total message count # No messages, but we still need to know the total message count
result = await self.client(self.request) result = await self.client(self.request)
if isinstance(result, types.messages.MessagesNotModified): if isinstance(result, _tl.messages.MessagesNotModified):
self.total = result.count self.total = result.count
else: else:
self.total = getattr(result, 'count', len(result.messages)) self.total = getattr(result, 'count', len(result.messages))
@ -189,7 +188,7 @@ class _MessagesIter(RequestIter):
messages = reversed(r.messages) if self.reverse else r.messages messages = reversed(r.messages) if self.reverse else r.messages
for message in messages: for message in messages:
if (isinstance(message, types.MessageEmpty) if (isinstance(message, _tl.MessageEmpty)
or self.from_id and message.sender_id != self.from_id): or self.from_id and message.sender_id != self.from_id):
continue continue
@ -245,7 +244,7 @@ class _MessagesIter(RequestIter):
# We want to skip the one we already have # We want to skip the one we already have
self.request.offset_id += 1 self.request.offset_id += 1
if isinstance(self.request, functions.messages.SearchRequest): if isinstance(self.request, _tl.fn.messages.SearchRequest):
# Unlike getHistory and searchGlobal that use *offset* date, # Unlike getHistory and searchGlobal that use *offset* date,
# this is *max* date. This means that doing a search in reverse # this is *max* date. This means that doing a search in reverse
# will break it. Since it's not really needed once we're going # will break it. Since it's not really needed once we're going
@ -255,11 +254,11 @@ class _MessagesIter(RequestIter):
# getHistory, searchGlobal and getReplies call it offset_date # getHistory, searchGlobal and getReplies call it offset_date
self.request.offset_date = last_message.date self.request.offset_date = last_message.date
if isinstance(self.request, functions.messages.SearchGlobalRequest): if isinstance(self.request, _tl.fn.messages.SearchGlobalRequest):
if last_message.input_chat: if last_message.input_chat:
self.request.offset_peer = last_message.input_chat self.request.offset_peer = last_message.input_chat
else: else:
self.request.offset_peer = types.InputPeerEmpty() self.request.offset_peer = _tl.InputPeerEmpty()
self.request.offset_rate = getattr(response, 'next_rate', 0) self.request.offset_rate = getattr(response, 'next_rate', 0)
@ -287,16 +286,16 @@ class _IDsIter(RequestIter):
if self._ty == helpers._EntityType.CHANNEL: if self._ty == helpers._EntityType.CHANNEL:
try: try:
r = await self.client( r = await self.client(
functions.channels.GetMessagesRequest(self._entity, ids)) _tl.fn.channels.GetMessages(self._entity, ids))
except errors.MessageIdsEmptyError: except errors.MessageIdsEmptyError:
# All IDs were invalid, use a dummy result # All IDs were invalid, use a dummy result
r = types.messages.MessagesNotModified(len(ids)) r = _tl.messages.MessagesNotModified(len(ids))
else: else:
r = await self.client(functions.messages.GetMessagesRequest(ids)) r = await self.client(_tl.fn.messages.GetMessages(ids))
if self._entity: if self._entity:
from_id = await self.client._get_peer(self._entity) from_id = await self.client._get_peer(self._entity)
if isinstance(r, types.messages.MessagesNotModified): if isinstance(r, _tl.messages.MessagesNotModified):
self.buffer.extend(None for _ in ids) self.buffer.extend(None for _ in ids)
return return
@ -312,7 +311,7 @@ class _IDsIter(RequestIter):
# since the user can enter arbitrary numbers which can belong to # since the user can enter arbitrary numbers which can belong to
# arbitrary chats. Validate these unless ``from_id is None``. # arbitrary chats. Validate these unless ``from_id is None``.
for message in r.messages: for message in r.messages:
if isinstance(message, types.MessageEmpty) or ( if isinstance(message, _tl.MessageEmpty) or (
from_id and message.peer_id != from_id): from_id and message.peer_id != from_id):
self.buffer.append(None) self.buffer.append(None)
else: else:
@ -331,7 +330,7 @@ def iter_messages(
min_id: int = 0, min_id: int = 0,
add_offset: int = 0, add_offset: int = 0,
search: str = None, search: str = None,
filter: 'typing.Union[types.TypeMessagesFilter, typing.Type[types.TypeMessagesFilter]]' = None, filter: 'typing.Union[_tl.TypeMessagesFilter, typing.Type[_tl.TypeMessagesFilter]]' = None,
from_user: 'hints.EntityLike' = None, from_user: 'hints.EntityLike' = None,
wait_time: float = None, wait_time: float = None,
ids: 'typing.Union[int, typing.Sequence[int]]' = None, ids: 'typing.Union[int, typing.Sequence[int]]' = None,
@ -393,9 +392,9 @@ async def get_messages(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalL
async def _get_comment_data( async def _get_comment_data(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message: 'typing.Union[int, types.Message]' message: 'typing.Union[int, _tl.Message]'
): ):
r = await self(functions.messages.GetDiscussionMessageRequest( r = await self(_tl.fn.messages.GetDiscussionMessage(
peer=entity, peer=entity,
msg_id=utils.get_message_id(message) msg_id=utils.get_message_id(message)
)) ))
@ -408,10 +407,10 @@ async def send_message(
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message: 'hints.MessageLike' = '', message: 'hints.MessageLike' = '',
*, *,
reply_to: 'typing.Union[int, types.Message]' = None, reply_to: 'typing.Union[int, _tl.Message]' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
parse_mode: typing.Optional[str] = (), parse_mode: typing.Optional[str] = (),
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
link_preview: bool = True, link_preview: bool = True,
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None, file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
@ -422,8 +421,8 @@ async def send_message(
background: bool = None, background: bool = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None comment_to: 'typing.Union[int, _tl.Message]' = None
) -> 'types.Message': ) -> '_tl.Message':
if file is not None: if file is not None:
return await self.send_file( return await self.send_file(
entity, file, caption=message, reply_to=reply_to, entity, file, caption=message, reply_to=reply_to,
@ -439,7 +438,7 @@ async def send_message(
if comment_to is not None: if comment_to is not None:
entity, reply_to = await self._get_comment_data(entity, comment_to) entity, reply_to = await self._get_comment_data(entity, comment_to)
if isinstance(message, types.Message): if isinstance(message, _tl.Message):
if buttons is None: if buttons is None:
markup = message.reply_markup markup = message.reply_markup
else: else:
@ -449,7 +448,7 @@ async def send_message(
silent = message.silent silent = message.silent
if (message.media and not isinstance( if (message.media and not isinstance(
message.media, types.MessageMediaWebPage)): message.media, _tl.MessageMediaWebPage)):
return await self.send_file( return await self.send_file(
entity, entity,
message.media, message.media,
@ -462,7 +461,7 @@ async def send_message(
schedule=schedule schedule=schedule
) )
request = functions.messages.SendMessageRequest( request = _tl.fn.messages.SendMessage(
peer=entity, peer=entity,
message=message.message or '', message=message.message or '',
silent=silent, silent=silent,
@ -472,7 +471,7 @@ async def send_message(
entities=message.entities, entities=message.entities,
clear_draft=clear_draft, clear_draft=clear_draft,
no_webpage=not isinstance( no_webpage=not isinstance(
message.media, types.MessageMediaWebPage), message.media, _tl.MessageMediaWebPage),
schedule_date=schedule schedule_date=schedule
) )
message = message.message message = message.message
@ -484,7 +483,7 @@ async def send_message(
'The message cannot be empty unless a file is provided' 'The message cannot be empty unless a file is provided'
) )
request = functions.messages.SendMessageRequest( request = _tl.fn.messages.SendMessage(
peer=entity, peer=entity,
message=message, message=message,
entities=formatting_entities, entities=formatting_entities,
@ -498,8 +497,8 @@ async def send_message(
) )
result = await self(request) result = await self(request)
if isinstance(result, types.UpdateShortSentMessage): if isinstance(result, _tl.UpdateShortSentMessage):
message = types.Message( message = _tl.Message(
id=result.id, id=result.id,
peer_id=await self._get_peer(entity), peer_id=await self._get_peer(entity),
message=message, message=message,
@ -526,7 +525,7 @@ async def forward_messages(
silent: bool = None, silent: bool = None,
as_album: bool = None, as_album: bool = None,
schedule: 'hints.DateLike' = None schedule: 'hints.DateLike' = None
) -> 'typing.Sequence[types.Message]': ) -> 'typing.Sequence[_tl.Message]':
if as_album is not None: if as_album is not None:
warnings.warn('the as_album argument is deprecated and no longer has any effect') warnings.warn('the as_album argument is deprecated and no longer has any effect')
@ -548,7 +547,7 @@ async def forward_messages(
return from_peer_id return from_peer_id
raise ValueError('from_peer must be given if integer IDs are used') raise ValueError('from_peer must be given if integer IDs are used')
elif isinstance(m, types.Message): elif isinstance(m, _tl.Message):
return m.chat_id return m.chat_id
else: else:
raise TypeError('Cannot forward messages of type {}'.format(type(m))) raise TypeError('Cannot forward messages of type {}'.format(type(m)))
@ -562,7 +561,7 @@ async def forward_messages(
chat = await chunk[0].get_input_chat() chat = await chunk[0].get_input_chat()
chunk = [m.id for m in chunk] chunk = [m.id for m in chunk]
req = functions.messages.ForwardMessagesRequest( req = _tl.fn.messages.ForwardMessages(
from_peer=chat, from_peer=chat,
id=chunk, id=chunk,
to_peer=entity, to_peer=entity,
@ -578,13 +577,13 @@ async def forward_messages(
async def edit_message( async def edit_message(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'typing.Union[hints.EntityLike, types.Message]', entity: 'typing.Union[hints.EntityLike, _tl.Message]',
message: 'hints.MessageLike' = None, message: 'hints.MessageLike' = None,
text: str = None, text: str = None,
*, *,
parse_mode: str = (), parse_mode: str = (),
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
link_preview: bool = True, link_preview: bool = True,
file: 'hints.FileLike' = None, file: 'hints.FileLike' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
@ -592,11 +591,11 @@ async def edit_message(
buttons: 'hints.MarkupLike' = None, buttons: 'hints.MarkupLike' = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None schedule: 'hints.DateLike' = None
) -> 'types.Message': ) -> '_tl.Message':
if isinstance(entity, types.InputBotInlineMessageID): if isinstance(entity, _tl.InputBotInlineMessageID):
text = text or message text = text or message
message = entity message = entity
elif isinstance(entity, types.Message): elif isinstance(entity, _tl.Message):
text = message # Shift the parameters to the right text = message # Shift the parameters to the right
message = entity message = entity
entity = entity.peer_id entity = entity.peer_id
@ -609,8 +608,8 @@ async def edit_message(
attributes=attributes, attributes=attributes,
force_document=force_document) force_document=force_document)
if isinstance(entity, types.InputBotInlineMessageID): if isinstance(entity, _tl.InputBotInlineMessageID):
request = functions.messages.EditInlineBotMessageRequest( request = _tl.fn.messages.EditInlineBotMessage(
id=entity, id=entity,
message=text, message=text,
no_webpage=not link_preview, no_webpage=not link_preview,
@ -631,7 +630,7 @@ async def edit_message(
return await self(request) return await self(request)
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
request = functions.messages.EditMessageRequest( request = _tl.fn.messages.EditMessage(
peer=entity, peer=entity,
id=utils.get_message_id(message), id=utils.get_message_id(message),
message=text, message=text,
@ -649,13 +648,13 @@ async def delete_messages(
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message_ids: 'typing.Union[hints.MessageIDLike, typing.Sequence[hints.MessageIDLike]]', message_ids: 'typing.Union[hints.MessageIDLike, typing.Sequence[hints.MessageIDLike]]',
*, *,
revoke: bool = True) -> 'typing.Sequence[types.messages.AffectedMessages]': revoke: bool = True) -> 'typing.Sequence[_tl.messages.AffectedMessages]':
if not utils.is_list_like(message_ids): if not utils.is_list_like(message_ids):
message_ids = (message_ids,) message_ids = (message_ids,)
message_ids = ( message_ids = (
m.id if isinstance(m, ( m.id if isinstance(m, (
types.Message, types.MessageService, types.MessageEmpty)) _tl.Message, _tl.MessageService, _tl.MessageEmpty))
else int(m) for m in message_ids else int(m) for m in message_ids
) )
@ -667,10 +666,10 @@ async def delete_messages(
ty = helpers._EntityType.USER ty = helpers._EntityType.USER
if ty == helpers._EntityType.CHANNEL: if ty == helpers._EntityType.CHANNEL:
return await self([functions.channels.DeleteMessagesRequest( return await self([_tl.fn.channels.DeleteMessages(
entity, list(c)) for c in utils.chunks(message_ids)]) entity, list(c)) for c in utils.chunks(message_ids)])
else: else:
return await self([functions.messages.DeleteMessagesRequest( return await self([_tl.fn.messages.DeleteMessages(
list(c), revoke) for c in utils.chunks(message_ids)]) list(c), revoke) for c in utils.chunks(message_ids)])
async def send_read_acknowledge( async def send_read_acknowledge(
@ -691,16 +690,16 @@ async def send_read_acknowledge(
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
if clear_mentions: if clear_mentions:
await self(functions.messages.ReadMentionsRequest(entity)) await self(_tl.fn.messages.ReadMentions(entity))
if max_id is None: if max_id is None:
return True return True
if max_id is not None: if max_id is not None:
if helpers._entity_type(entity) == helpers._EntityType.CHANNEL: if helpers._entity_type(entity) == helpers._EntityType.CHANNEL:
return await self(functions.channels.ReadHistoryRequest( return await self(_tl.fn.channels.ReadHistory(
utils.get_input_channel(entity), max_id=max_id)) utils.get_input_channel(entity), max_id=max_id))
else: else:
return await self(functions.messages.ReadHistoryRequest( return await self(_tl.fn.messages.ReadHistory(
entity, max_id=max_id)) entity, max_id=max_id))
return False return False
@ -728,10 +727,10 @@ async def _pin(self, entity, message, *, unpin, notify=False, pm_oneside=False):
message = utils.get_message_id(message) or 0 message = utils.get_message_id(message) or 0
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
if message <= 0: # old behaviour accepted negative IDs to unpin if message <= 0: # old behaviour accepted negative IDs to unpin
await self(functions.messages.UnpinAllMessagesRequest(entity)) await self(_tl.fn.messages.UnpinAllMessages(entity))
return return
request = functions.messages.UpdatePinnedMessageRequest( request = _tl.fn.messages.UpdatePinnedMessage(
peer=entity, peer=entity,
id=message, id=message,
silent=not notify, silent=not notify,

View File

@ -7,15 +7,13 @@ import platform
import time import time
import typing import typing
from .. import version, helpers, __name__ as __base_name__ from .. import version, helpers, __name__ as __base_name__, _tl
from ..crypto import rsa from ..crypto import rsa
from ..entitycache import EntityCache from ..entitycache import EntityCache
from ..extensions import markdown from ..extensions import markdown
from ..network import MTProtoSender, Connection, ConnectionTcpFull, TcpMTProxy from ..network import MTProtoSender, Connection, ConnectionTcpFull, TcpMTProxy
from ..sessions import Session, SQLiteSession, MemorySession from ..sessions import Session, SQLiteSession, MemorySession
from ..statecache import StateCache from ..statecache import StateCache
from ..tl import functions, types
from ..tl.alltlobjects import LAYER
DEFAULT_DC_ID = 2 DEFAULT_DC_ID = 2
DEFAULT_IPV4_IP = '149.154.167.51' DEFAULT_IPV4_IP = '149.154.167.51'
@ -122,7 +120,7 @@ def init(
import warnings import warnings
warnings.warn( warnings.warn(
'The sqlite3 module is not available under this ' 'The sqlite3 module is not available under this '
'Python installation and no custom session ' 'Python installation and no _ session '
'instance was given; using MemorySession.\n' 'instance was given; using MemorySession.\n'
'You will need to re-login every time unless ' 'You will need to re-login every time unless '
'you use another session storage' 'you use another session storage'
@ -198,7 +196,7 @@ def init(
assert isinstance(connection, type) assert isinstance(connection, type)
self._connection = connection self._connection = connection
init_proxy = None if not issubclass(connection, TcpMTProxy) else \ init_proxy = None if not issubclass(connection, TcpMTProxy) else \
types.InputClientProxy(*connection.address_info(proxy)) _tl.InputClientProxy(*connection.address_info(proxy))
# Used on connection. Capture the variables in a lambda since # Used on connection. Capture the variables in a lambda since
# exporting clients need to create this InvokeWithLayerRequest. # exporting clients need to create this InvokeWithLayerRequest.
@ -212,7 +210,7 @@ def init(
default_device_model = system.machine default_device_model = system.machine
default_system_version = re.sub(r'-.+','',system.release) default_system_version = re.sub(r'-.+','',system.release)
self._init_request = functions.InitConnectionRequest( self._init_request = _tl.fn.InitConnection(
api_id=self.api_id, api_id=self.api_id,
device_model=device_model or default_device_model or 'Unknown', device_model=device_model or default_device_model or 'Unknown',
system_version=system_version or default_system_version or '1.0', system_version=system_version or default_system_version or '1.0',
@ -322,10 +320,10 @@ async def connect(self: 'TelegramClient') -> None:
self.session.auth_key = self._sender.auth_key self.session.auth_key = self._sender.auth_key
self.session.save() self.session.save()
self._init_request.query = functions.help.GetConfigRequest() self._init_request.query = _tl.fn.help.GetConfig()
await self._sender.send(functions.InvokeWithLayerRequest( await self._sender.send(_tl.fn.InvokeWithLayer(
LAYER, self._init_request _tl.alltlobjects.LAYER, self._init_request
)) ))
self._updates_handle = self.loop.create_task(self._update_loop()) self._updates_handle = self.loop.create_task(self._update_loop())
@ -339,7 +337,7 @@ async def disconnect(self: 'TelegramClient'):
def set_proxy(self: 'TelegramClient', proxy: typing.Union[tuple, dict]): def set_proxy(self: 'TelegramClient', proxy: typing.Union[tuple, dict]):
init_proxy = None if not issubclass(self._connection, TcpMTProxy) else \ init_proxy = None if not issubclass(self._connection, TcpMTProxy) else \
types.InputClientProxy(*self._connection.address_info(proxy)) _tl.InputClientProxy(*self._connection.address_info(proxy))
self._init_request.proxy = init_proxy self._init_request.proxy = init_proxy
self._proxy = proxy self._proxy = proxy
@ -386,7 +384,7 @@ async def _disconnect_coro(self: 'TelegramClient'):
pts, date = self._state_cache[None] pts, date = self._state_cache[None]
if pts and date: if pts and date:
self.session.set_update_state(0, types.updates.State( self.session.set_update_state(0, _tl.updates.State(
pts=pts, pts=pts,
qts=0, qts=0,
date=date, date=date,
@ -436,10 +434,10 @@ async def _get_dc(self: 'TelegramClient', dc_id, cdn=False):
"""Gets the Data Center (DC) associated to 'dc_id'""" """Gets the Data Center (DC) associated to 'dc_id'"""
cls = self.__class__ cls = self.__class__
if not cls._config: if not cls._config:
cls._config = await self(functions.help.GetConfigRequest()) cls._config = await self(_tl.fn.help.GetConfig())
if cdn and not self._cdn_config: if cdn and not self._cdn_config:
cls._cdn_config = await self(functions.help.GetCdnConfigRequest()) cls._cdn_config = await self(_tl.fn.help.GetCdnConfig())
for pk in cls._cdn_config.public_keys: for pk in cls._cdn_config.public_keys:
rsa.add_key(pk.public_key) rsa.add_key(pk.public_key)
@ -481,9 +479,9 @@ async def _create_exported_sender(self: 'TelegramClient', dc_id):
local_addr=self._local_addr local_addr=self._local_addr
)) ))
self._log[__name__].info('Exporting auth for new borrowed sender in %s', dc) self._log[__name__].info('Exporting auth for new borrowed sender in %s', dc)
auth = await self(functions.auth.ExportAuthorizationRequest(dc_id)) auth = await self(_tl.fn.auth.ExportAuthorization(dc_id))
self._init_request.query = functions.auth.ImportAuthorizationRequest(id=auth.id, bytes=auth.bytes) self._init_request.query = _tl.fn.auth.ImportAuthorization(id=auth.id, bytes=auth.bytes)
req = functions.InvokeWithLayerRequest(LAYER, self._init_request) req = _tl.fn.InvokeWithLayer(LAYER, self._init_request)
await sender.send(req) await sender.send(req)
return sender return sender

View File

@ -8,8 +8,7 @@ from . import (
account, auth, bots, buttons, chats, dialogs, downloads, messageparse, messages, account, auth, bots, buttons, chats, dialogs, downloads, messageparse, messages,
telegrambaseclient, updates, uploads, users telegrambaseclient, updates, uploads, users
) )
from .. import helpers, version from .. import helpers, version, _tl
from ..tl import types, custom
from ..network import ConnectionTcpFull from ..network import ConnectionTcpFull
from ..events.common import EventBuilder, EventCommon from ..events.common import EventBuilder, EventCommon
@ -369,7 +368,7 @@ class TelegramClient:
*, *,
password: str = None, password: str = None,
bot_token: str = None, bot_token: str = None,
phone_code_hash: str = None) -> 'typing.Union[types.User, types.auth.SentCode]': phone_code_hash: str = None) -> 'typing.Union[_tl.User, _tl.auth.SentCode]':
""" """
Logs in to Telegram to an existing user or bot account. Logs in to Telegram to an existing user or bot account.
@ -428,7 +427,7 @@ class TelegramClient:
last_name: str = '', last_name: str = '',
*, *,
phone: str = None, phone: str = None,
phone_code_hash: str = None) -> 'types.User': phone_code_hash: str = None) -> '_tl.User':
""" """
Signs up to Telegram as a new user account. Signs up to Telegram as a new user account.
@ -477,7 +476,7 @@ class TelegramClient:
self: 'TelegramClient', self: 'TelegramClient',
phone: str, phone: str,
*, *,
force_sms: bool = False) -> 'types.auth.SentCode': force_sms: bool = False) -> '_tl.auth.SentCode':
""" """
Sends the Telegram code needed to login to the given phone number. Sends the Telegram code needed to login to the given phone number.
@ -630,7 +629,7 @@ class TelegramClient:
*, *,
entity: 'hints.EntityLike' = None, entity: 'hints.EntityLike' = None,
offset: str = None, offset: str = None,
geo_point: 'types.GeoPoint' = None) -> custom.InlineResults: geo_point: '_tl.GeoPoint' = None) -> custom.InlineResults:
""" """
Makes an inline query to the specified bot (``@vote New Poll``). Makes an inline query to the specified bot (``@vote New Poll``).
@ -679,7 +678,7 @@ class TelegramClient:
@staticmethod @staticmethod
def build_reply_markup( def build_reply_markup(
buttons: 'typing.Optional[hints.MarkupLike]', buttons: 'typing.Optional[hints.MarkupLike]',
inline_only: bool = False) -> 'typing.Optional[types.TypeReplyMarkup]': inline_only: bool = False) -> 'typing.Optional[_tl.TypeReplyMarkup]':
""" """
Builds a :tl:`ReplyInlineMarkup` or :tl:`ReplyKeyboardMarkup` for Builds a :tl:`ReplyInlineMarkup` or :tl:`ReplyKeyboardMarkup` for
the given buttons. the given buttons.
@ -722,7 +721,7 @@ class TelegramClient:
limit: float = None, limit: float = None,
*, *,
search: str = '', search: str = '',
filter: 'types.TypeChannelParticipantsFilter' = None, filter: '_tl.TypeChannelParticipantsFilter' = None,
aggressive: bool = False) -> chats._ParticipantsIter: aggressive: bool = False) -> chats._ParticipantsIter:
""" """
Iterator over the participants belonging to the specified chat. Iterator over the participants belonging to the specified chat.
@ -1018,7 +1017,7 @@ class TelegramClient:
def action( def action(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
action: 'typing.Union[str, types.TypeSendMessageAction]', action: 'typing.Union[str, _tl.TypeSendMessageAction]',
*, *,
delay: float = 4, delay: float = 4,
auto_cancel: bool = True) -> 'typing.Union[_ChatAction, typing.Coroutine]': auto_cancel: bool = True) -> 'typing.Union[_ChatAction, typing.Coroutine]':
@ -1109,7 +1108,7 @@ class TelegramClient:
manage_call: bool = None, manage_call: bool = None,
anonymous: bool = None, anonymous: bool = None,
is_admin: bool = None, is_admin: bool = None,
title: str = None) -> types.Updates: title: str = None) -> _tl.Updates:
""" """
Edits admin permissions for someone in a chat. Edits admin permissions for someone in a chat.
@ -1216,7 +1215,7 @@ class TelegramClient:
send_polls: bool = True, send_polls: bool = True,
change_info: bool = True, change_info: bool = True,
invite_users: bool = True, invite_users: bool = True,
pin_messages: bool = True) -> types.Updates: pin_messages: bool = True) -> _tl.Updates:
""" """
Edits user restrictions in a chat. Edits user restrictions in a chat.
@ -1396,7 +1395,7 @@ class TelegramClient:
async def get_stats( async def get_stats(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message: 'typing.Union[int, types.Message]' = None, message: 'typing.Union[int, _tl.Message]' = None,
): ):
""" """
Retrieves statistics from the given megagroup or broadcast channel. Retrieves statistics from the given megagroup or broadcast channel.
@ -1449,7 +1448,7 @@ class TelegramClient:
*, *,
offset_date: 'hints.DateLike' = None, offset_date: 'hints.DateLike' = None,
offset_id: int = 0, offset_id: int = 0,
offset_peer: 'hints.EntityLike' = types.InputPeerEmpty(), offset_peer: 'hints.EntityLike' = _tl.InputPeerEmpty(),
ignore_pinned: bool = False, ignore_pinned: bool = False,
ignore_migrated: bool = False, ignore_migrated: bool = False,
folder: int = None, folder: int = None,
@ -1604,7 +1603,7 @@ class TelegramClient:
folder: typing.Union[int, typing.Sequence[int]] = None, folder: typing.Union[int, typing.Sequence[int]] = None,
*, *,
unpack=None unpack=None
) -> types.Updates: ) -> _tl.Updates:
""" """
Edits the folder used by one or more dialogs to archive them. Edits the folder used by one or more dialogs to archive them.
@ -1756,7 +1755,7 @@ class TelegramClient:
message: 'hints.MessageLike', message: 'hints.MessageLike',
file: 'hints.FileLike' = None, file: 'hints.FileLike' = None,
*, *,
thumb: 'typing.Union[int, types.TypePhotoSize]' = None, thumb: 'typing.Union[int, _tl.TypePhotoSize]' = None,
progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]: progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]:
""" """
Downloads the given media from a message object. Downloads the given media from a message object.
@ -1850,7 +1849,7 @@ class TelegramClient:
input_location (:tl:`InputFileLocation`): input_location (:tl:`InputFileLocation`):
The file location from which the file will be downloaded. The file location from which the file will be downloaded.
See `telethon.utils.get_input_location` source for a complete See `telethon.utils.get_input_location` source for a complete
list of supported types. list of supported _tl.
file (`str` | `file`, optional): file (`str` | `file`, optional):
The output file path, directory, or stream-like object. The output file path, directory, or stream-like object.
@ -2048,7 +2047,7 @@ class TelegramClient:
min_id: int = 0, min_id: int = 0,
add_offset: int = 0, add_offset: int = 0,
search: str = None, search: str = None,
filter: 'typing.Union[types.TypeMessagesFilter, typing.Type[types.TypeMessagesFilter]]' = None, filter: 'typing.Union[_tl.TypeMessagesFilter, typing.Type[_tl.TypeMessagesFilter]]' = None,
from_user: 'hints.EntityLike' = None, from_user: 'hints.EntityLike' = None,
wait_time: float = None, wait_time: float = None,
ids: 'typing.Union[int, typing.Sequence[int]]' = None, ids: 'typing.Union[int, typing.Sequence[int]]' = None,
@ -2258,10 +2257,10 @@ class TelegramClient:
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message: 'hints.MessageLike' = '', message: 'hints.MessageLike' = '',
*, *,
reply_to: 'typing.Union[int, types.Message]' = None, reply_to: 'typing.Union[int, _tl.Message]' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
parse_mode: typing.Optional[str] = (), parse_mode: typing.Optional[str] = (),
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
link_preview: bool = True, link_preview: bool = True,
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None, file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
@ -2272,8 +2271,8 @@ class TelegramClient:
background: bool = None, background: bool = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None comment_to: 'typing.Union[int, _tl.Message]' = None
) -> 'types.Message': ) -> '_tl.Message':
""" """
Sends a message to the specified user, chat or channel. Sends a message to the specified user, chat or channel.
@ -2458,7 +2457,7 @@ class TelegramClient:
silent: bool = None, silent: bool = None,
as_album: bool = None, as_album: bool = None,
schedule: 'hints.DateLike' = None schedule: 'hints.DateLike' = None
) -> 'typing.Sequence[types.Message]': ) -> 'typing.Sequence[_tl.Message]':
""" """
Forwards the given messages to the specified entity. Forwards the given messages to the specified entity.
@ -2531,13 +2530,13 @@ class TelegramClient:
async def edit_message( async def edit_message(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'typing.Union[hints.EntityLike, types.Message]', entity: 'typing.Union[hints.EntityLike, _tl.Message]',
message: 'hints.MessageLike' = None, message: 'hints.MessageLike' = None,
text: str = None, text: str = None,
*, *,
parse_mode: str = (), parse_mode: str = (),
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
link_preview: bool = True, link_preview: bool = True,
file: 'hints.FileLike' = None, file: 'hints.FileLike' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
@ -2545,7 +2544,7 @@ class TelegramClient:
buttons: 'hints.MarkupLike' = None, buttons: 'hints.MarkupLike' = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None schedule: 'hints.DateLike' = None
) -> 'types.Message': ) -> '_tl.Message':
""" """
Edits the given message to change its text or media. Edits the given message to change its text or media.
@ -2663,7 +2662,7 @@ class TelegramClient:
entity: 'hints.EntityLike', entity: 'hints.EntityLike',
message_ids: 'typing.Union[hints.MessageIDLike, typing.Sequence[hints.MessageIDLike]]', message_ids: 'typing.Union[hints.MessageIDLike, typing.Sequence[hints.MessageIDLike]]',
*, *,
revoke: bool = True) -> 'typing.Sequence[types.messages.AffectedMessages]': revoke: bool = True) -> 'typing.Sequence[_tl.messages.AffectedMessages]':
""" """
Deletes the given messages, optionally "for everyone". Deletes the given messages, optionally "for everyone".
@ -3171,11 +3170,11 @@ class TelegramClient:
clear_draft: bool = False, clear_draft: bool = False,
progress_callback: 'hints.ProgressCallback' = None, progress_callback: 'hints.ProgressCallback' = None,
reply_to: 'hints.MessageIDLike' = None, reply_to: 'hints.MessageIDLike' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
allow_cache: bool = True, allow_cache: bool = True,
parse_mode: str = (), parse_mode: str = (),
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
voice_note: bool = False, voice_note: bool = False,
video_note: bool = False, video_note: bool = False,
buttons: 'hints.MarkupLike' = None, buttons: 'hints.MarkupLike' = None,
@ -3183,9 +3182,9 @@ class TelegramClient:
background: bool = None, background: bool = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None, comment_to: 'typing.Union[int, _tl.Message]' = None,
ttl: int = None, ttl: int = None,
**kwargs) -> 'types.Message': **kwargs) -> '_tl.Message':
""" """
Sends message with the given file to the specified entity. Sends message with the given file to the specified entity.
@ -3392,11 +3391,11 @@ class TelegramClient:
# Dices, including dart and other future emoji # Dices, including dart and other future emoji
from telethon.tl import types from telethon.tl import types
await client.send_file(chat, types.InputMediaDice('')) await client.send_file(chat, _tl.InputMediaDice(''))
await client.send_file(chat, types.InputMediaDice('🎯')) await client.send_file(chat, _tl.InputMediaDice('🎯'))
# Contacts # Contacts
await client.send_file(chat, types.InputMediaContact( await client.send_file(chat, _tl.InputMediaContact(
phone_number='+34 123 456 789', phone_number='+34 123 456 789',
first_name='Example', first_name='Example',
last_name='', last_name='',
@ -3415,7 +3414,7 @@ class TelegramClient:
use_cache: type = None, use_cache: type = None,
key: bytes = None, key: bytes = None,
iv: bytes = None, iv: bytes = None,
progress_callback: 'hints.ProgressCallback' = None) -> 'types.TypeInputFile': progress_callback: 'hints.ProgressCallback' = None) -> '_tl.TypeInputFile':
""" """
Uploads a file to Telegram's servers, without sending it. Uploads a file to Telegram's servers, without sending it.
@ -3522,7 +3521,7 @@ class TelegramClient:
return users.call(self._sender, request, ordered=ordered) return users.call(self._sender, request, ordered=ordered)
async def get_me(self: 'TelegramClient', input_peer: bool = False) \ async def get_me(self: 'TelegramClient', input_peer: bool = False) \
-> 'typing.Union[types.User, types.InputPeerUser]': -> 'typing.Union[_tl.User, _tl.InputPeerUser]':
""" """
Gets "me", the current :tl:`User` who is logged in. Gets "me", the current :tl:`User` who is logged in.
@ -3633,7 +3632,7 @@ class TelegramClient:
async def get_input_entity( async def get_input_entity(
self: 'TelegramClient', self: 'TelegramClient',
peer: 'hints.EntityLike') -> 'types.TypeInputPeer': peer: 'hints.EntityLike') -> '_tl.TypeInputPeer':
""" """
Turns the given entity into its input entity version. Turns the given entity into its input entity version.

View File

@ -8,9 +8,8 @@ import traceback
import typing import typing
import logging import logging
from .. import events, utils, errors from .. import events, utils, errors, _tl
from ..events.common import EventBuilder, EventCommon from ..events.common import EventBuilder, EventCommon
from ..tl import types, functions
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient from .telegramclient import TelegramClient
@ -22,7 +21,7 @@ Callback = typing.Callable[[typing.Any], typing.Any]
async def _run_until_disconnected(self: 'TelegramClient'): async def _run_until_disconnected(self: 'TelegramClient'):
try: try:
# Make a high-level request to notify that we want updates # Make a high-level request to notify that we want updates
await self(functions.updates.GetStateRequest()) await self(_tl.fn.updates.GetState())
return await self.disconnected return await self.disconnected
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
@ -32,7 +31,7 @@ async def _run_until_disconnected(self: 'TelegramClient'):
async def set_receive_updates(self: 'TelegramClient', receive_updates): async def set_receive_updates(self: 'TelegramClient', receive_updates):
self._no_updates = not receive_updates self._no_updates = not receive_updates
if receive_updates: if receive_updates:
await self(functions.updates.GetStateRequest()) await self(_tl.fn.updates.GetState())
async def run_until_disconnected(self: 'TelegramClient'): async def run_until_disconnected(self: 'TelegramClient'):
return await self._run_until_disconnected() return await self._run_until_disconnected()
@ -91,24 +90,24 @@ async def catch_up(self: 'TelegramClient'):
self.session.catching_up = True self.session.catching_up = True
try: try:
while True: while True:
d = await self(functions.updates.GetDifferenceRequest( d = await self(_tl.fn.updates.GetDifference(
pts, date, 0 pts, date, 0
)) ))
if isinstance(d, (types.updates.DifferenceSlice, if isinstance(d, (_tl.updates.DifferenceSlice,
types.updates.Difference)): _tl.updates.Difference)):
if isinstance(d, types.updates.Difference): if isinstance(d, _tl.updates.Difference):
state = d.state state = d.state
else: else:
state = d.intermediate_state state = d.intermediate_state
pts, date = state.pts, state.date pts, date = state.pts, state.date
self._handle_update(types.Updates( self._handle_update(_tl.Updates(
users=d.users, users=d.users,
chats=d.chats, chats=d.chats,
date=state.date, date=state.date,
seq=state.seq, seq=state.seq,
updates=d.other_updates + [ updates=d.other_updates + [
types.UpdateNewMessage(m, 0, 0) _tl.UpdateNewMessage(m, 0, 0)
for m in d.new_messages for m in d.new_messages
] ]
)) ))
@ -128,9 +127,9 @@ async def catch_up(self: 'TelegramClient'):
# some). This can be used to detect collisions (i.e. # some). This can be used to detect collisions (i.e.
# it would return an update we have already seen). # it would return an update we have already seen).
else: else:
if isinstance(d, types.updates.DifferenceEmpty): if isinstance(d, _tl.updates.DifferenceEmpty):
date = d.date date = d.date
elif isinstance(d, types.updates.DifferenceTooLong): elif isinstance(d, _tl.updates.DifferenceTooLong):
pts = d.pts pts = d.pts
break break
except (ConnectionError, asyncio.CancelledError): except (ConnectionError, asyncio.CancelledError):
@ -148,12 +147,12 @@ def _handle_update(self: 'TelegramClient', update):
self.session.process_entities(update) self.session.process_entities(update)
self._entity_cache.add(update) self._entity_cache.add(update)
if isinstance(update, (types.Updates, types.UpdatesCombined)): if isinstance(update, (_tl.Updates, _tl.UpdatesCombined)):
entities = {utils.get_peer_id(x): x for x in entities = {utils.get_peer_id(x): x for x in
itertools.chain(update.users, update.chats)} itertools.chain(update.users, update.chats)}
for u in update.updates: for u in update.updates:
self._process_update(u, update.updates, entities=entities) self._process_update(u, update.updates, entities=entities)
elif isinstance(update, types.UpdateShort): elif isinstance(update, _tl.UpdateShort):
self._process_update(update.update, None) self._process_update(update.update, None)
else: else:
self._process_update(update, None) self._process_update(update, None)
@ -230,7 +229,7 @@ async def _update_loop(self: 'TelegramClient'):
continue continue
try: try:
await self(functions.updates.GetStateRequest()) await self(_tl.fn.updates.GetState())
except (ConnectionError, asyncio.CancelledError): except (ConnectionError, asyncio.CancelledError):
return return
@ -359,7 +358,7 @@ async def _get_difference(self: 'TelegramClient', update, channel_id, pts_date):
assert isinstance(channel_id, int), 'channel_id was {}, not int in {}'.format(type(channel_id), update) assert isinstance(channel_id, int), 'channel_id was {}, not int in {}'.format(type(channel_id), update)
try: try:
# Wrap the ID inside a peer to ensure we get a channel back. # Wrap the ID inside a peer to ensure we get a channel back.
where = await self.get_input_entity(types.PeerChannel(channel_id)) where = await self.get_input_entity(_tl.PeerChannel(channel_id))
except ValueError: except ValueError:
# There's a high chance that this fails, since # There's a high chance that this fails, since
# we are getting the difference to fetch entities. # we are getting the difference to fetch entities.
@ -367,15 +366,15 @@ async def _get_difference(self: 'TelegramClient', update, channel_id, pts_date):
if not pts_date: if not pts_date:
# First-time, can't get difference. Get pts instead. # First-time, can't get difference. Get pts instead.
result = await self(functions.channels.GetFullChannelRequest( result = await self(_tl.fn.channels.GetFullChannel(
utils.get_input_channel(where) utils.get_input_channel(where)
)) ))
self._state_cache[channel_id] = result.full_chat.pts self._state_cache[channel_id] = result.full_chat.pts
return return
result = await self(functions.updates.GetChannelDifferenceRequest( result = await self(_tl.fn.updates.GetChannelDifference(
channel=where, channel=where,
filter=types.ChannelMessagesFilterEmpty(), filter=_tl.ChannelMessagesFilterEmpty(),
pts=pts_date, # just pts pts=pts_date, # just pts
limit=100, limit=100,
force=True force=True
@ -383,20 +382,20 @@ async def _get_difference(self: 'TelegramClient', update, channel_id, pts_date):
else: else:
if not pts_date[0]: if not pts_date[0]:
# First-time, can't get difference. Get pts instead. # First-time, can't get difference. Get pts instead.
result = await self(functions.updates.GetStateRequest()) result = await self(_tl.fn.updates.GetState())
self._state_cache[None] = result.pts, result.date self._state_cache[None] = result.pts, result.date
return return
result = await self(functions.updates.GetDifferenceRequest( result = await self(_tl.fn.updates.GetDifference(
pts=pts_date[0], pts=pts_date[0],
date=pts_date[1], date=pts_date[1],
qts=0 qts=0
)) ))
if isinstance(result, (types.updates.Difference, if isinstance(result, (_tl.updates.Difference,
types.updates.DifferenceSlice, _tl.updates.DifferenceSlice,
types.updates.ChannelDifference, _tl.updates.ChannelDifference,
types.updates.ChannelDifferenceTooLong)): _tl.updates.ChannelDifferenceTooLong)):
update._entities.update({ update._entities.update({
utils.get_peer_id(x): x for x in utils.get_peer_id(x): x for x in
itertools.chain(result.users, result.chats) itertools.chain(result.users, result.chats)

View File

@ -9,8 +9,7 @@ from io import BytesIO
from ..crypto import AES from ..crypto import AES
from .. import utils, helpers, hints from .. import utils, helpers, hints, _tl
from ..tl import types, functions, custom
try: try:
import PIL import PIL
@ -99,11 +98,11 @@ async def send_file(
clear_draft: bool = False, clear_draft: bool = False,
progress_callback: 'hints.ProgressCallback' = None, progress_callback: 'hints.ProgressCallback' = None,
reply_to: 'hints.MessageIDLike' = None, reply_to: 'hints.MessageIDLike' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None, attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
thumb: 'hints.FileLike' = None, thumb: 'hints.FileLike' = None,
allow_cache: bool = True, allow_cache: bool = True,
parse_mode: str = (), parse_mode: str = (),
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None, formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
voice_note: bool = False, voice_note: bool = False,
video_note: bool = False, video_note: bool = False,
buttons: 'hints.MarkupLike' = None, buttons: 'hints.MarkupLike' = None,
@ -111,9 +110,9 @@ async def send_file(
background: bool = None, background: bool = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None, schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None, comment_to: 'typing.Union[int, _tl.Message]' = None,
ttl: int = None, ttl: int = None,
**kwargs) -> 'types.Message': **kwargs) -> '_tl.Message':
# TODO Properly implement allow_cache to reuse the sha256 of the file # TODO Properly implement allow_cache to reuse the sha256 of the file
# i.e. `None` was used # i.e. `None` was used
if not file: if not file:
@ -182,7 +181,7 @@ async def send_file(
raise TypeError('Cannot use {!r} as file'.format(file)) raise TypeError('Cannot use {!r} as file'.format(file))
markup = self.build_reply_markup(buttons) markup = self.build_reply_markup(buttons)
request = functions.messages.SendMediaRequest( request = _tl.fn.messages.SendMedia(
entity, media, reply_to_msg_id=reply_to, message=caption, entity, media, reply_to_msg_id=reply_to, message=caption,
entities=msg_entities, reply_markup=markup, silent=silent, entities=msg_entities, reply_markup=markup, silent=silent,
schedule_date=schedule, clear_draft=clear_draft, schedule_date=schedule, clear_draft=clear_draft,
@ -225,14 +224,14 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
fh, fm, _ = await self._file_to_media( fh, fm, _ = await self._file_to_media(
file, supports_streaming=supports_streaming, file, supports_streaming=supports_streaming,
force_document=force_document, ttl=ttl) force_document=force_document, ttl=ttl)
if isinstance(fm, (types.InputMediaUploadedPhoto, types.InputMediaPhotoExternal)): if isinstance(fm, (_tl.InputMediaUploadedPhoto, _tl.InputMediaPhotoExternal)):
r = await self(functions.messages.UploadMediaRequest( r = await self(_tl.fn.messages.UploadMedia(
entity, media=fm entity, media=fm
)) ))
fm = utils.get_input_media(r.photo) fm = utils.get_input_media(r.photo)
elif isinstance(fm, types.InputMediaUploadedDocument): elif isinstance(fm, _tl.InputMediaUploadedDocument):
r = await self(functions.messages.UploadMediaRequest( r = await self(_tl.fn.messages.UploadMedia(
entity, media=fm entity, media=fm
)) ))
@ -243,7 +242,7 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
caption, msg_entities = captions.pop() caption, msg_entities = captions.pop()
else: else:
caption, msg_entities = '', None caption, msg_entities = '', None
media.append(types.InputSingleMedia( media.append(_tl.InputSingleMedia(
fm, fm,
message=caption, message=caption,
entities=msg_entities entities=msg_entities
@ -251,7 +250,7 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
)) ))
# Now we can construct the multi-media request # Now we can construct the multi-media request
request = functions.messages.SendMultiMediaRequest( request = _tl.fn.messages.SendMultiMedia(
entity, reply_to_msg_id=reply_to, multi_media=media, entity, reply_to_msg_id=reply_to, multi_media=media,
silent=silent, schedule_date=schedule, clear_draft=clear_draft, silent=silent, schedule_date=schedule, clear_draft=clear_draft,
background=background background=background
@ -271,8 +270,8 @@ async def upload_file(
use_cache: type = None, use_cache: type = None,
key: bytes = None, key: bytes = None,
iv: bytes = None, iv: bytes = None,
progress_callback: 'hints.ProgressCallback' = None) -> 'types.TypeInputFile': progress_callback: 'hints.ProgressCallback' = None) -> '_tl.TypeInputFile':
if isinstance(file, (types.InputFile, types.InputFileBig)): if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
return file # Already uploaded return file # Already uploaded
pos = 0 pos = 0
@ -343,10 +342,10 @@ async def upload_file(
# The SavePartRequest is different depending on whether # The SavePartRequest is different depending on whether
# the file is too large or not (over or less than 10MB) # the file is too large or not (over or less than 10MB)
if is_big: if is_big:
request = functions.upload.SaveBigFilePartRequest( request = _tl.fn.upload.SaveBigFilePart(
file_id, part_index, part_count, part) file_id, part_index, part_count, part)
else: else:
request = functions.upload.SaveFilePartRequest( request = _tl.fn.upload.SaveFilePart(
file_id, part_index, part) file_id, part_index, part)
result = await self(request) result = await self(request)
@ -360,9 +359,9 @@ async def upload_file(
'Failed to upload file part {}.'.format(part_index)) 'Failed to upload file part {}.'.format(part_index))
if is_big: if is_big:
return types.InputFileBig(file_id, part_count, file_name) return _tl.InputFileBig(file_id, part_count, file_name)
else: else:
return custom.InputSizedFile( return _tl.custom.InputSizedFile(
file_id, part_count, file_name, md5=hash_md5, size=file_size file_id, part_count, file_name, md5=hash_md5, size=file_size
) )
@ -385,7 +384,7 @@ async def _file_to_media(
# `aiofiles` do not base `io.IOBase` but do have `read`, so we # `aiofiles` do not base `io.IOBase` but do have `read`, so we
# just check for the read attribute to see if it's file-like. # just check for the read attribute to see if it's file-like.
if not isinstance(file, (str, bytes, types.InputFile, types.InputFileBig))\ if not isinstance(file, (str, bytes, _tl.InputFile, _tl.InputFileBig))\
and not hasattr(file, 'read'): and not hasattr(file, 'read'):
# The user may pass a Message containing media (or the media, # The user may pass a Message containing media (or the media,
# or anything similar) that should be treated as a file. Try # or anything similar) that should be treated as a file. Try
@ -411,7 +410,7 @@ async def _file_to_media(
media = None media = None
file_handle = None file_handle = None
if isinstance(file, (types.InputFile, types.InputFileBig)): if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
file_handle = file file_handle = file
elif not isinstance(file, str) or os.path.isfile(file): elif not isinstance(file, str) or os.path.isfile(file):
file_handle = await self.upload_file( file_handle = await self.upload_file(
@ -421,9 +420,9 @@ async def _file_to_media(
) )
elif re.match('https?://', file): elif re.match('https?://', file):
if as_image: if as_image:
media = types.InputMediaPhotoExternal(file, ttl_seconds=ttl) media = _tl.InputMediaPhotoExternal(file, ttl_seconds=ttl)
else: else:
media = types.InputMediaDocumentExternal(file, ttl_seconds=ttl) media = _tl.InputMediaDocumentExternal(file, ttl_seconds=ttl)
else: else:
bot_file = utils.resolve_bot_file_id(file) bot_file = utils.resolve_bot_file_id(file)
if bot_file: if bot_file:
@ -437,7 +436,7 @@ async def _file_to_media(
'an HTTP URL or a valid bot-API-like file ID'.format(file) 'an HTTP URL or a valid bot-API-like file ID'.format(file)
) )
elif as_image: elif as_image:
media = types.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl) media = _tl.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl)
else: else:
attributes, mime_type = utils.get_attributes( attributes, mime_type = utils.get_attributes(
file, file,
@ -457,7 +456,7 @@ async def _file_to_media(
thumb = str(thumb.absolute()) thumb = str(thumb.absolute())
thumb = await self.upload_file(thumb, file_size=file_size) thumb = await self.upload_file(thumb, file_size=file_size)
media = types.InputMediaUploadedDocument( media = _tl.InputMediaUploadedDocument(
file=file_handle, file=file_handle,
mime_type=mime_type, mime_type=mime_type,
attributes=attributes, attributes=attributes,

View File

@ -4,10 +4,9 @@ import itertools
import time import time
import typing import typing
from .. import errors, helpers, utils, hints from .. import errors, helpers, utils, hints, _tl
from ..errors import MultiError, RPCError from ..errors import MultiError, RPCError
from ..helpers import retry_range from ..helpers import retry_range
from ..tl import TLRequest, types, functions
_NOT_A_REQUEST = lambda: TypeError('You can only invoke requests, not types!') _NOT_A_REQUEST = lambda: TypeError('You can only invoke requests, not types!')
@ -48,7 +47,7 @@ async def call(self: 'TelegramClient', sender, request, ordered=False, flood_sle
raise errors.FloodWaitError(request=r, capture=diff) raise errors.FloodWaitError(request=r, capture=diff)
if self._no_updates: if self._no_updates:
r = functions.InvokeWithoutUpdatesRequest(r) r = _tl.fn.InvokeWithoutUpdates(r)
request_index = 0 request_index = 0
last_error = None last_error = None
@ -128,13 +127,13 @@ async def call(self: 'TelegramClient', sender, request, ordered=False, flood_sle
async def get_me(self: 'TelegramClient', input_peer: bool = False) \ async def get_me(self: 'TelegramClient', input_peer: bool = False) \
-> 'typing.Union[types.User, types.InputPeerUser]': -> 'typing.Union[_tl.User, _tl.InputPeerUser]':
if input_peer and self._self_input_peer: if input_peer and self._self_input_peer:
return self._self_input_peer return self._self_input_peer
try: try:
me = (await self( me = (await self(
functions.users.GetUsersRequest([types.InputUserSelf()])))[0] _tl.fn.users.GetUsers([_tl.InputUserSelf()])))[0]
self._bot = me.bot self._bot = me.bot
if not self._self_input_peer: if not self._self_input_peer:
@ -165,7 +164,7 @@ async def is_user_authorized(self: 'TelegramClient') -> bool:
if self._authorized is None: if self._authorized is None:
try: try:
# Any request that requires authorization will work # Any request that requires authorization will work
await self(functions.updates.GetStateRequest()) await self(_tl.fn.updates.GetState())
self._authorized = True self._authorized = True
except errors.RPCError: except errors.RPCError:
self._authorized = False self._authorized = False
@ -209,14 +208,14 @@ async def get_entity(
tmp = [] tmp = []
while users: while users:
curr, users = users[:200], users[200:] curr, users = users[:200], users[200:]
tmp.extend(await self(functions.users.GetUsersRequest(curr))) tmp.extend(await self(_tl.fn.users.GetUsers(curr)))
users = tmp users = tmp
if chats: # TODO Handle chats slice? if chats: # TODO Handle chats slice?
chats = (await self( chats = (await self(
functions.messages.GetChatsRequest([x.chat_id for x in chats]))).chats _tl.fn.messages.GetChats([x.chat_id for x in chats]))).chats
if channels: if channels:
channels = (await self( channels = (await self(
functions.channels.GetChannelsRequest(channels))).chats _tl.fn.channels.GetChannels(channels))).chats
# Merge users, chats and channels into a single dictionary # Merge users, chats and channels into a single dictionary
id_entity = { id_entity = {
@ -232,19 +231,19 @@ async def get_entity(
for x in inputs: for x in inputs:
if isinstance(x, str): if isinstance(x, str):
result.append(await self._get_entity_from_string(x)) result.append(await self._get_entity_from_string(x))
elif not isinstance(x, types.InputPeerSelf): elif not isinstance(x, _tl.InputPeerSelf):
result.append(id_entity[utils.get_peer_id(x)]) result.append(id_entity[utils.get_peer_id(x)])
else: else:
result.append(next( result.append(next(
u for u in id_entity.values() u for u in id_entity.values()
if isinstance(u, types.User) and u.is_self if isinstance(u, _tl.User) and u.is_self
)) ))
return result[0] if single else result return result[0] if single else result
async def get_input_entity( async def get_input_entity(
self: 'TelegramClient', self: 'TelegramClient',
peer: 'hints.EntityLike') -> 'types.TypeInputPeer': peer: 'hints.EntityLike') -> '_tl.TypeInputPeer':
# Short-circuit if the input parameter directly maps to an InputPeer # Short-circuit if the input parameter directly maps to an InputPeer
try: try:
return utils.get_input_peer(peer) return utils.get_input_peer(peer)
@ -261,7 +260,7 @@ async def get_input_entity(
# Then come known strings that take precedence # Then come known strings that take precedence
if peer in ('me', 'self'): if peer in ('me', 'self'):
return types.InputPeerSelf() return _tl.InputPeerSelf()
# No InputPeer, cached peer, or known string. Fetch from disk cache # No InputPeer, cached peer, or known string. Fetch from disk cache
try: try:
@ -279,10 +278,10 @@ async def get_input_entity(
# If we're not a bot but the user is in our contacts, it seems to work # If we're not a bot but the user is in our contacts, it seems to work
# regardless. These are the only two special-cased requests. # regardless. These are the only two special-cased requests.
peer = utils.get_peer(peer) peer = utils.get_peer(peer)
if isinstance(peer, types.PeerUser): if isinstance(peer, _tl.PeerUser):
users = await self(functions.users.GetUsersRequest([ users = await self(_tl.fn.users.GetUsers([
types.InputUser(peer.user_id, access_hash=0)])) _tl.InputUser(peer.user_id, access_hash=0)]))
if users and not isinstance(users[0], types.UserEmpty): if users and not isinstance(users[0], _tl.UserEmpty):
# If the user passed a valid ID they expect to work for # If the user passed a valid ID they expect to work for
# channels but would be valid for users, we get UserEmpty. # channels but would be valid for users, we get UserEmpty.
# Avoid returning the invalid empty input peer for that. # Avoid returning the invalid empty input peer for that.
@ -291,12 +290,12 @@ async def get_input_entity(
# it's not, work as a chat and try to validate it through # it's not, work as a chat and try to validate it through
# another request, but that becomes too much work. # another request, but that becomes too much work.
return utils.get_input_peer(users[0]) return utils.get_input_peer(users[0])
elif isinstance(peer, types.PeerChat): elif isinstance(peer, _tl.PeerChat):
return types.InputPeerChat(peer.chat_id) return _tl.InputPeerChat(peer.chat_id)
elif isinstance(peer, types.PeerChannel): elif isinstance(peer, _tl.PeerChannel):
try: try:
channels = await self(functions.channels.GetChannelsRequest([ channels = await self(_tl.fn.channels.GetChannels([
types.InputChannel(peer.channel_id, access_hash=0)])) _tl.InputChannel(peer.channel_id, access_hash=0)]))
return utils.get_input_peer(channels.chats[0]) return utils.get_input_peer(channels.chats[0])
except errors.ChannelInvalidError: except errors.ChannelInvalidError:
pass pass
@ -326,7 +325,7 @@ async def get_peer_id(
except AttributeError: except AttributeError:
peer = await self.get_input_entity(peer) peer = await self.get_input_entity(peer)
if isinstance(peer, types.InputPeerSelf): if isinstance(peer, _tl.InputPeerSelf):
peer = await self.get_me(input_peer=True) peer = await self.get_me(input_peer=True)
return utils.get_peer_id(peer, add_mark=add_mark) return utils.get_peer_id(peer, add_mark=add_mark)
@ -348,7 +347,7 @@ async def _get_entity_from_string(self: 'TelegramClient', string):
if phone: if phone:
try: try:
for user in (await self( for user in (await self(
functions.contacts.GetContactsRequest(0))).users: _tl.fn.contacts.GetContacts(0))).users:
if user.phone == phone: if user.phone == phone:
return user return user
except errors.BotMethodInvalidError: except errors.BotMethodInvalidError:
@ -360,26 +359,26 @@ async def _get_entity_from_string(self: 'TelegramClient', string):
username, is_join_chat = utils.parse_username(string) username, is_join_chat = utils.parse_username(string)
if is_join_chat: if is_join_chat:
invite = await self( invite = await self(
functions.messages.CheckChatInviteRequest(username)) _tl.fn.messages.CheckChatInvite(username))
if isinstance(invite, types.ChatInvite): if isinstance(invite, _tl.ChatInvite):
raise ValueError( raise ValueError(
'Cannot get entity from a channel (or group) ' 'Cannot get entity from a channel (or group) '
'that you are not part of. Join the group and retry' 'that you are not part of. Join the group and retry'
) )
elif isinstance(invite, types.ChatInviteAlready): elif isinstance(invite, _tl.ChatInviteAlready):
return invite.chat return invite.chat
elif username: elif username:
try: try:
result = await self( result = await self(
functions.contacts.ResolveUsernameRequest(username)) _tl.fn.contacts.ResolveUsername(username))
except errors.UsernameNotOccupiedError as e: except errors.UsernameNotOccupiedError as e:
raise ValueError('No user has "{}" as username' raise ValueError('No user has "{}" as username'
.format(username)) from e .format(username)) from e
try: try:
pid = utils.get_peer_id(result.peer, add_mark=False) pid = utils.get_peer_id(result.peer, add_mark=False)
if isinstance(result.peer, types.PeerUser): if isinstance(result.peer, _tl.PeerUser):
return next(x for x in result.users if x.id == pid) return next(x for x in result.users if x.id == pid)
else: else:
return next(x for x in result.chats if x.id == pid) return next(x for x in result.chats if x.id == pid)
@ -407,11 +406,11 @@ async def _get_input_dialog(self: 'TelegramClient', dialog):
dialog.peer = await self.get_input_entity(dialog.peer) dialog.peer = await self.get_input_entity(dialog.peer)
return dialog return dialog
elif dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer') elif dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
return types.InputDialogPeer(dialog) return _tl.InputDialogPeer(dialog)
except AttributeError: except AttributeError:
pass pass
return types.InputDialogPeer(await self.get_input_entity(dialog)) return _tl.InputDialogPeer(await self.get_input_entity(dialog))
async def _get_input_notify(self: 'TelegramClient', notify): async def _get_input_notify(self: 'TelegramClient', notify):
""" """
@ -421,10 +420,10 @@ async def _get_input_notify(self: 'TelegramClient', notify):
""" """
try: try:
if notify.SUBCLASS_OF_ID == 0x58981615: if notify.SUBCLASS_OF_ID == 0x58981615:
if isinstance(notify, types.InputNotifyPeer): if isinstance(notify, _tl.InputNotifyPeer):
notify.peer = await self.get_input_entity(notify.peer) notify.peer = await self.get_input_entity(notify.peer)
return notify return notify
except AttributeError: except AttributeError:
pass pass
return types.InputNotifyPeer(await self.get_input_entity(notify)) return _tl.InputNotifyPeer(await self.get_input_entity(notify))

View File

@ -3,8 +3,7 @@ This module holds the CdnDecrypter utility class.
""" """
from hashlib import sha256 from hashlib import sha256
from ..tl.functions.upload import GetCdnFileRequest, ReuploadCdnFileRequest from .. import _tl
from ..tl.types.upload import CdnFileReuploadNeeded, CdnFile
from ..crypto import AESModeCTR from ..crypto import AESModeCTR
from ..errors import CdnFileTamperedError from ..errors import CdnFileTamperedError
@ -52,14 +51,14 @@ class CdnDecrypter:
cdn_aes, cdn_redirect.cdn_file_hashes cdn_aes, cdn_redirect.cdn_file_hashes
) )
cdn_file = await cdn_client(GetCdnFileRequest( cdn_file = await cdn_client(_tl.fn.upload.GetCdnFile(
file_token=cdn_redirect.file_token, file_token=cdn_redirect.file_token,
offset=cdn_redirect.cdn_file_hashes[0].offset, offset=cdn_redirect.cdn_file_hashes[0].offset,
limit=cdn_redirect.cdn_file_hashes[0].limit limit=cdn_redirect.cdn_file_hashes[0].limit
)) ))
if isinstance(cdn_file, CdnFileReuploadNeeded): if isinstance(cdn_file, _tl.upload.CdnFileReuploadNeeded):
# We need to use the original client here # We need to use the original client here
await client(ReuploadCdnFileRequest( await client(_tl.fn.upload.ReuploadCdnFile(
file_token=cdn_redirect.file_token, file_token=cdn_redirect.file_token,
request_token=cdn_file.request_token request_token=cdn_file.request_token
)) ))
@ -82,13 +81,13 @@ class CdnDecrypter:
""" """
if self.cdn_file_hashes: if self.cdn_file_hashes:
cdn_hash = self.cdn_file_hashes.pop(0) cdn_hash = self.cdn_file_hashes.pop(0)
cdn_file = self.client(GetCdnFileRequest( cdn_file = self.client(_tl.fn.upload.GetCdnFile(
self.file_token, cdn_hash.offset, cdn_hash.limit self.file_token, cdn_hash.offset, cdn_hash.limit
)) ))
cdn_file.bytes = self.cdn_aes.encrypt(cdn_file.bytes) cdn_file.bytes = self.cdn_aes.encrypt(cdn_file.bytes)
self.check(cdn_file.bytes, cdn_hash) self.check(cdn_file.bytes, cdn_hash)
else: else:
cdn_file = CdnFile(bytes(0)) cdn_file = _tl.upload.CdnFile(bytes(0))
return cdn_file return cdn_file

View File

@ -11,7 +11,7 @@ except ImportError:
rsa = None rsa = None
raise ImportError('Missing module "rsa", please install via pip.') raise ImportError('Missing module "rsa", please install via pip.')
from ..tl import TLObject from .. import _tl
# {fingerprint: (Crypto.PublicKey.RSA._RSAobj, old)} dictionary # {fingerprint: (Crypto.PublicKey.RSA._RSAobj, old)} dictionary
@ -41,8 +41,8 @@ def _compute_fingerprint(key):
:param key: the Crypto.RSA key. :param key: the Crypto.RSA key.
:return: its 8-bytes-long fingerprint. :return: its 8-bytes-long fingerprint.
""" """
n = TLObject.serialize_bytes(get_byte_array(key.n)) n = _tl.TLObject.serialize_bytes(get_byte_array(key.n))
e = TLObject.serialize_bytes(get_byte_array(key.e)) e = _tl.TLObject.serialize_bytes(get_byte_array(key.e))
# Telegram uses the last 8 bytes as the fingerprint # Telegram uses the last 8 bytes as the fingerprint
return struct.unpack('<q', sha1(n + e).digest()[-8:])[0] return struct.unpack('<q', sha1(n + e).digest()[-8:])[0]

View File

@ -8,8 +8,7 @@ from io import BytesIO
from struct import unpack from struct import unpack
from ..errors import TypeNotFoundError from ..errors import TypeNotFoundError
from ..tl.alltlobjects import tlobjects from .. import _tl
from ..tl.core import core_objects
_EPOCH_NAIVE = datetime(*time.gmtime(0)[:6]) _EPOCH_NAIVE = datetime(*time.gmtime(0)[:6])
_EPOCH = _EPOCH_NAIVE.replace(tzinfo=timezone.utc) _EPOCH = _EPOCH_NAIVE.replace(tzinfo=timezone.utc)
@ -118,7 +117,7 @@ class BinaryReader:
def tgread_object(self): def tgread_object(self):
"""Reads a Telegram object.""" """Reads a Telegram object."""
constructor_id = self.read_int(signed=False) constructor_id = self.read_int(signed=False)
clazz = tlobjects.get(constructor_id, None) clazz = _tl.tlobjects.get(constructor_id, None)
if clazz is None: if clazz is None:
# The class was None, but there's still a # The class was None, but there's still a
# chance of it being a manually parsed value like bool! # chance of it being a manually parsed value like bool!
@ -130,7 +129,7 @@ class BinaryReader:
elif value == 0x1cb5c415: # Vector elif value == 0x1cb5c415: # Vector
return [self.tgread_object() for _ in range(self.read_int())] return [self.tgread_object() for _ in range(self.read_int())]
clazz = core_objects.get(constructor_id, None) clazz = _tl.core.get(constructor_id, None)
if clazz is None: if clazz is None:
# If there was still no luck, give up # If there was still no luck, give up
self.seek(-4) # Go back self.seek(-4) # Go back

View File

@ -1,8 +1,7 @@
import inspect import inspect
import itertools import itertools
from . import utils from . import utils, _tl
from .tl import types
# Which updates have the following fields? # Which updates have the following fields?
_has_field = { _has_field = {
@ -25,8 +24,8 @@ _has_field = {
def _fill(): def _fill():
for name in dir(types): for name in dir(_tl):
update = getattr(types, name) update = getattr(_tl, name)
if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e: if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e:
cid = update.CONSTRUCTOR_ID cid = update.CONSTRUCTOR_ID
sig = inspect.signature(update.__init__) sig = inspect.signature(update.__init__)
@ -84,7 +83,7 @@ class EntityCache:
except TypeError: except TypeError:
raise KeyError('Invalid key will not have entity') from None raise KeyError('Invalid key will not have entity') from None
for cls in (types.PeerUser, types.PeerChat, types.PeerChannel): for cls in (_tl.PeerUser, _tl.PeerChat, _tl.PeerChannel):
result = self.__dict__.get(utils.get_peer_id(cls(item))) result = self.__dict__.get(utils.get_peer_id(cls(item)))
if result: if result:
return result return result
@ -111,7 +110,7 @@ class EntityCache:
""" """
# This method is called pretty often and we want it to have the lowest # This method is called pretty often and we want it to have the lowest
# overhead possible. For that, we avoid `isinstance` and constantly # overhead possible. For that, we avoid `isinstance` and constantly
# getting attributes out of `types.` by "caching" the constructor IDs # getting attributes out of `_tl.` by "caching" the constructor IDs
# in sets inside the arguments, and using local variables. # in sets inside the arguments, and using local variables.
dct = self.__dict__ dct = self.__dict__
cid = update.CONSTRUCTOR_ID cid = update.CONSTRUCTOR_ID
@ -120,11 +119,11 @@ class EntityCache:
return False return False
if cid in has_chat_id and \ if cid in has_chat_id and \
utils.get_peer_id(types.PeerChat(update.chat_id)) not in dct: utils.get_peer_id(_tl.PeerChat(update.chat_id)) not in dct:
return False return False
if cid in has_channel_id and \ if cid in has_channel_id and \
utils.get_peer_id(types.PeerChannel(update.channel_id)) not in dct: utils.get_peer_id(_tl.PeerChannel(update.channel_id)) not in dct:
return False return False
if cid in has_peer and \ if cid in has_peer and \

View File

@ -1,29 +1,28 @@
import datetime import datetime
import typing import typing
from . import helpers from . import helpers, _tl
from .tl import types, custom
Phone = str Phone = str
Username = str Username = str
PeerID = int PeerID = int
Entity = typing.Union[types.User, types.Chat, types.Channel] Entity = typing.Union[_tl.User, _tl.Chat, _tl.Channel]
FullEntity = typing.Union[types.UserFull, types.messages.ChatFull, types.ChatFull, types.ChannelFull] FullEntity = typing.Union[_tl.UserFull, _tl.messages.ChatFull, _tl.ChatFull, _tl.ChannelFull]
EntityLike = typing.Union[ EntityLike = typing.Union[
Phone, Phone,
Username, Username,
PeerID, PeerID,
types.TypePeer, _tl.TypePeer,
types.TypeInputPeer, _tl.TypeInputPeer,
Entity, Entity,
FullEntity FullEntity
] ]
EntitiesLike = typing.Union[EntityLike, typing.Sequence[EntityLike]] EntitiesLike = typing.Union[EntityLike, typing.Sequence[EntityLike]]
ButtonLike = typing.Union[types.TypeKeyboardButton, custom.Button] ButtonLike = typing.Union[_tl.TypeKeyboardButton, custom.Button]
MarkupLike = typing.Union[ MarkupLike = typing.Union[
types.TypeReplyMarkup, _tl.TypeReplyMarkup,
ButtonLike, ButtonLike,
typing.Sequence[ButtonLike], typing.Sequence[ButtonLike],
typing.Sequence[typing.Sequence[ButtonLike]] typing.Sequence[typing.Sequence[ButtonLike]]
@ -42,9 +41,9 @@ FileLike = typing.Union[
BotFileID, BotFileID,
bytes, bytes,
typing.BinaryIO, typing.BinaryIO,
types.TypeMessageMedia, _tl.TypeMessageMedia,
types.TypeInputFile, _tl.TypeInputFile,
types.TypeInputFileLocation _tl.TypeInputFileLocation
] ]
# Can't use `typing.Type` in Python 3.5.2 # Can't use `typing.Type` in Python 3.5.2
@ -61,7 +60,7 @@ except TypeError:
typing.BinaryIO typing.BinaryIO
] ]
MessageLike = typing.Union[str, types.Message] MessageLike = typing.Union[str, _tl.Message]
MessageIDLike = typing.Union[int, types.Message, types.TypeInputMessage] MessageIDLike = typing.Union[int, _tl.Message, _tl.TypeInputMessage]
ProgressCallback = typing.Callable[[int, int], None] ProgressCallback = typing.Callable[[int, int], None]

View File

@ -7,14 +7,7 @@ from html import escape
from html.parser import HTMLParser from html.parser import HTMLParser
from typing import Iterable, Optional, Tuple, List from typing import Iterable, Optional, Tuple, List
from .. import helpers from .. import helpers, _tl
from ..tl.types import (
MessageEntityBold, MessageEntityItalic, MessageEntityCode,
MessageEntityPre, MessageEntityEmail, MessageEntityUrl,
MessageEntityTextUrl, MessageEntityMentionName,
MessageEntityUnderline, MessageEntityStrike, MessageEntityBlockquote,
TypeMessageEntity
)
# Helpers from markdown.py # Helpers from markdown.py
@ -46,15 +39,15 @@ class HTMLToTelegramParser(HTMLParser):
EntityType = None EntityType = None
args = {} args = {}
if tag == 'strong' or tag == 'b': if tag == 'strong' or tag == 'b':
EntityType = MessageEntityBold EntityType = _tl.MessageEntityBold
elif tag == 'em' or tag == 'i': elif tag == 'em' or tag == 'i':
EntityType = MessageEntityItalic EntityType = _tl.MessageEntityItalic
elif tag == 'u': elif tag == 'u':
EntityType = MessageEntityUnderline EntityType = _tl.MessageEntityUnderline
elif tag == 'del' or tag == 's': elif tag == 'del' or tag == 's':
EntityType = MessageEntityStrike EntityType = _tl.MessageEntityStrike
elif tag == 'blockquote': elif tag == 'blockquote':
EntityType = MessageEntityBlockquote EntityType = _tl.MessageEntityBlockquote
elif tag == 'code': elif tag == 'code':
try: try:
# If we're in the middle of a <pre> tag, this <code> tag is # If we're in the middle of a <pre> tag, this <code> tag is
@ -69,9 +62,9 @@ class HTMLToTelegramParser(HTMLParser):
except KeyError: except KeyError:
pass pass
except KeyError: except KeyError:
EntityType = MessageEntityCode EntityType = _tl.MessageEntityCode
elif tag == 'pre': elif tag == 'pre':
EntityType = MessageEntityPre EntityType = _tl.MessageEntityPre
args['language'] = '' args['language'] = ''
elif tag == 'a': elif tag == 'a':
try: try:
@ -80,12 +73,12 @@ class HTMLToTelegramParser(HTMLParser):
return return
if url.startswith('mailto:'): if url.startswith('mailto:'):
url = url[len('mailto:'):] url = url[len('mailto:'):]
EntityType = MessageEntityEmail EntityType = _tl.MessageEntityEmail
else: else:
if self.get_starttag_text() == url: if self.get_starttag_text() == url:
EntityType = MessageEntityUrl EntityType = _tl.MessageEntityUrl
else: else:
EntityType = MessageEntityTextUrl EntityType = _tl.MessageEntityTextUrl
args['url'] = url args['url'] = url
url = None url = None
self._open_tags_meta.popleft() self._open_tags_meta.popleft()
@ -121,10 +114,10 @@ class HTMLToTelegramParser(HTMLParser):
self.entities.append(entity) self.entities.append(entity)
def parse(html: str) -> Tuple[str, List[TypeMessageEntity]]: def parse(html: str) -> Tuple[str, List[_tl.TypeMessageEntity]]:
""" """
Parses the given HTML message and returns its stripped representation Parses the given HTML message and returns its stripped representation
plus a list of the MessageEntity's that were found. plus a list of the _tl.MessageEntity's that were found.
:param html: the message with HTML to be parsed. :param html: the message with HTML to be parsed.
:return: a tuple consisting of (clean message, [message entities]). :return: a tuple consisting of (clean message, [message entities]).
@ -138,14 +131,14 @@ def parse(html: str) -> Tuple[str, List[TypeMessageEntity]]:
return _del_surrogate(text), parser.entities return _del_surrogate(text), parser.entities
def unparse(text: str, entities: Iterable[TypeMessageEntity], _offset: int = 0, def unparse(text: str, entities: Iterable[_tl.TypeMessageEntity], _offset: int = 0,
_length: Optional[int] = None) -> str: _length: Optional[int] = None) -> str:
""" """
Performs the reverse operation to .parse(), effectively returning HTML Performs the reverse operation to .parse(), effectively returning HTML
given a normal text and its MessageEntity's. given a normal text and its _tl.MessageEntity's.
:param text: the text to be reconverted into HTML. :param text: the text to be reconverted into HTML.
:param entities: the MessageEntity's applied to the text. :param entities: the _tl.MessageEntity's applied to the text.
:return: a HTML representation of the combination of both inputs. :return: a HTML representation of the combination of both inputs.
""" """
if not text: if not text:
@ -185,19 +178,19 @@ def unparse(text: str, entities: Iterable[TypeMessageEntity], _offset: int = 0,
_offset=entity.offset, _length=length) _offset=entity.offset, _length=length)
entity_type = type(entity) entity_type = type(entity)
if entity_type == MessageEntityBold: if entity_type == _tl.MessageEntityBold:
html.append('<strong>{}</strong>'.format(entity_text)) html.append('<strong>{}</strong>'.format(entity_text))
elif entity_type == MessageEntityItalic: elif entity_type == _tl.MessageEntityItalic:
html.append('<em>{}</em>'.format(entity_text)) html.append('<em>{}</em>'.format(entity_text))
elif entity_type == MessageEntityCode: elif entity_type == _tl.MessageEntityCode:
html.append('<code>{}</code>'.format(entity_text)) html.append('<code>{}</code>'.format(entity_text))
elif entity_type == MessageEntityUnderline: elif entity_type == _tl.MessageEntityUnderline:
html.append('<u>{}</u>'.format(entity_text)) html.append('<u>{}</u>'.format(entity_text))
elif entity_type == MessageEntityStrike: elif entity_type == _tl.MessageEntityStrike:
html.append('<del>{}</del>'.format(entity_text)) html.append('<del>{}</del>'.format(entity_text))
elif entity_type == MessageEntityBlockquote: elif entity_type == _tl.MessageEntityBlockquote:
html.append('<blockquote>{}</blockquote>'.format(entity_text)) html.append('<blockquote>{}</blockquote>'.format(entity_text))
elif entity_type == MessageEntityPre: elif entity_type == _tl.MessageEntityPre:
if entity.language: if entity.language:
html.append( html.append(
"<pre>\n" "<pre>\n"
@ -208,14 +201,14 @@ def unparse(text: str, entities: Iterable[TypeMessageEntity], _offset: int = 0,
else: else:
html.append('<pre><code>{}</code></pre>' html.append('<pre><code>{}</code></pre>'
.format(entity_text)) .format(entity_text))
elif entity_type == MessageEntityEmail: elif entity_type == _tl.MessageEntityEmail:
html.append('<a href="mailto:{0}">{0}</a>'.format(entity_text)) html.append('<a href="mailto:{0}">{0}</a>'.format(entity_text))
elif entity_type == MessageEntityUrl: elif entity_type == _tl.MessageEntityUrl:
html.append('<a href="{0}">{0}</a>'.format(entity_text)) html.append('<a href="{0}">{0}</a>'.format(entity_text))
elif entity_type == MessageEntityTextUrl: elif entity_type == _tl.MessageEntityTextUrl:
html.append('<a href="{}">{}</a>' html.append('<a href="{}">{}</a>'
.format(escape(entity.url), entity_text)) .format(escape(entity.url), entity_text))
elif entity_type == MessageEntityMentionName: elif entity_type == _tl.MessageEntityMentionName:
html.append('<a href="tg://user?id={}">{}</a>' html.append('<a href="tg://user?id={}">{}</a>'
.format(entity.user_id, entity_text)) .format(entity.user_id, entity_text))
else: else:

View File

@ -7,19 +7,14 @@ import re
import warnings import warnings
from ..helpers import add_surrogate, del_surrogate, within_surrogate, strip_text from ..helpers import add_surrogate, del_surrogate, within_surrogate, strip_text
from ..tl import TLObject from .. import _tl
from ..tl.types import (
MessageEntityBold, MessageEntityItalic, MessageEntityCode,
MessageEntityPre, MessageEntityTextUrl, MessageEntityMentionName,
MessageEntityStrike
)
DEFAULT_DELIMITERS = { DEFAULT_DELIMITERS = {
'**': MessageEntityBold, '**': _tl.MessageEntityBold,
'__': MessageEntityItalic, '__': _tl.MessageEntityItalic,
'~~': MessageEntityStrike, '~~': _tl.MessageEntityStrike,
'`': MessageEntityCode, '`': _tl.MessageEntityCode,
'```': MessageEntityPre '```': _tl.MessageEntityPre
} }
DEFAULT_URL_RE = re.compile(r'\[([\S\s]+?)\]\((.+?)\)') DEFAULT_URL_RE = re.compile(r'\[([\S\s]+?)\]\((.+?)\)')
@ -33,7 +28,7 @@ def overlap(a, b, x, y):
def parse(message, delimiters=None, url_re=None): def parse(message, delimiters=None, url_re=None):
""" """
Parses the given markdown message and returns its stripped representation Parses the given markdown message and returns its stripped representation
plus a list of the MessageEntity's that were found. plus a list of the _tl.MessageEntity's that were found.
:param message: the message with markdown-like syntax to be parsed. :param message: the message with markdown-like syntax to be parsed.
:param delimiters: the delimiters to be used, {delimiter: type}. :param delimiters: the delimiters to be used, {delimiter: type}.
@ -98,13 +93,13 @@ def parse(message, delimiters=None, url_re=None):
# Append the found entity # Append the found entity
ent = delimiters[delim] ent = delimiters[delim]
if ent == MessageEntityPre: if ent == _tl.MessageEntityPre:
result.append(ent(i, end - i - len(delim), '')) # has 'lang' result.append(ent(i, end - i - len(delim), '')) # has 'lang'
else: else:
result.append(ent(i, end - i - len(delim))) result.append(ent(i, end - i - len(delim)))
# No nested entities inside code blocks # No nested entities inside code blocks
if ent in (MessageEntityCode, MessageEntityPre): if ent in (_tl.MessageEntityCode, _tl.MessageEntityPre):
i = end - len(delim) i = end - len(delim)
continue continue
@ -125,7 +120,7 @@ def parse(message, delimiters=None, url_re=None):
if ent.offset + ent.length > m.start(): if ent.offset + ent.length > m.start():
ent.length -= delim_size ent.length -= delim_size
result.append(MessageEntityTextUrl( result.append(_tl.MessageEntityTextUrl(
offset=m.start(), length=len(m.group(1)), offset=m.start(), length=len(m.group(1)),
url=del_surrogate(m.group(2)) url=del_surrogate(m.group(2))
)) ))
@ -141,10 +136,10 @@ def parse(message, delimiters=None, url_re=None):
def unparse(text, entities, delimiters=None, url_fmt=None): def unparse(text, entities, delimiters=None, url_fmt=None):
""" """
Performs the reverse operation to .parse(), effectively returning Performs the reverse operation to .parse(), effectively returning
markdown-like syntax given a normal text and its MessageEntity's. markdown-like syntax given a normal text and its _tl.MessageEntity's.
:param text: the text to be reconverted into markdown. :param text: the text to be reconverted into markdown.
:param entities: the MessageEntity's applied to the text. :param entities: the _tl.MessageEntity's applied to the text.
:return: a markdown-like text representing the combination of both inputs. :return: a markdown-like text representing the combination of both inputs.
""" """
if not text or not entities: if not text or not entities:
@ -158,7 +153,7 @@ def unparse(text, entities, delimiters=None, url_fmt=None):
if url_fmt is not None: if url_fmt is not None:
warnings.warn('url_fmt is deprecated') # since it complicates everything *a lot* warnings.warn('url_fmt is deprecated') # since it complicates everything *a lot*
if isinstance(entities, TLObject): if isinstance(entities, _tl.TLObject):
entities = (entities,) entities = (entities,)
text = add_surrogate(text) text = add_surrogate(text)
@ -173,9 +168,9 @@ def unparse(text, entities, delimiters=None, url_fmt=None):
insert_at.append((e, delimiter)) insert_at.append((e, delimiter))
else: else:
url = None url = None
if isinstance(entity, MessageEntityTextUrl): if isinstance(entity, _tl.MessageEntityTextUrl):
url = entity.url url = entity.url
elif isinstance(entity, MessageEntityMentionName): elif isinstance(entity, _tl.MessageEntityMentionName):
url = 'tg://user?id={}'.format(entity.user_id) url = 'tg://user?id={}'.format(entity.user_id)
if url: if url:
insert_at.append((s, '[')) insert_at.append((s, '['))

View File

@ -2,7 +2,7 @@ import hashlib
import os import os
from .crypto import factorization from .crypto import factorization
from .tl import types from . import _tl
def check_prime_and_good_check(prime: int, g: int): def check_prime_and_good_check(prime: int, g: int):
@ -110,7 +110,7 @@ def pbkdf2sha512(password: bytes, salt: bytes, iterations: int):
return hashlib.pbkdf2_hmac('sha512', password, salt, iterations) return hashlib.pbkdf2_hmac('sha512', password, salt, iterations)
def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow, def compute_hash(algo: _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
password: str): password: str):
hash1 = sha256(algo.salt1, password.encode('utf-8'), algo.salt1) hash1 = sha256(algo.salt1, password.encode('utf-8'), algo.salt1)
hash2 = sha256(algo.salt2, hash1, algo.salt2) hash2 = sha256(algo.salt2, hash1, algo.salt2)
@ -118,7 +118,7 @@ def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter1000
return sha256(algo.salt2, hash3, algo.salt2) return sha256(algo.salt2, hash3, algo.salt2)
def compute_digest(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow, def compute_digest(algo: _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
password: str): password: str):
try: try:
check_prime_and_good(algo.p, algo.g) check_prime_and_good(algo.p, algo.g)
@ -133,9 +133,9 @@ def compute_digest(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter10
# https://github.com/telegramdesktop/tdesktop/blob/18b74b90451a7db2379a9d753c9cbaf8734b4d5d/Telegram/SourceFiles/core/core_cloud_password.cpp # https://github.com/telegramdesktop/tdesktop/blob/18b74b90451a7db2379a9d753c9cbaf8734b4d5d/Telegram/SourceFiles/core/core_cloud_password.cpp
def compute_check(request: types.account.Password, password: str): def compute_check(request: _tl.account.Password, password: str):
algo = request.current_algo algo = request.current_algo
if not isinstance(algo, types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow): if not isinstance(algo, _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow):
raise ValueError('unsupported password algorithm {}' raise ValueError('unsupported password algorithm {}'
.format(algo.__class__.__name__)) .format(algo.__class__.__name__))
@ -190,5 +190,5 @@ def compute_check(request: types.account.Password, password: str):
K K
) )
return types.InputCheckPasswordSRP( return _tl.InputCheckPasswordSRP(
request.srp_id, bytes(a_for_hash), bytes(M1)) request.srp_id, bytes(a_for_hash), bytes(M1))

View File

@ -1,6 +1,6 @@
import inspect import inspect
from .tl import types from . import _tl
# Which updates have the following fields? # Which updates have the following fields?
@ -9,8 +9,8 @@ _has_channel_id = []
# TODO EntityCache does the same. Reuse? # TODO EntityCache does the same. Reuse?
def _fill(): def _fill():
for name in dir(types): for name in dir(_tl):
update = getattr(types, name) update = getattr(_tl, name)
if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e: if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e:
cid = update.CONSTRUCTOR_ID cid = update.CONSTRUCTOR_ID
sig = inspect.signature(update.__init__) sig = inspect.signature(update.__init__)
@ -51,41 +51,41 @@ class StateCache:
*, *,
channel_id=None, channel_id=None,
has_pts=frozenset(x.CONSTRUCTOR_ID for x in ( has_pts=frozenset(x.CONSTRUCTOR_ID for x in (
types.UpdateNewMessage, _tl.UpdateNewMessage,
types.UpdateDeleteMessages, _tl.UpdateDeleteMessages,
types.UpdateReadHistoryInbox, _tl.UpdateReadHistoryInbox,
types.UpdateReadHistoryOutbox, _tl.UpdateReadHistoryOutbox,
types.UpdateWebPage, _tl.UpdateWebPage,
types.UpdateReadMessagesContents, _tl.UpdateReadMessagesContents,
types.UpdateEditMessage, _tl.UpdateEditMessage,
types.updates.State, _tl.updates.State,
types.updates.DifferenceTooLong, _tl.updates.DifferenceTooLong,
types.UpdateShortMessage, _tl.UpdateShortMessage,
types.UpdateShortChatMessage, _tl.UpdateShortChatMessage,
types.UpdateShortSentMessage _tl.UpdateShortSentMessage
)), )),
has_date=frozenset(x.CONSTRUCTOR_ID for x in ( has_date=frozenset(x.CONSTRUCTOR_ID for x in (
types.UpdateUserPhoto, _tl.UpdateUserPhoto,
types.UpdateEncryption, _tl.UpdateEncryption,
types.UpdateEncryptedMessagesRead, _tl.UpdateEncryptedMessagesRead,
types.UpdateChatParticipantAdd, _tl.UpdateChatParticipantAdd,
types.updates.DifferenceEmpty, _tl.updates.DifferenceEmpty,
types.UpdateShortMessage, _tl.UpdateShortMessage,
types.UpdateShortChatMessage, _tl.UpdateShortChatMessage,
types.UpdateShort, _tl.UpdateShort,
types.UpdatesCombined, _tl.UpdatesCombined,
types.Updates, _tl.Updates,
types.UpdateShortSentMessage, _tl.UpdateShortSentMessage,
)), )),
has_channel_pts=frozenset(x.CONSTRUCTOR_ID for x in ( has_channel_pts=frozenset(x.CONSTRUCTOR_ID for x in (
types.UpdateChannelTooLong, _tl.UpdateChannelTooLong,
types.UpdateNewChannelMessage, _tl.UpdateNewChannelMessage,
types.UpdateDeleteChannelMessages, _tl.UpdateDeleteChannelMessages,
types.UpdateEditChannelMessage, _tl.UpdateEditChannelMessage,
types.UpdateChannelWebPage, _tl.UpdateChannelWebPage,
types.updates.ChannelDifferenceEmpty, _tl.updates.ChannelDifferenceEmpty,
types.updates.ChannelDifferenceTooLong, _tl.updates.ChannelDifferenceTooLong,
types.updates.ChannelDifference _tl.updates.ChannelDifference
)), )),
check_only=False check_only=False
): ):
@ -120,8 +120,8 @@ class StateCache:
has_channel_id=frozenset(_has_channel_id), has_channel_id=frozenset(_has_channel_id),
# Hardcoded because only some with message are for channels # Hardcoded because only some with message are for channels
has_message=frozenset(x.CONSTRUCTOR_ID for x in ( has_message=frozenset(x.CONSTRUCTOR_ID for x in (
types.UpdateNewChannelMessage, _tl.UpdateNewChannelMessage,
types.UpdateEditChannelMessage _tl.UpdateEditChannelMessage
)) ))
): ):
""" """

View File

@ -21,7 +21,7 @@ from types import GeneratorType
from .extensions import markdown, html from .extensions import markdown, html
from .helpers import add_surrogate, del_surrogate, strip_text from .helpers import add_surrogate, del_surrogate, strip_text
from .tl import types from . import _tl
try: try:
import hachoir import hachoir
@ -32,26 +32,26 @@ except ImportError:
# Register some of the most common mime-types to avoid any issues. # Register some of the most common mime-types to avoid any issues.
# See https://github.com/LonamiWebs/Telethon/issues/1096. # See https://github.com/LonamiWebs/Telethon/issues/1096.
mimetypes.add_type('image/png', '.png') mime_tl.add_type('image/png', '.png')
mimetypes.add_type('image/jpeg', '.jpeg') mime_tl.add_type('image/jpeg', '.jpeg')
mimetypes.add_type('image/webp', '.webp') mime_tl.add_type('image/webp', '.webp')
mimetypes.add_type('image/gif', '.gif') mime_tl.add_type('image/gif', '.gif')
mimetypes.add_type('image/bmp', '.bmp') mime_tl.add_type('image/bmp', '.bmp')
mimetypes.add_type('image/x-tga', '.tga') mime_tl.add_type('image/x-tga', '.tga')
mimetypes.add_type('image/tiff', '.tiff') mime_tl.add_type('image/tiff', '.tiff')
mimetypes.add_type('image/vnd.adobe.photoshop', '.psd') mime_tl.add_type('image/vnd.adobe.photoshop', '.psd')
mimetypes.add_type('video/mp4', '.mp4') mime_tl.add_type('video/mp4', '.mp4')
mimetypes.add_type('video/quicktime', '.mov') mime_tl.add_type('video/quicktime', '.mov')
mimetypes.add_type('video/avi', '.avi') mime_tl.add_type('video/avi', '.avi')
mimetypes.add_type('audio/mpeg', '.mp3') mime_tl.add_type('audio/mpeg', '.mp3')
mimetypes.add_type('audio/m4a', '.m4a') mime_tl.add_type('audio/m4a', '.m4a')
mimetypes.add_type('audio/aac', '.aac') mime_tl.add_type('audio/aac', '.aac')
mimetypes.add_type('audio/ogg', '.ogg') mime_tl.add_type('audio/ogg', '.ogg')
mimetypes.add_type('audio/flac', '.flac') mime_tl.add_type('audio/flac', '.flac')
mimetypes.add_type('application/x-tgsticker', '.tgs') mime_tl.add_type('application/x-tgsticker', '.tgs')
USERNAME_RE = re.compile( USERNAME_RE = re.compile(
r'@|(?:https?://)?(?:www\.)?(?:telegram\.(?:me|dog)|t\.me)/(@|joinchat/)?' r'@|(?:https?://)?(?:www\.)?(?:telegram\.(?:me|dog)|t\.me)/(@|joinchat/)?'
@ -92,7 +92,7 @@ def get_display_name(entity):
Gets the display name for the given :tl:`User`, Gets the display name for the given :tl:`User`,
:tl:`Chat` or :tl:`Channel`. Returns an empty string otherwise. :tl:`Chat` or :tl:`Channel`. Returns an empty string otherwise.
""" """
if isinstance(entity, types.User): if isinstance(entity, _tl.User):
if entity.last_name and entity.first_name: if entity.last_name and entity.first_name:
return '{} {}'.format(entity.first_name, entity.last_name) return '{} {}'.format(entity.first_name, entity.last_name)
elif entity.first_name: elif entity.first_name:
@ -102,7 +102,7 @@ def get_display_name(entity):
else: else:
return '' return ''
elif isinstance(entity, (types.Chat, types.ChatForbidden, types.Channel)): elif isinstance(entity, (_tl.Chat, _tl.ChatForbidden, _tl.Channel)):
return entity.title return entity.title
return '' return ''
@ -117,14 +117,14 @@ def get_extension(media):
return '.jpg' return '.jpg'
except TypeError: except TypeError:
# These cases are not handled by input photo because it can't # These cases are not handled by input photo because it can't
if isinstance(media, (types.UserProfilePhoto, types.ChatPhoto)): if isinstance(media, (_tl.UserProfilePhoto, _tl.ChatPhoto)):
return '.jpg' return '.jpg'
# Documents will come with a mime type # Documents will come with a mime type
if isinstance(media, types.MessageMediaDocument): if isinstance(media, _tl.MessageMediaDocument):
media = media.document media = media.document
if isinstance(media, ( if isinstance(media, (
types.Document, types.WebDocument, types.WebDocumentNoProxy)): _tl.Document, _tl.WebDocument, _tl.WebDocumentNoProxy)):
if media.mime_type == 'application/octet-stream': if media.mime_type == 'application/octet-stream':
# Octet stream are just bytes, which have no default extension # Octet stream are just bytes, which have no default extension
return '' return ''
@ -184,53 +184,53 @@ def get_input_peer(entity, allow_self=True, check_hash=True):
else: else:
_raise_cast_fail(entity, 'InputPeer') _raise_cast_fail(entity, 'InputPeer')
if isinstance(entity, types.User): if isinstance(entity, _tl.User):
if entity.is_self and allow_self: if entity.is_self and allow_self:
return types.InputPeerSelf() return _tl.InputPeerSelf()
elif (entity.access_hash is not None and not entity.min) or not check_hash: elif (entity.access_hash is not None and not entity.min) or not check_hash:
return types.InputPeerUser(entity.id, entity.access_hash) return _tl.InputPeerUser(entity.id, entity.access_hash)
else: else:
raise TypeError('User without access_hash or min info cannot be input') raise TypeError('User without access_hash or min info cannot be input')
if isinstance(entity, (types.Chat, types.ChatEmpty, types.ChatForbidden)): if isinstance(entity, (_tl.Chat, _tl.ChatEmpty, _tl.ChatForbidden)):
return types.InputPeerChat(entity.id) return _tl.InputPeerChat(entity.id)
if isinstance(entity, types.Channel): if isinstance(entity, _tl.Channel):
if (entity.access_hash is not None and not entity.min) or not check_hash: if (entity.access_hash is not None and not entity.min) or not check_hash:
return types.InputPeerChannel(entity.id, entity.access_hash) return _tl.InputPeerChannel(entity.id, entity.access_hash)
else: else:
raise TypeError('Channel without access_hash or min info cannot be input') raise TypeError('Channel without access_hash or min info cannot be input')
if isinstance(entity, types.ChannelForbidden): if isinstance(entity, _tl.ChannelForbidden):
# "channelForbidden are never min", and since their hash is # "channelForbidden are never min", and since their hash is
# also not optional, we assume that this truly is the case. # also not optional, we assume that this truly is the case.
return types.InputPeerChannel(entity.id, entity.access_hash) return _tl.InputPeerChannel(entity.id, entity.access_hash)
if isinstance(entity, types.InputUser): if isinstance(entity, _tl.InputUser):
return types.InputPeerUser(entity.user_id, entity.access_hash) return _tl.InputPeerUser(entity.user_id, entity.access_hash)
if isinstance(entity, types.InputChannel): if isinstance(entity, _tl.InputChannel):
return types.InputPeerChannel(entity.channel_id, entity.access_hash) return _tl.InputPeerChannel(entity.channel_id, entity.access_hash)
if isinstance(entity, types.InputUserSelf): if isinstance(entity, _tl.InputUserSelf):
return types.InputPeerSelf() return _tl.InputPeerSelf()
if isinstance(entity, types.InputUserFromMessage): if isinstance(entity, _tl.InputUserFromMessage):
return types.InputPeerUserFromMessage(entity.peer, entity.msg_id, entity.user_id) return _tl.InputPeerUserFromMessage(entity.peer, entity.msg_id, entity.user_id)
if isinstance(entity, types.InputChannelFromMessage): if isinstance(entity, _tl.InputChannelFromMessage):
return types.InputPeerChannelFromMessage(entity.peer, entity.msg_id, entity.channel_id) return _tl.InputPeerChannelFromMessage(entity.peer, entity.msg_id, entity.channel_id)
if isinstance(entity, types.UserEmpty): if isinstance(entity, _tl.UserEmpty):
return types.InputPeerEmpty() return _tl.InputPeerEmpty()
if isinstance(entity, types.UserFull): if isinstance(entity, _tl.UserFull):
return get_input_peer(entity.user) return get_input_peer(entity.user)
if isinstance(entity, types.ChatFull): if isinstance(entity, _tl.ChatFull):
return types.InputPeerChat(entity.id) return _tl.InputPeerChat(entity.id)
if isinstance(entity, types.PeerChat): if isinstance(entity, _tl.PeerChat):
return types.InputPeerChat(entity.chat_id) return _tl.InputPeerChat(entity.chat_id)
_raise_cast_fail(entity, 'InputPeer') _raise_cast_fail(entity, 'InputPeer')
@ -251,14 +251,14 @@ def get_input_channel(entity):
except AttributeError: except AttributeError:
_raise_cast_fail(entity, 'InputChannel') _raise_cast_fail(entity, 'InputChannel')
if isinstance(entity, (types.Channel, types.ChannelForbidden)): if isinstance(entity, (_tl.Channel, _tl.ChannelForbidden)):
return types.InputChannel(entity.id, entity.access_hash or 0) return _tl.InputChannel(entity.id, entity.access_hash or 0)
if isinstance(entity, types.InputPeerChannel): if isinstance(entity, _tl.InputPeerChannel):
return types.InputChannel(entity.channel_id, entity.access_hash) return _tl.InputChannel(entity.channel_id, entity.access_hash)
if isinstance(entity, types.InputPeerChannelFromMessage): if isinstance(entity, _tl.InputPeerChannelFromMessage):
return types.InputChannelFromMessage(entity.peer, entity.msg_id, entity.channel_id) return _tl.InputChannelFromMessage(entity.peer, entity.msg_id, entity.channel_id)
_raise_cast_fail(entity, 'InputChannel') _raise_cast_fail(entity, 'InputChannel')
@ -279,26 +279,26 @@ def get_input_user(entity):
except AttributeError: except AttributeError:
_raise_cast_fail(entity, 'InputUser') _raise_cast_fail(entity, 'InputUser')
if isinstance(entity, types.User): if isinstance(entity, _tl.User):
if entity.is_self: if entity.is_self:
return types.InputUserSelf() return _tl.InputUserSelf()
else: else:
return types.InputUser(entity.id, entity.access_hash or 0) return _tl.InputUser(entity.id, entity.access_hash or 0)
if isinstance(entity, types.InputPeerSelf): if isinstance(entity, _tl.InputPeerSelf):
return types.InputUserSelf() return _tl.InputUserSelf()
if isinstance(entity, (types.UserEmpty, types.InputPeerEmpty)): if isinstance(entity, (_tl.UserEmpty, _tl.InputPeerEmpty)):
return types.InputUserEmpty() return _tl.InputUserEmpty()
if isinstance(entity, types.UserFull): if isinstance(entity, _tl.UserFull):
return get_input_user(entity.user) return get_input_user(entity.user)
if isinstance(entity, types.InputPeerUser): if isinstance(entity, _tl.InputPeerUser):
return types.InputUser(entity.user_id, entity.access_hash) return _tl.InputUser(entity.user_id, entity.access_hash)
if isinstance(entity, types.InputPeerUserFromMessage): if isinstance(entity, _tl.InputPeerUserFromMessage):
return types.InputUserFromMessage(entity.peer, entity.msg_id, entity.user_id) return _tl.InputUserFromMessage(entity.peer, entity.msg_id, entity.user_id)
_raise_cast_fail(entity, 'InputUser') _raise_cast_fail(entity, 'InputUser')
@ -309,12 +309,12 @@ def get_input_dialog(dialog):
if dialog.SUBCLASS_OF_ID == 0xa21c9795: # crc32(b'InputDialogPeer') if dialog.SUBCLASS_OF_ID == 0xa21c9795: # crc32(b'InputDialogPeer')
return dialog return dialog
if dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer') if dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
return types.InputDialogPeer(dialog) return _tl.InputDialogPeer(dialog)
except AttributeError: except AttributeError:
_raise_cast_fail(dialog, 'InputDialogPeer') _raise_cast_fail(dialog, 'InputDialogPeer')
try: try:
return types.InputDialogPeer(get_input_peer(dialog)) return _tl.InputDialogPeer(get_input_peer(dialog))
except TypeError: except TypeError:
pass pass
@ -329,18 +329,18 @@ def get_input_document(document):
except AttributeError: except AttributeError:
_raise_cast_fail(document, 'InputDocument') _raise_cast_fail(document, 'InputDocument')
if isinstance(document, types.Document): if isinstance(document, _tl.Document):
return types.InputDocument( return _tl.InputDocument(
id=document.id, access_hash=document.access_hash, id=document.id, access_hash=document.access_hash,
file_reference=document.file_reference) file_reference=document.file_reference)
if isinstance(document, types.DocumentEmpty): if isinstance(document, _tl.DocumentEmpty):
return types.InputDocumentEmpty() return _tl.InputDocumentEmpty()
if isinstance(document, types.MessageMediaDocument): if isinstance(document, _tl.MessageMediaDocument):
return get_input_document(document.document) return get_input_document(document.document)
if isinstance(document, types.Message): if isinstance(document, _tl.Message):
return get_input_document(document.media) return get_input_document(document.media)
_raise_cast_fail(document, 'InputDocument') _raise_cast_fail(document, 'InputDocument')
@ -354,32 +354,32 @@ def get_input_photo(photo):
except AttributeError: except AttributeError:
_raise_cast_fail(photo, 'InputPhoto') _raise_cast_fail(photo, 'InputPhoto')
if isinstance(photo, types.Message): if isinstance(photo, _tl.Message):
photo = photo.media photo = photo.media
if isinstance(photo, (types.photos.Photo, types.MessageMediaPhoto)): if isinstance(photo, (_tl.photos.Photo, _tl.MessageMediaPhoto)):
photo = photo.photo photo = photo.photo
if isinstance(photo, types.Photo): if isinstance(photo, _tl.Photo):
return types.InputPhoto(id=photo.id, access_hash=photo.access_hash, return _tl.InputPhoto(id=photo.id, access_hash=photo.access_hash,
file_reference=photo.file_reference) file_reference=photo.file_reference)
if isinstance(photo, types.PhotoEmpty): if isinstance(photo, _tl.PhotoEmpty):
return types.InputPhotoEmpty() return _tl.InputPhotoEmpty()
if isinstance(photo, types.messages.ChatFull): if isinstance(photo, _tl.messages.ChatFull):
photo = photo.full_chat photo = photo.full_chat
if isinstance(photo, types.ChannelFull): if isinstance(photo, _tl.ChannelFull):
return get_input_photo(photo.chat_photo) return get_input_photo(photo.chat_photo)
elif isinstance(photo, types.UserFull): elif isinstance(photo, _tl.UserFull):
return get_input_photo(photo.profile_photo) return get_input_photo(photo.profile_photo)
elif isinstance(photo, (types.Channel, types.Chat, types.User)): elif isinstance(photo, (_tl.Channel, _tl.Chat, _tl.User)):
return get_input_photo(photo.photo) return get_input_photo(photo.photo)
if isinstance(photo, (types.UserEmpty, types.ChatEmpty, if isinstance(photo, (_tl.UserEmpty, _tl.ChatEmpty,
types.ChatForbidden, types.ChannelForbidden)): _tl.ChatForbidden, _tl.ChannelForbidden)):
return types.InputPhotoEmpty() return _tl.InputPhotoEmpty()
_raise_cast_fail(photo, 'InputPhoto') _raise_cast_fail(photo, 'InputPhoto')
@ -390,15 +390,15 @@ def get_input_chat_photo(photo):
if photo.SUBCLASS_OF_ID == 0xd4eb2d74: # crc32(b'InputChatPhoto') if photo.SUBCLASS_OF_ID == 0xd4eb2d74: # crc32(b'InputChatPhoto')
return photo return photo
elif photo.SUBCLASS_OF_ID == 0xe7655f1f: # crc32(b'InputFile'): elif photo.SUBCLASS_OF_ID == 0xe7655f1f: # crc32(b'InputFile'):
return types.InputChatUploadedPhoto(photo) return _tl.InputChatUploadedPhoto(photo)
except AttributeError: except AttributeError:
_raise_cast_fail(photo, 'InputChatPhoto') _raise_cast_fail(photo, 'InputChatPhoto')
photo = get_input_photo(photo) photo = get_input_photo(photo)
if isinstance(photo, types.InputPhoto): if isinstance(photo, _tl.InputPhoto):
return types.InputChatPhoto(photo) return _tl.InputChatPhoto(photo)
elif isinstance(photo, types.InputPhotoEmpty): elif isinstance(photo, _tl.InputPhotoEmpty):
return types.InputChatPhotoEmpty() return _tl.InputChatPhotoEmpty()
_raise_cast_fail(photo, 'InputChatPhoto') _raise_cast_fail(photo, 'InputChatPhoto')
@ -411,16 +411,16 @@ def get_input_geo(geo):
except AttributeError: except AttributeError:
_raise_cast_fail(geo, 'InputGeoPoint') _raise_cast_fail(geo, 'InputGeoPoint')
if isinstance(geo, types.GeoPoint): if isinstance(geo, _tl.GeoPoint):
return types.InputGeoPoint(lat=geo.lat, long=geo.long) return _tl.InputGeoPoint(lat=geo.lat, long=geo.long)
if isinstance(geo, types.GeoPointEmpty): if isinstance(geo, _tl.GeoPointEmpty):
return types.InputGeoPointEmpty() return _tl.InputGeoPointEmpty()
if isinstance(geo, types.MessageMediaGeo): if isinstance(geo, _tl.MessageMediaGeo):
return get_input_geo(geo.geo) return get_input_geo(geo.geo)
if isinstance(geo, types.Message): if isinstance(geo, _tl.Message):
return get_input_geo(geo.media) return get_input_geo(geo.media)
_raise_cast_fail(geo, 'InputGeoPoint') _raise_cast_fail(geo, 'InputGeoPoint')
@ -443,39 +443,39 @@ def get_input_media(
if media.SUBCLASS_OF_ID == 0xfaf846f4: # crc32(b'InputMedia') if media.SUBCLASS_OF_ID == 0xfaf846f4: # crc32(b'InputMedia')
return media return media
elif media.SUBCLASS_OF_ID == 0x846363e0: # crc32(b'InputPhoto') elif media.SUBCLASS_OF_ID == 0x846363e0: # crc32(b'InputPhoto')
return types.InputMediaPhoto(media, ttl_seconds=ttl) return _tl.InputMediaPhoto(media, ttl_seconds=ttl)
elif media.SUBCLASS_OF_ID == 0xf33fdb68: # crc32(b'InputDocument') elif media.SUBCLASS_OF_ID == 0xf33fdb68: # crc32(b'InputDocument')
return types.InputMediaDocument(media, ttl_seconds=ttl) return _tl.InputMediaDocument(media, ttl_seconds=ttl)
except AttributeError: except AttributeError:
_raise_cast_fail(media, 'InputMedia') _raise_cast_fail(media, 'InputMedia')
if isinstance(media, types.MessageMediaPhoto): if isinstance(media, _tl.MessageMediaPhoto):
return types.InputMediaPhoto( return _tl.InputMediaPhoto(
id=get_input_photo(media.photo), id=get_input_photo(media.photo),
ttl_seconds=ttl or media.ttl_seconds ttl_seconds=ttl or media.ttl_seconds
) )
if isinstance(media, (types.Photo, types.photos.Photo, types.PhotoEmpty)): if isinstance(media, (_tl.Photo, _tl.photos.Photo, _tl.PhotoEmpty)):
return types.InputMediaPhoto( return _tl.InputMediaPhoto(
id=get_input_photo(media), id=get_input_photo(media),
ttl_seconds=ttl ttl_seconds=ttl
) )
if isinstance(media, types.MessageMediaDocument): if isinstance(media, _tl.MessageMediaDocument):
return types.InputMediaDocument( return _tl.InputMediaDocument(
id=get_input_document(media.document), id=get_input_document(media.document),
ttl_seconds=ttl or media.ttl_seconds ttl_seconds=ttl or media.ttl_seconds
) )
if isinstance(media, (types.Document, types.DocumentEmpty)): if isinstance(media, (_tl.Document, _tl.DocumentEmpty)):
return types.InputMediaDocument( return _tl.InputMediaDocument(
id=get_input_document(media), id=get_input_document(media),
ttl_seconds=ttl ttl_seconds=ttl
) )
if isinstance(media, (types.InputFile, types.InputFileBig)): if isinstance(media, (_tl.InputFile, _tl.InputFileBig)):
if is_photo: if is_photo:
return types.InputMediaUploadedPhoto(file=media, ttl_seconds=ttl) return _tl.InputMediaUploadedPhoto(file=media, ttl_seconds=ttl)
else: else:
attrs, mime = get_attributes( attrs, mime = get_attributes(
media, media,
@ -485,29 +485,29 @@ def get_input_media(
video_note=video_note, video_note=video_note,
supports_streaming=supports_streaming supports_streaming=supports_streaming
) )
return types.InputMediaUploadedDocument( return _tl.InputMediaUploadedDocument(
file=media, mime_type=mime, attributes=attrs, force_file=force_document, file=media, mime_type=mime, attributes=attrs, force_file=force_document,
ttl_seconds=ttl) ttl_seconds=ttl)
if isinstance(media, types.MessageMediaGame): if isinstance(media, _tl.MessageMediaGame):
return types.InputMediaGame(id=types.InputGameID( return _tl.InputMediaGame(id=_tl.InputGameID(
id=media.game.id, id=media.game.id,
access_hash=media.game.access_hash access_hash=media.game.access_hash
)) ))
if isinstance(media, types.MessageMediaContact): if isinstance(media, _tl.MessageMediaContact):
return types.InputMediaContact( return _tl.InputMediaContact(
phone_number=media.phone_number, phone_number=media.phone_number,
first_name=media.first_name, first_name=media.first_name,
last_name=media.last_name, last_name=media.last_name,
vcard='' vcard=''
) )
if isinstance(media, types.MessageMediaGeo): if isinstance(media, _tl.MessageMediaGeo):
return types.InputMediaGeoPoint(geo_point=get_input_geo(media.geo)) return _tl.InputMediaGeoPoint(geo_point=get_input_geo(media.geo))
if isinstance(media, types.MessageMediaVenue): if isinstance(media, _tl.MessageMediaVenue):
return types.InputMediaVenue( return _tl.InputMediaVenue(
geo_point=get_input_geo(media.geo), geo_point=get_input_geo(media.geo),
title=media.title, title=media.title,
address=media.address, address=media.address,
@ -516,19 +516,19 @@ def get_input_media(
venue_type='' venue_type=''
) )
if isinstance(media, types.MessageMediaDice): if isinstance(media, _tl.MessageMediaDice):
return types.InputMediaDice(media.emoticon) return _tl.InputMediaDice(media.emoticon)
if isinstance(media, ( if isinstance(media, (
types.MessageMediaEmpty, types.MessageMediaUnsupported, _tl.MessageMediaEmpty, _tl.MessageMediaUnsupported,
types.ChatPhotoEmpty, types.UserProfilePhotoEmpty, _tl.ChatPhotoEmpty, _tl.UserProfilePhotoEmpty,
types.ChatPhoto, types.UserProfilePhoto)): _tl.ChatPhoto, _tl.UserProfilePhoto)):
return types.InputMediaEmpty() return _tl.InputMediaEmpty()
if isinstance(media, types.Message): if isinstance(media, _tl.Message):
return get_input_media(media.media, is_photo=is_photo, ttl=ttl) return get_input_media(media.media, is_photo=is_photo, ttl=ttl)
if isinstance(media, types.MessageMediaPoll): if isinstance(media, _tl.MessageMediaPoll):
if media.poll.quiz: if media.poll.quiz:
if not media.results.results: if not media.results.results:
# A quiz has correct answers, which we don't know until answered. # A quiz has correct answers, which we don't know until answered.
@ -539,15 +539,15 @@ def get_input_media(
else: else:
correct_answers = None correct_answers = None
return types.InputMediaPoll( return _tl.InputMediaPoll(
poll=media.poll, poll=media.poll,
correct_answers=correct_answers, correct_answers=correct_answers,
solution=media.results.solution, solution=media.results.solution,
solution_entities=media.results.solution_entities, solution_entities=media.results.solution_entities,
) )
if isinstance(media, types.Poll): if isinstance(media, _tl.Poll):
return types.InputMediaPoll(media) return _tl.InputMediaPoll(media)
_raise_cast_fail(media, 'InputMedia') _raise_cast_fail(media, 'InputMedia')
@ -556,11 +556,11 @@ def get_input_message(message):
"""Similar to :meth:`get_input_peer`, but for input messages.""" """Similar to :meth:`get_input_peer`, but for input messages."""
try: try:
if isinstance(message, int): # This case is really common too if isinstance(message, int): # This case is really common too
return types.InputMessageID(message) return _tl.InputMessageID(message)
elif message.SUBCLASS_OF_ID == 0x54b6bcc5: # crc32(b'InputMessage'): elif message.SUBCLASS_OF_ID == 0x54b6bcc5: # crc32(b'InputMessage'):
return message return message
elif message.SUBCLASS_OF_ID == 0x790009e3: # crc32(b'Message'): elif message.SUBCLASS_OF_ID == 0x790009e3: # crc32(b'Message'):
return types.InputMessageID(message.id) return _tl.InputMessageID(message.id)
except AttributeError: except AttributeError:
pass pass
@ -573,7 +573,7 @@ def get_input_group_call(call):
if call.SUBCLASS_OF_ID == 0x58611ab1: # crc32(b'InputGroupCall') if call.SUBCLASS_OF_ID == 0x58611ab1: # crc32(b'InputGroupCall')
return call return call
elif call.SUBCLASS_OF_ID == 0x20b4f320: # crc32(b'GroupCall') elif call.SUBCLASS_OF_ID == 0x20b4f320: # crc32(b'GroupCall')
return types.InputGroupCall(id=call.id, access_hash=call.access_hash) return _tl.InputGroupCall(id=call.id, access_hash=call.access_hash)
except AttributeError: except AttributeError:
_raise_cast_fail(call, 'InputGroupCall') _raise_cast_fail(call, 'InputGroupCall')
@ -675,10 +675,10 @@ def get_attributes(file, *, attributes=None, mime_type=None,
# Note: ``file.name`` works for :tl:`InputFile` and some `IOBase` streams # Note: ``file.name`` works for :tl:`InputFile` and some `IOBase` streams
name = file if isinstance(file, str) else getattr(file, 'name', 'unnamed') name = file if isinstance(file, str) else getattr(file, 'name', 'unnamed')
if mime_type is None: if mime_type is None:
mime_type = mimetypes.guess_type(name)[0] mime_type = mime_tl.guess_type(name)[0]
attr_dict = {types.DocumentAttributeFilename: attr_dict = {_tl.DocumentAttributeFilename:
types.DocumentAttributeFilename(os.path.basename(name))} _tl.DocumentAttributeFilename(os.path.basename(name))}
if is_audio(file): if is_audio(file):
m = _get_metadata(file) m = _get_metadata(file)
@ -690,8 +690,8 @@ def get_attributes(file, *, attributes=None, mime_type=None,
else: else:
performer = None performer = None
attr_dict[types.DocumentAttributeAudio] = \ attr_dict[_tl.DocumentAttributeAudio] = \
types.DocumentAttributeAudio( _tl.DocumentAttributeAudio(
voice=voice_note, voice=voice_note,
title=m.get('title') if m.has('title') else None, title=m.get('title') if m.has('title') else None,
performer=performer, performer=performer,
@ -702,7 +702,7 @@ def get_attributes(file, *, attributes=None, mime_type=None,
if not force_document and is_video(file): if not force_document and is_video(file):
m = _get_metadata(file) m = _get_metadata(file)
if m: if m:
doc = types.DocumentAttributeVideo( doc = _tl.DocumentAttributeVideo(
round_message=video_note, round_message=video_note,
w=m.get('width') if m.has('width') else 1, w=m.get('width') if m.has('width') else 1,
h=m.get('height') if m.has('height') else 1, h=m.get('height') if m.has('height') else 1,
@ -719,22 +719,22 @@ def get_attributes(file, *, attributes=None, mime_type=None,
if t_m and t_m.has("height"): if t_m and t_m.has("height"):
height = t_m.get("height") height = t_m.get("height")
doc = types.DocumentAttributeVideo( doc = _tl.DocumentAttributeVideo(
0, width, height, round_message=video_note, 0, width, height, round_message=video_note,
supports_streaming=supports_streaming) supports_streaming=supports_streaming)
else: else:
doc = types.DocumentAttributeVideo( doc = _tl.DocumentAttributeVideo(
0, 1, 1, round_message=video_note, 0, 1, 1, round_message=video_note,
supports_streaming=supports_streaming) supports_streaming=supports_streaming)
attr_dict[types.DocumentAttributeVideo] = doc attr_dict[_tl.DocumentAttributeVideo] = doc
if voice_note: if voice_note:
if types.DocumentAttributeAudio in attr_dict: if _tl.DocumentAttributeAudio in attr_dict:
attr_dict[types.DocumentAttributeAudio].voice = True attr_dict[_tl.DocumentAttributeAudio].voice = True
else: else:
attr_dict[types.DocumentAttributeAudio] = \ attr_dict[_tl.DocumentAttributeAudio] = \
types.DocumentAttributeAudio(0, voice=True) _tl.DocumentAttributeAudio(0, voice=True)
# Now override the attributes if any. As we have a dict of # Now override the attributes if any. As we have a dict of
# {cls: instance}, we can override any class with the list # {cls: instance}, we can override any class with the list
@ -803,23 +803,23 @@ def _get_file_info(location):
except AttributeError: except AttributeError:
_raise_cast_fail(location, 'InputFileLocation') _raise_cast_fail(location, 'InputFileLocation')
if isinstance(location, types.Message): if isinstance(location, _tl.Message):
location = location.media location = location.media
if isinstance(location, types.MessageMediaDocument): if isinstance(location, _tl.MessageMediaDocument):
location = location.document location = location.document
elif isinstance(location, types.MessageMediaPhoto): elif isinstance(location, _tl.MessageMediaPhoto):
location = location.photo location = location.photo
if isinstance(location, types.Document): if isinstance(location, _tl.Document):
return _FileInfo(location.dc_id, types.InputDocumentFileLocation( return _FileInfo(location.dc_id, _tl.InputDocumentFileLocation(
id=location.id, id=location.id,
access_hash=location.access_hash, access_hash=location.access_hash,
file_reference=location.file_reference, file_reference=location.file_reference,
thumb_size='' # Presumably to download one of its thumbnails thumb_size='' # Presumably to download one of its thumbnails
), location.size) ), location.size)
elif isinstance(location, types.Photo): elif isinstance(location, _tl.Photo):
return _FileInfo(location.dc_id, types.InputPhotoFileLocation( return _FileInfo(location.dc_id, _tl.InputPhotoFileLocation(
id=location.id, id=location.id,
access_hash=location.access_hash, access_hash=location.access_hash,
file_reference=location.file_reference, file_reference=location.file_reference,
@ -860,7 +860,7 @@ def is_image(file):
if match: if match:
return True return True
else: else:
return isinstance(resolve_bot_file_id(file), types.Photo) return isinstance(resolve_bot_file_id(file), _tl.Photo)
def is_gif(file): def is_gif(file):
@ -881,7 +881,7 @@ def is_audio(file):
return False return False
else: else:
file = 'a' + ext file = 'a' + ext
return (mimetypes.guess_type(file)[0] or '').startswith('audio/') return (mime_tl.guess_type(file)[0] or '').startswith('audio/')
def is_video(file): def is_video(file):
@ -895,7 +895,7 @@ def is_video(file):
return False return False
else: else:
file = 'a' + ext file = 'a' + ext
return (mimetypes.guess_type(file)[0] or '').startswith('video/') return (mime_tl.guess_type(file)[0] or '').startswith('video/')
def is_list_like(obj): def is_list_like(obj):
@ -971,27 +971,27 @@ def get_peer(peer):
elif peer.SUBCLASS_OF_ID == 0x2d45687: elif peer.SUBCLASS_OF_ID == 0x2d45687:
return peer return peer
elif isinstance(peer, ( elif isinstance(peer, (
types.contacts.ResolvedPeer, types.InputNotifyPeer, _tl.contacts.ResolvedPeer, _tl.InputNotifyPeer,
types.TopPeer, types.Dialog, types.DialogPeer)): _tl.TopPeer, _tl.Dialog, _tl.DialogPeer)):
return peer.peer return peer.peer
elif isinstance(peer, types.ChannelFull): elif isinstance(peer, _tl.ChannelFull):
return types.PeerChannel(peer.id) return _tl.PeerChannel(peer.id)
elif isinstance(peer, types.UserEmpty): elif isinstance(peer, _tl.UserEmpty):
return types.PeerUser(peer.id) return _tl.PeerUser(peer.id)
elif isinstance(peer, types.ChatEmpty): elif isinstance(peer, _tl.ChatEmpty):
return types.PeerChat(peer.id) return _tl.PeerChat(peer.id)
if peer.SUBCLASS_OF_ID in (0x7d7c6f86, 0xd9c7fc18): if peer.SUBCLASS_OF_ID in (0x7d7c6f86, 0xd9c7fc18):
# ChatParticipant, ChannelParticipant # ChatParticipant, ChannelParticipant
return types.PeerUser(peer.user_id) return _tl.PeerUser(peer.user_id)
peer = get_input_peer(peer, allow_self=False, check_hash=False) peer = get_input_peer(peer, allow_self=False, check_hash=False)
if isinstance(peer, (types.InputPeerUser, types.InputPeerUserFromMessage)): if isinstance(peer, (_tl.InputPeerUser, _tl.InputPeerUserFromMessage)):
return types.PeerUser(peer.user_id) return _tl.PeerUser(peer.user_id)
elif isinstance(peer, types.InputPeerChat): elif isinstance(peer, _tl.InputPeerChat):
return types.PeerChat(peer.chat_id) return _tl.PeerChat(peer.chat_id)
elif isinstance(peer, (types.InputPeerChannel, types.InputPeerChannelFromMessage)): elif isinstance(peer, (_tl.InputPeerChannel, _tl.InputPeerChannelFromMessage)):
return types.PeerChannel(peer.channel_id) return _tl.PeerChannel(peer.channel_id)
except (AttributeError, TypeError): except (AttributeError, TypeError):
pass pass
_raise_cast_fail(peer, 'Peer') _raise_cast_fail(peer, 'Peer')
@ -1017,7 +1017,7 @@ def get_peer_id(peer, add_mark=True):
return peer if add_mark else resolve_id(peer)[0] return peer if add_mark else resolve_id(peer)[0]
# Tell the user to use their client to resolve InputPeerSelf if we got one # Tell the user to use their client to resolve InputPeerSelf if we got one
if isinstance(peer, types.InputPeerSelf): if isinstance(peer, _tl.InputPeerSelf):
_raise_cast_fail(peer, 'int (you might want to use client.get_peer_id)') _raise_cast_fail(peer, 'int (you might want to use client.get_peer_id)')
try: try:
@ -1025,15 +1025,15 @@ def get_peer_id(peer, add_mark=True):
except TypeError: except TypeError:
_raise_cast_fail(peer, 'int') _raise_cast_fail(peer, 'int')
if isinstance(peer, types.PeerUser): if isinstance(peer, _tl.PeerUser):
return peer.user_id return peer.user_id
elif isinstance(peer, types.PeerChat): elif isinstance(peer, _tl.PeerChat):
# Check in case the user mixed things up to avoid blowing up # Check in case the user mixed things up to avoid blowing up
if not (0 < peer.chat_id <= 0x7fffffff): if not (0 < peer.chat_id <= 0x7fffffff):
peer.chat_id = resolve_id(peer.chat_id)[0] peer.chat_id = resolve_id(peer.chat_id)[0]
return -peer.chat_id if add_mark else peer.chat_id return -peer.chat_id if add_mark else peer.chat_id
else: # if isinstance(peer, types.PeerChannel): else: # if isinstance(peer, _tl.PeerChannel):
# Check in case the user mixed things up to avoid blowing up # Check in case the user mixed things up to avoid blowing up
if not (0 < peer.channel_id <= 0x7fffffff): if not (0 < peer.channel_id <= 0x7fffffff):
peer.channel_id = resolve_id(peer.channel_id)[0] peer.channel_id = resolve_id(peer.channel_id)[0]
@ -1048,14 +1048,14 @@ def get_peer_id(peer, add_mark=True):
def resolve_id(marked_id): def resolve_id(marked_id):
"""Given a marked ID, returns the original ID and its :tl:`Peer` type.""" """Given a marked ID, returns the original ID and its :tl:`Peer` type."""
if marked_id >= 0: if marked_id >= 0:
return marked_id, types.PeerUser return marked_id, _tl.PeerUser
marked_id = -marked_id marked_id = -marked_id
if marked_id > 1000000000000: if marked_id > 1000000000000:
marked_id -= 1000000000000 marked_id -= 1000000000000
return marked_id, types.PeerChannel return marked_id, _tl.PeerChannel
else: else:
return marked_id, types.PeerChat return marked_id, _tl.PeerChat
def _rle_decode(data): def _rle_decode(data):
@ -1159,12 +1159,12 @@ def resolve_bot_file_id(file_id):
attributes = [] attributes = []
if file_type == 3 or file_type == 9: if file_type == 3 or file_type == 9:
attributes.append(types.DocumentAttributeAudio( attributes.append(_tl.DocumentAttributeAudio(
duration=0, duration=0,
voice=file_type == 3 voice=file_type == 3
)) ))
elif file_type == 4 or file_type == 13: elif file_type == 4 or file_type == 13:
attributes.append(types.DocumentAttributeVideo( attributes.append(_tl.DocumentAttributeVideo(
duration=0, duration=0,
w=0, w=0,
h=0, h=0,
@ -1172,14 +1172,14 @@ def resolve_bot_file_id(file_id):
)) ))
# elif file_type == 5: # other, cannot know which # elif file_type == 5: # other, cannot know which
elif file_type == 8: elif file_type == 8:
attributes.append(types.DocumentAttributeSticker( attributes.append(_tl.DocumentAttributeSticker(
alt='', alt='',
stickerset=types.InputStickerSetEmpty() stickerset=_tl.InputStickerSetEmpty()
)) ))
elif file_type == 10: elif file_type == 10:
attributes.append(types.DocumentAttributeAnimated()) attributes.append(_tl.DocumentAttributeAnimated())
return types.Document( return _tl.Document(
id=media_id, id=media_id,
access_hash=access_hash, access_hash=access_hash,
date=None, date=None,
@ -1210,12 +1210,12 @@ def resolve_bot_file_id(file_id):
# Thumbnails (small) always have ID 0; otherwise size 'x' # Thumbnails (small) always have ID 0; otherwise size 'x'
photo_size = 's' if media_id or access_hash else 'x' photo_size = 's' if media_id or access_hash else 'x'
return types.Photo( return _tl.Photo(
id=media_id, id=media_id,
access_hash=access_hash, access_hash=access_hash,
file_reference=b'', file_reference=b'',
date=None, date=None,
sizes=[types.PhotoSize( sizes=[_tl.PhotoSize(
type=photo_size, type=photo_size,
w=0, w=0,
h=0, h=0,
@ -1235,21 +1235,21 @@ def pack_bot_file_id(file):
If an invalid parameter is given, it will ``return None``. If an invalid parameter is given, it will ``return None``.
""" """
if isinstance(file, types.MessageMediaDocument): if isinstance(file, _tl.MessageMediaDocument):
file = file.document file = file.document
elif isinstance(file, types.MessageMediaPhoto): elif isinstance(file, _tl.MessageMediaPhoto):
file = file.photo file = file.photo
if isinstance(file, types.Document): if isinstance(file, _tl.Document):
file_type = 5 file_type = 5
for attribute in file.attributes: for attribute in file.attributes:
if isinstance(attribute, types.DocumentAttributeAudio): if isinstance(attribute, _tl.DocumentAttributeAudio):
file_type = 3 if attribute.voice else 9 file_type = 3 if attribute.voice else 9
elif isinstance(attribute, types.DocumentAttributeVideo): elif isinstance(attribute, _tl.DocumentAttributeVideo):
file_type = 13 if attribute.round_message else 4 file_type = 13 if attribute.round_message else 4
elif isinstance(attribute, types.DocumentAttributeSticker): elif isinstance(attribute, _tl.DocumentAttributeSticker):
file_type = 8 file_type = 8
elif isinstance(attribute, types.DocumentAttributeAnimated): elif isinstance(attribute, _tl.DocumentAttributeAnimated):
file_type = 10 file_type = 10
else: else:
continue continue
@ -1258,9 +1258,9 @@ def pack_bot_file_id(file):
return _encode_telegram_base64(_rle_encode(struct.pack( return _encode_telegram_base64(_rle_encode(struct.pack(
'<iiqqb', file_type, file.dc_id, file.id, file.access_hash, 2))) '<iiqqb', file_type, file.dc_id, file.id, file.access_hash, 2)))
elif isinstance(file, types.Photo): elif isinstance(file, _tl.Photo):
size = next((x for x in reversed(file.sizes) if isinstance( size = next((x for x in reversed(file.sizes) if isinstance(
x, (types.PhotoSize, types.PhotoCachedSize))), None) x, (_tl.PhotoSize, _tl.PhotoCachedSize))), None)
if not size: if not size:
return None return None
@ -1326,7 +1326,7 @@ def resolve_inline_message_id(inline_msg_id):
try: try:
dc_id, message_id, pid, access_hash = \ dc_id, message_id, pid, access_hash = \
struct.unpack('<iiiq', _decode_telegram_base64(inline_msg_id)) struct.unpack('<iiiq', _decode_telegram_base64(inline_msg_id))
peer = types.PeerChannel(-pid) if pid < 0 else types.PeerUser(pid) peer = _tl.PeerChannel(-pid) if pid < 0 else _tl.PeerUser(pid)
return message_id, peer, dc_id, access_hash return message_id, peer, dc_id, access_hash
except (struct.error, TypeError): except (struct.error, TypeError):
return None, None, None, None return None, None, None, None
@ -1360,14 +1360,14 @@ def encode_waveform(waveform):
file = 'my.ogg' file = 'my.ogg'
# Send 'my.ogg' with a ascending-triangle waveform # Send 'my.ogg' with a ascending-triangle waveform
await client.send_file(chat, file, attributes=[types.DocumentAttributeAudio( await client.send_file(chat, file, attributes=[_tl.DocumentAttributeAudio(
duration=7, duration=7,
voice=True, voice=True,
waveform=utils.encode_waveform(bytes(range(2 ** 5)) # 2**5 because 5-bit waveform=utils.encode_waveform(bytes(range(2 ** 5)) # 2**5 because 5-bit
)] )]
# Send 'my.ogg' with a square waveform # Send 'my.ogg' with a square waveform
await client.send_file(chat, file, attributes=[types.DocumentAttributeAudio( await client.send_file(chat, file, attributes=[_tl.DocumentAttributeAudio(
duration=7, duration=7,
voice=True, voice=True,
waveform=utils.encode_waveform(bytes((31, 31, 15, 15, 15, 15, 31, 31)) * 4) waveform=utils.encode_waveform(bytes((31, 31, 15, 15, 15, 15, 31, 31)) * 4)
@ -1542,18 +1542,18 @@ def stripped_photo_to_jpg(stripped):
def _photo_size_byte_count(size): def _photo_size_byte_count(size):
if isinstance(size, types.PhotoSize): if isinstance(size, _tl.PhotoSize):
return size.size return size.size
elif isinstance(size, types.PhotoStrippedSize): elif isinstance(size, _tl.PhotoStrippedSize):
if len(size.bytes) < 3 or size.bytes[0] != 1: if len(size.bytes) < 3 or size.bytes[0] != 1:
return len(size.bytes) return len(size.bytes)
return len(size.bytes) + 622 return len(size.bytes) + 622
elif isinstance(size, types.PhotoCachedSize): elif isinstance(size, _tl.PhotoCachedSize):
return len(size.bytes) return len(size.bytes)
elif isinstance(size, types.PhotoSizeEmpty): elif isinstance(size, _tl.PhotoSizeEmpty):
return 0 return 0
elif isinstance(size, types.PhotoSizeProgressive): elif isinstance(size, _tl.PhotoSizeProgressive):
return max(size.sizes) return max(size.sizes)
else: else:
return None return None

View File

@ -6,17 +6,10 @@ import os
import time import time
from hashlib import sha1 from hashlib import sha1
from ..tl.types import ( from .. import helpers, _tl
ResPQ, PQInnerData, ServerDHParamsFail, ServerDHParamsOk,
ServerDHInnerData, ClientDHInnerData, DhGenOk, DhGenRetry, DhGenFail
)
from .. import helpers
from ..crypto import AES, AuthKey, Factorization, rsa from ..crypto import AES, AuthKey, Factorization, rsa
from ..errors import SecurityError from ..errors import SecurityError
from ..extensions import BinaryReader from ..extensions import BinaryReader
from ..tl.functions import (
ReqPqMultiRequest, ReqDHParamsRequest, SetClientDHParamsRequest
)
async def do_authentication(sender): async def do_authentication(sender):
@ -28,8 +21,8 @@ async def do_authentication(sender):
""" """
# Step 1 sending: PQ Request, endianness doesn't matter since it's random # Step 1 sending: PQ Request, endianness doesn't matter since it's random
nonce = int.from_bytes(os.urandom(16), 'big', signed=True) nonce = int.from_bytes(os.urandom(16), 'big', signed=True)
res_pq = await sender.send(ReqPqMultiRequest(nonce)) res_pq = await sender.send(_tl.fn.ReqPqMulti(nonce))
assert isinstance(res_pq, ResPQ), 'Step 1 answer was %s' % res_pq assert isinstance(res_pq, _tl.ResPQ), 'Step 1 answer was %s' % res_pq
if res_pq.nonce != nonce: if res_pq.nonce != nonce:
raise SecurityError('Step 1 invalid nonce from server') raise SecurityError('Step 1 invalid nonce from server')
@ -41,7 +34,7 @@ async def do_authentication(sender):
p, q = rsa.get_byte_array(p), rsa.get_byte_array(q) p, q = rsa.get_byte_array(p), rsa.get_byte_array(q)
new_nonce = int.from_bytes(os.urandom(32), 'little', signed=True) new_nonce = int.from_bytes(os.urandom(32), 'little', signed=True)
pq_inner_data = bytes(PQInnerData( pq_inner_data = bytes(_tl.PQInnerData(
pq=rsa.get_byte_array(pq), p=p, q=q, pq=rsa.get_byte_array(pq), p=p, q=q,
nonce=res_pq.nonce, nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce, server_nonce=res_pq.server_nonce,
@ -72,7 +65,7 @@ async def do_authentication(sender):
) )
) )
server_dh_params = await sender.send(ReqDHParamsRequest( server_dh_params = await sender.send(_tl.fn.ReqDHParams(
nonce=res_pq.nonce, nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce, server_nonce=res_pq.server_nonce,
p=p, q=q, p=p, q=q,
@ -81,7 +74,7 @@ async def do_authentication(sender):
)) ))
assert isinstance( assert isinstance(
server_dh_params, (ServerDHParamsOk, ServerDHParamsFail)),\ server_dh_params, (_tl.ServerDHParamsOk, _tl.ServerDHParamsFail)),\
'Step 2.1 answer was %s' % server_dh_params 'Step 2.1 answer was %s' % server_dh_params
if server_dh_params.nonce != res_pq.nonce: if server_dh_params.nonce != res_pq.nonce:
@ -90,7 +83,7 @@ async def do_authentication(sender):
if server_dh_params.server_nonce != res_pq.server_nonce: if server_dh_params.server_nonce != res_pq.server_nonce:
raise SecurityError('Step 2 invalid server nonce from server') raise SecurityError('Step 2 invalid server nonce from server')
if isinstance(server_dh_params, ServerDHParamsFail): if isinstance(server_dh_params, _tl.ServerDHParamsFail):
nnh = int.from_bytes( nnh = int.from_bytes(
sha1(new_nonce.to_bytes(32, 'little', signed=True)).digest()[4:20], sha1(new_nonce.to_bytes(32, 'little', signed=True)).digest()[4:20],
'little', signed=True 'little', signed=True
@ -98,7 +91,7 @@ async def do_authentication(sender):
if server_dh_params.new_nonce_hash != nnh: if server_dh_params.new_nonce_hash != nnh:
raise SecurityError('Step 2 invalid DH fail nonce from server') raise SecurityError('Step 2 invalid DH fail nonce from server')
assert isinstance(server_dh_params, ServerDHParamsOk),\ assert isinstance(server_dh_params, _tl.ServerDHParamsOk),\
'Step 2.2 answer was %s' % server_dh_params 'Step 2.2 answer was %s' % server_dh_params
# Step 3 sending: Complete DH Exchange # Step 3 sending: Complete DH Exchange
@ -116,7 +109,7 @@ async def do_authentication(sender):
with BinaryReader(plain_text_answer) as reader: with BinaryReader(plain_text_answer) as reader:
reader.read(20) # hash sum reader.read(20) # hash sum
server_dh_inner = reader.tgread_object() server_dh_inner = reader.tgread_object()
assert isinstance(server_dh_inner, ServerDHInnerData),\ assert isinstance(server_dh_inner, _tl.ServerDHInnerData),\
'Step 3 answer was %s' % server_dh_inner 'Step 3 answer was %s' % server_dh_inner
if server_dh_inner.nonce != res_pq.nonce: if server_dh_inner.nonce != res_pq.nonce:
@ -157,7 +150,7 @@ async def do_authentication(sender):
raise SecurityError('g_b is not within (2^{2048-64}, dh_prime - 2^{2048-64})') raise SecurityError('g_b is not within (2^{2048-64}, dh_prime - 2^{2048-64})')
# Prepare client DH Inner Data # Prepare client DH Inner Data
client_dh_inner = bytes(ClientDHInnerData( client_dh_inner = bytes(_tl.ClientDHInnerData(
nonce=res_pq.nonce, nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce, server_nonce=res_pq.server_nonce,
retry_id=0, # TODO Actual retry ID retry_id=0, # TODO Actual retry ID
@ -170,13 +163,13 @@ async def do_authentication(sender):
client_dh_encrypted = AES.encrypt_ige(client_dh_inner_hashed, key, iv) client_dh_encrypted = AES.encrypt_ige(client_dh_inner_hashed, key, iv)
# Prepare Set client DH params # Prepare Set client DH params
dh_gen = await sender.send(SetClientDHParamsRequest( dh_gen = await sender.send(_tl.fn.SetClientDHParams(
nonce=res_pq.nonce, nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce, server_nonce=res_pq.server_nonce,
encrypted_data=client_dh_encrypted, encrypted_data=client_dh_encrypted,
)) ))
nonce_types = (DhGenOk, DhGenRetry, DhGenFail) nonce_types = (_tl.DhGenOk, _tl.DhGenRetry, _tl.DhGenFail)
assert isinstance(dh_gen, nonce_types), 'Step 3.1 answer was %s' % dh_gen assert isinstance(dh_gen, nonce_types), 'Step 3.1 answer was %s' % dh_gen
name = dh_gen.__class__.__name__ name = dh_gen.__class__.__name__
if dh_gen.nonce != res_pq.nonce: if dh_gen.nonce != res_pq.nonce:
@ -194,7 +187,7 @@ async def do_authentication(sender):
if dh_hash != new_nonce_hash: if dh_hash != new_nonce_hash:
raise SecurityError('Step 3 invalid new nonce hash') raise SecurityError('Step 3 invalid new nonce hash')
if not isinstance(dh_gen, DhGenOk): if not isinstance(dh_gen, _tl.DhGenOk):
raise AssertionError('Step 3.2 answer was %s' % dh_gen) raise AssertionError('Step 3.2 answer was %s' % dh_gen)
return auth_key, time_offset return auth_key, time_offset

View File

@ -1 +0,0 @@
from .tlobject import TLObject, TLRequest

View File

@ -140,7 +140,7 @@ class Dialog:
# Un-archiving # Un-archiving
dialog.archive(0) dialog.archive(0)
""" """
return await self._client(functions.folders.EditPeerFoldersRequest([ return await self._client(_tl.fn.folders.EditPeerFolders([
types.InputFolderPeer(self.input_entity, folder_id=folder) types.InputFolderPeer(self.input_entity, folder_id=folder)
])) ]))

View File

@ -1,8 +1,6 @@
import datetime import datetime
from .. import TLObject from ... import _tl
from ..functions.messages import SaveDraftRequest
from ..types import DraftMessage
from ...errors import RPCError from ...errors import RPCError
from ...extensions import markdown from ...extensions import markdown
from ...utils import get_input_peer, get_peer from ...utils import get_input_peer, get_peer
@ -30,8 +28,8 @@ class Draft:
self._entity = entity self._entity = entity
self._input_entity = get_input_peer(entity) if entity else None self._input_entity = get_input_peer(entity) if entity else None
if not draft or not isinstance(draft, DraftMessage): if not draft or not isinstance(draft, _tl.DraftMessage):
draft = DraftMessage('', None, None, None, None) draft = _tl.DraftMessage('', None, None, None, None)
self._text = markdown.unparse(draft.message, draft.entities) self._text = markdown.unparse(draft.message, draft.entities)
self._raw_text = draft.message self._raw_text = draft.message
@ -134,7 +132,7 @@ class Draft:
raw_text, entities =\ raw_text, entities =\
await self._client._parse_message_text(text, parse_mode) await self._client._parse_message_text(text, parse_mode)
result = await self._client(SaveDraftRequest( result = await self._client(_tl.fn.SaveDraftRequest(
peer=self._peer, peer=self._peer,
message=raw_text, message=raw_text,
no_webpage=not link_preview, no_webpage=not link_preview,
@ -184,7 +182,7 @@ class Draft:
} }
def __str__(self): def __str__(self):
return TLObject.pretty_format(self.to_dict()) return _tl.TLObject.pretty_format(self.to_dict())
def stringify(self): def stringify(self):
return TLObject.pretty_format(self.to_dict(), indent=0) return _tl.TLObject.pretty_format(self.to_dict(), indent=0)

View File

@ -197,7 +197,7 @@ class InlineBuilder:
if isinstance(media, types.InputPhoto): if isinstance(media, types.InputPhoto):
fh = media fh = media
else: else:
r = await self._client(functions.messages.UploadMediaRequest( r = await self._client(_tl.fn.messages.UploadMedia(
types.InputPeerSelf(), media=media types.InputPeerSelf(), media=media
)) ))
fh = utils.get_input_photo(r.photo) fh = utils.get_input_photo(r.photo)
@ -317,7 +317,7 @@ class InlineBuilder:
if isinstance(media, types.InputDocument): if isinstance(media, types.InputDocument):
fh = media fh = media
else: else:
r = await self._client(functions.messages.UploadMediaRequest( r = await self._client(_tl.fn.messages.UploadMedia(
types.InputPeerSelf(), media=media types.InputPeerSelf(), media=media
)) ))
fh = utils.get_input_document(r.document) fh = utils.get_input_document(r.document)

View File

@ -150,7 +150,7 @@ class InlineResult:
else: else:
reply_id = None if reply_to is None else utils.get_message_id(reply_to) reply_id = None if reply_to is None else utils.get_message_id(reply_to)
req = functions.messages.SendInlineBotResultRequest( req = _tl.fn.messages.SendInlineBotResult(
peer=entity, peer=entity,
query_id=self._query_id, query_id=self._query_id,
id=self.result.id, id=self.result.id,

View File

@ -986,7 +986,7 @@ class Message(ChatGetter, SenderGetter, TLObject):
if options is None: if options is None:
options = [] options = []
return await self._client( return await self._client(
functions.messages.SendVoteRequest( _tl.fn.messages.SendVote(
peer=self._input_chat, peer=self._input_chat,
msg_id=self.id, msg_id=self.id,
options=options options=options

View File

@ -96,10 +96,10 @@ class MessageButton:
self._chat, self.button.text, parse_mode=None) self._chat, self.button.text, parse_mode=None)
elif isinstance(self.button, types.KeyboardButtonCallback): elif isinstance(self.button, types.KeyboardButtonCallback):
if password is not None: if password is not None:
pwd = await self._client(functions.account.GetPasswordRequest()) pwd = await self._client(_tl.fn.account.GetPassword())
password = pwd_mod.compute_check(pwd, password) password = pwd_mod.compute_check(pwd, password)
req = functions.messages.GetBotCallbackAnswerRequest( req = _tl.fn.messages.GetBotCallbackAnswer(
peer=self._chat, msg_id=self._msg_id, data=self.button.data, peer=self._chat, msg_id=self._msg_id, data=self.button.data,
password=password password=password
) )
@ -108,13 +108,13 @@ class MessageButton:
except BotResponseTimeoutError: except BotResponseTimeoutError:
return None return None
elif isinstance(self.button, types.KeyboardButtonSwitchInline): elif isinstance(self.button, types.KeyboardButtonSwitchInline):
return await self._client(functions.messages.StartBotRequest( return await self._client(_tl.fn.messages.StartBot(
bot=self._bot, peer=self._chat, start_param=self.button.query bot=self._bot, peer=self._chat, start_param=self.button.query
)) ))
elif isinstance(self.button, types.KeyboardButtonUrl): elif isinstance(self.button, types.KeyboardButtonUrl):
return webbrowser.open(self.button.url) return webbrowser.open(self.button.url)
elif isinstance(self.button, types.KeyboardButtonGame): elif isinstance(self.button, types.KeyboardButtonGame):
req = functions.messages.GetBotCallbackAnswerRequest( req = _tl.fn.messages.GetBotCallbackAnswer(
peer=self._chat, msg_id=self._msg_id, game=True peer=self._chat, msg_id=self._msg_id, game=True
) )
try: try:

View File

@ -15,7 +15,7 @@ class QRLogin:
""" """
def __init__(self, client, ignored_ids): def __init__(self, client, ignored_ids):
self._client = client self._client = client
self._request = functions.auth.ExportLoginTokenRequest( self._request = _tl.fn.auth.ExportLoginToken(
self._client.api_id, self._client.api_hash, ignored_ids) self._client.api_id, self._client.api_hash, ignored_ids)
self._resp = None self._resp = None
@ -108,7 +108,7 @@ class QRLogin:
resp = await self._client(self._request) resp = await self._client(self._request)
if isinstance(resp, types.auth.LoginTokenMigrateTo): if isinstance(resp, types.auth.LoginTokenMigrateTo):
await self._client._switch_dc(resp.dc_id) await self._client._switch_dc(resp.dc_id)
resp = await self._client(functions.auth.ImportLoginTokenRequest(resp.token)) resp = await self._client(_tl.fn.auth.ImportLoginToken(resp.token))
# resp should now be auth.loginTokenSuccess # resp should now be auth.loginTokenSuccess
if isinstance(resp, types.auth.LoginTokenSuccess): if isinstance(resp, types.auth.LoginTokenSuccess):

View File

@ -1,7 +1,7 @@
"""Errors not related to the Telegram API itself""" """Errors not related to the Telegram API itself"""
import struct import struct
from ..tl import TLRequest from .. import _tl
class ReadCancelledError(Exception): class ReadCancelledError(Exception):
@ -138,7 +138,7 @@ class MultiError(Exception):
raise TypeError( raise TypeError(
"Expected an exception object, not '%r'" % e "Expected an exception object, not '%r'" % e
) )
if not isinstance(req, TLRequest): if not isinstance(req, _tl.TLRequest):
raise TypeError( raise TypeError(
"Expected TLRequest object, not '%r'" % req "Expected TLRequest object, not '%r'" % req
) )

View File

@ -1,13 +1,13 @@
from ..tl import functions from .. import _tl
_NESTS_QUERY = ( _NESTS_QUERY = (
functions.InvokeAfterMsgRequest, _tl.fn.InvokeAfterMsg,
functions.InvokeAfterMsgsRequest, _tl.fn.InvokeAfterMsgs,
functions.InitConnectionRequest, _tl.fn.InitConnection,
functions.InvokeWithLayerRequest, _tl.fn.InvokeWithLayer,
functions.InvokeWithoutUpdatesRequest, _tl.fn.InvokeWithoutUpdates,
functions.InvokeWithMessagesRangeRequest, _tl.fn.InvokeWithMessagesRange,
functions.InvokeWithTakeoutRequest, _tl.fn.InvokeWithTakeout,
) )
class RPCError(Exception): class RPCError(Exception):

View File

@ -3,9 +3,7 @@ import time
import weakref import weakref
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types
from ..tl.custom.sendergetter import SenderGetter
_IGNORE_MAX_SIZE = 100 # len() _IGNORE_MAX_SIZE = 100 # len()
_IGNORE_MAX_AGE = 5 # seconds _IGNORE_MAX_AGE = 5 # seconds
@ -101,8 +99,8 @@ class Album(EventBuilder):
return # We only care about albums which come inside the same Updates return # We only care about albums which come inside the same Updates
if isinstance(update, if isinstance(update,
(types.UpdateNewMessage, types.UpdateNewChannelMessage)): (_tl.UpdateNewMessage, _tl.UpdateNewChannelMessage)):
if not isinstance(update.message, types.Message): if not isinstance(update.message, _tl.Message):
return # We don't care about MessageService's here return # We don't care about MessageService's here
group = update.message.grouped_id group = update.message.grouped_id
@ -130,8 +128,8 @@ class Album(EventBuilder):
# Figure out which updates share the same group and use those # Figure out which updates share the same group and use those
return cls.Event([ return cls.Event([
u.message for u in others u.message for u in others
if (isinstance(u, (types.UpdateNewMessage, types.UpdateNewChannelMessage)) if (isinstance(u, (_tl.UpdateNewMessage, _tl.UpdateNewChannelMessage))
and isinstance(u.message, types.Message) and isinstance(u.message, _tl.Message)
and u.message.grouped_id == group) and u.message.grouped_id == group)
]) ])
@ -140,7 +138,7 @@ class Album(EventBuilder):
if len(event.messages) > 1: if len(event.messages) > 1:
return super().filter(event) return super().filter(event)
class Event(EventCommon, SenderGetter): class Event(EventCommon, _tl.custom.sendergetter.SenderGetter):
""" """
Represents the event of a new album. Represents the event of a new album.
@ -150,7 +148,7 @@ class Album(EventBuilder):
""" """
def __init__(self, messages): def __init__(self, messages):
message = messages[0] message = messages[0]
if not message.out and isinstance(message.peer_id, types.PeerUser): if not message.out and isinstance(message.peer_id, _tl.PeerUser):
# Incoming message (e.g. from a bot) has peer_id=us, and # Incoming message (e.g. from a bot) has peer_id=us, and
# from_id=bot (the actual "chat" from a user's perspective). # from_id=bot (the actual "chat" from a user's perspective).
chat_peer = message.from_id chat_peer = message.from_id
@ -160,7 +158,7 @@ class Album(EventBuilder):
super().__init__(chat_peer=chat_peer, super().__init__(chat_peer=chat_peer,
msg_id=message.id, broadcast=bool(message.post)) msg_id=message.id, broadcast=bool(message.post))
SenderGetter.__init__(self, message.sender_id) _tl.custom.sendergetter.SenderGetter.__init__(self, message.sender_id)
self.messages = messages self.messages = messages
def _set_client(self, client): def _set_client(self, client):

View File

@ -2,9 +2,7 @@ import re
import struct import struct
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types, functions
from ..tl.custom.sendergetter import SenderGetter
@name_inner_event @name_inner_event
@ -88,13 +86,13 @@ class CallbackQuery(EventBuilder):
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, types.UpdateBotCallbackQuery): if isinstance(update, _tl.UpdateBotCallbackQuery):
return cls.Event(update, update.peer, update.msg_id) return cls.Event(update, update.peer, update.msg_id)
elif isinstance(update, types.UpdateInlineBotCallbackQuery): elif isinstance(update, _tl.UpdateInlineBotCallbackQuery):
# See https://github.com/LonamiWebs/Telethon/pull/1005 # See https://github.com/LonamiWebs/Telethon/pull/1005
# The long message ID is actually just msg_id + peer_id # The long message ID is actually just msg_id + peer_id
mid, pid = struct.unpack('<ii', struct.pack('<q', update.msg_id.id)) mid, pid = struct.unpack('<ii', struct.pack('<q', update.msg_id.id))
peer = types.PeerChannel(-pid) if pid < 0 else types.PeerUser(pid) peer = _tl.PeerChannel(-pid) if pid < 0 else _tl.PeerUser(pid)
return cls.Event(update, peer, mid) return cls.Event(update, peer, mid)
def filter(self, event): def filter(self, event):
@ -123,7 +121,7 @@ class CallbackQuery(EventBuilder):
return self.func(event) return self.func(event)
return True return True
class Event(EventCommon, SenderGetter): class Event(EventCommon, _tl.custom.sendergetter.SenderGetter):
""" """
Represents the event of a new callback query. Represents the event of a new callback query.
@ -141,7 +139,7 @@ class CallbackQuery(EventBuilder):
""" """
def __init__(self, query, peer, msg_id): def __init__(self, query, peer, msg_id):
super().__init__(peer, msg_id=msg_id) super().__init__(peer, msg_id=msg_id)
SenderGetter.__init__(self, query.user_id) _tl.custom.sendergetter.SenderGetter.__init__(self, query.user_id)
self.query = query self.query = query
self.data_match = None self.data_match = None
self.pattern_match = None self.pattern_match = None
@ -242,7 +240,7 @@ class CallbackQuery(EventBuilder):
self._answered = True self._answered = True
return await self._client( return await self._client(
functions.messages.SetBotCallbackAnswerRequest( _tl.fn.messages.SetBotCallbackAnswerRequest(
query_id=self.query.query_id, query_id=self.query.query_id,
cache_time=cache_time, cache_time=cache_time,
alert=alert, alert=alert,
@ -264,7 +262,7 @@ class CallbackQuery(EventBuilder):
chat, so methods like `respond` or `delete` won't work (but chat, so methods like `respond` or `delete` won't work (but
`edit` will always work). `edit` will always work).
""" """
return isinstance(self.query, types.UpdateInlineBotCallbackQuery) return isinstance(self.query, _tl.UpdateInlineBotCallbackQuery)
async def respond(self, *args, **kwargs): async def respond(self, *args, **kwargs):
""" """
@ -312,7 +310,7 @@ class CallbackQuery(EventBuilder):
since the message object is normally not present. since the message object is normally not present.
""" """
self._client.loop.create_task(self.answer()) self._client.loop.create_task(self.answer())
if isinstance(self.query.msg_id, types.InputBotInlineMessageID): if isinstance(self.query.msg_id, _tl.InputBotInlineMessageID):
return await self._client.edit_message( return await self._client.edit_message(
self.query.msg_id, *args, **kwargs self.query.msg_id, *args, **kwargs
) )

View File

@ -1,6 +1,5 @@
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types
@name_inner_event @name_inner_event
@ -36,23 +35,23 @@ class ChatAction(EventBuilder):
# Rely on specific pin updates for unpins, but otherwise ignore them # Rely on specific pin updates for unpins, but otherwise ignore them
# for new pins (we'd rather handle the new service message with pin, # for new pins (we'd rather handle the new service message with pin,
# so that we can act on that message'). # so that we can act on that message').
if isinstance(update, types.UpdatePinnedChannelMessages) and not update.pinned: if isinstance(update, _tl.UpdatePinnedChannelMessages) and not update.pinned:
return cls.Event(types.PeerChannel(update.channel_id), return cls.Event(_tl.PeerChannel(update.channel_id),
pin_ids=update.messages, pin_ids=update.messages,
pin=update.pinned) pin=update.pinned)
elif isinstance(update, types.UpdatePinnedMessages) and not update.pinned: elif isinstance(update, _tl.UpdatePinnedMessages) and not update.pinned:
return cls.Event(update.peer, return cls.Event(update.peer,
pin_ids=update.messages, pin_ids=update.messages,
pin=update.pinned) pin=update.pinned)
elif isinstance(update, types.UpdateChatParticipantAdd): elif isinstance(update, _tl.UpdateChatParticipantAdd):
return cls.Event(types.PeerChat(update.chat_id), return cls.Event(_tl.PeerChat(update.chat_id),
added_by=update.inviter_id or True, added_by=update.inviter_id or True,
users=update.user_id) users=update.user_id)
elif isinstance(update, types.UpdateChatParticipantDelete): elif isinstance(update, _tl.UpdateChatParticipantDelete):
return cls.Event(types.PeerChat(update.chat_id), return cls.Event(_tl.PeerChat(update.chat_id),
kicked_by=True, kicked_by=True,
users=update.user_id) users=update.user_id)
@ -61,50 +60,50 @@ class ChatAction(EventBuilder):
# better not to rely on this. Rely only in MessageActionChatDeleteUser. # better not to rely on this. Rely only in MessageActionChatDeleteUser.
elif (isinstance(update, ( elif (isinstance(update, (
types.UpdateNewMessage, types.UpdateNewChannelMessage)) _tl.UpdateNewMessage, _tl.UpdateNewChannelMessage))
and isinstance(update.message, types.MessageService)): and isinstance(update.message, _tl.MessageService)):
msg = update.message msg = update.message
action = update.message.action action = update.message.action
if isinstance(action, types.MessageActionChatJoinedByLink): if isinstance(action, _tl.MessageActionChatJoinedByLink):
return cls.Event(msg, return cls.Event(msg,
added_by=True, added_by=True,
users=msg.from_id) users=msg.from_id)
elif isinstance(action, types.MessageActionChatAddUser): elif isinstance(action, _tl.MessageActionChatAddUser):
# If a user adds itself, it means they joined via the public chat username # If a user adds itself, it means they joined via the public chat username
added_by = ([msg.sender_id] == action.users) or msg.from_id added_by = ([msg.sender_id] == action.users) or msg.from_id
return cls.Event(msg, return cls.Event(msg,
added_by=added_by, added_by=added_by,
users=action.users) users=action.users)
elif isinstance(action, types.MessageActionChatDeleteUser): elif isinstance(action, _tl.MessageActionChatDeleteUser):
return cls.Event(msg, return cls.Event(msg,
kicked_by=utils.get_peer_id(msg.from_id) if msg.from_id else True, kicked_by=utils.get_peer_id(msg.from_id) if msg.from_id else True,
users=action.user_id) users=action.user_id)
elif isinstance(action, types.MessageActionChatCreate): elif isinstance(action, _tl.MessageActionChatCreate):
return cls.Event(msg, return cls.Event(msg,
users=action.users, users=action.users,
created=True, created=True,
new_title=action.title) new_title=action.title)
elif isinstance(action, types.MessageActionChannelCreate): elif isinstance(action, _tl.MessageActionChannelCreate):
return cls.Event(msg, return cls.Event(msg,
created=True, created=True,
users=msg.from_id, users=msg.from_id,
new_title=action.title) new_title=action.title)
elif isinstance(action, types.MessageActionChatEditTitle): elif isinstance(action, _tl.MessageActionChatEditTitle):
return cls.Event(msg, return cls.Event(msg,
users=msg.from_id, users=msg.from_id,
new_title=action.title) new_title=action.title)
elif isinstance(action, types.MessageActionChatEditPhoto): elif isinstance(action, _tl.MessageActionChatEditPhoto):
return cls.Event(msg, return cls.Event(msg,
users=msg.from_id, users=msg.from_id,
new_photo=action.photo) new_photo=action.photo)
elif isinstance(action, types.MessageActionChatDeletePhoto): elif isinstance(action, _tl.MessageActionChatDeletePhoto):
return cls.Event(msg, return cls.Event(msg,
users=msg.from_id, users=msg.from_id,
new_photo=True) new_photo=True)
elif isinstance(action, types.MessageActionPinMessage) and msg.reply_to: elif isinstance(action, _tl.MessageActionPinMessage) and msg.reply_to:
return cls.Event(msg, return cls.Event(msg,
pin_ids=[msg.reply_to_msg_id]) pin_ids=[msg.reply_to_msg_id])
elif isinstance(action, types.MessageActionGameScore): elif isinstance(action, _tl.MessageActionGameScore):
return cls.Event(msg, return cls.Event(msg,
new_score=action.score) new_score=action.score)
@ -153,7 +152,7 @@ class ChatAction(EventBuilder):
def __init__(self, where, new_photo=None, def __init__(self, where, new_photo=None,
added_by=None, kicked_by=None, created=None, added_by=None, kicked_by=None, created=None,
users=None, new_title=None, pin_ids=None, pin=None, new_score=None): users=None, new_title=None, pin_ids=None, pin=None, new_score=None):
if isinstance(where, types.MessageService): if isinstance(where, _tl.MessageService):
self.action_message = where self.action_message = where
where = where.peer_id where = where.peer_id
else: else:
@ -169,7 +168,7 @@ class ChatAction(EventBuilder):
self.new_photo = new_photo is not None self.new_photo = new_photo is not None
self.photo = \ self.photo = \
new_photo if isinstance(new_photo, types.Photo) else None new_photo if isinstance(new_photo, _tl.Photo) else None
self._added_by = None self._added_by = None
self._kicked_by = None self._kicked_by = None
@ -283,7 +282,7 @@ class ChatAction(EventBuilder):
""" """
The user who added ``users``, if applicable (`None` otherwise). The user who added ``users``, if applicable (`None` otherwise).
""" """
if self._added_by and not isinstance(self._added_by, types.User): if self._added_by and not isinstance(self._added_by, _tl.User):
aby = self._entities.get(utils.get_peer_id(self._added_by)) aby = self._entities.get(utils.get_peer_id(self._added_by))
if aby: if aby:
self._added_by = aby self._added_by = aby
@ -304,7 +303,7 @@ class ChatAction(EventBuilder):
""" """
The user who kicked ``users``, if applicable (`None` otherwise). The user who kicked ``users``, if applicable (`None` otherwise).
""" """
if self._kicked_by and not isinstance(self._kicked_by, types.User): if self._kicked_by and not isinstance(self._kicked_by, _tl.User):
kby = self._entities.get(utils.get_peer_id(self._kicked_by)) kby = self._entities.get(utils.get_peer_id(self._kicked_by))
if kby: if kby:
self._kicked_by = kby self._kicked_by = kby
@ -393,7 +392,7 @@ class ChatAction(EventBuilder):
await self.action_message._reload_message() await self.action_message._reload_message()
self._users = [ self._users = [
u for u in self.action_message.action_entities u for u in self.action_message.action_entities
if isinstance(u, (types.User, types.UserEmpty))] if isinstance(u, (_tl.User, _tl.UserEmpty))]
return self._users return self._users
@ -433,7 +432,7 @@ class ChatAction(EventBuilder):
self._input_users = [ self._input_users = [
utils.get_input_peer(u) utils.get_input_peer(u)
for u in self.action_message.action_entities for u in self.action_message.action_entities
if isinstance(u, (types.User, types.UserEmpty))] if isinstance(u, (_tl.User, _tl.UserEmpty))]
return self._input_users or [] return self._input_users or []

View File

@ -2,9 +2,7 @@ import abc
import asyncio import asyncio
import warnings import warnings
from .. import utils from .. import utils, _tl
from ..tl import TLObject, types
from ..tl.custom.chatgetter import ChatGetter
async def _into_id_set(client, chats): async def _into_id_set(client, chats):
@ -22,16 +20,16 @@ async def _into_id_set(client, chats):
result.add(chat) # Explicitly marked IDs are negative result.add(chat) # Explicitly marked IDs are negative
else: else:
result.update({ # Support all valid types of peers result.update({ # Support all valid types of peers
utils.get_peer_id(types.PeerUser(chat)), utils.get_peer_id(_tl.PeerUser(chat)),
utils.get_peer_id(types.PeerChat(chat)), utils.get_peer_id(_tl.PeerChat(chat)),
utils.get_peer_id(types.PeerChannel(chat)), utils.get_peer_id(_tl.PeerChannel(chat)),
}) })
elif isinstance(chat, TLObject) and chat.SUBCLASS_OF_ID == 0x2d45687: elif isinstance(chat, _tl.TLObject) and chat.SUBCLASS_OF_ID == 0x2d45687:
# 0x2d45687 == crc32(b'Peer') # 0x2d45687 == crc32(b'Peer')
result.add(utils.get_peer_id(chat)) result.add(utils.get_peer_id(chat))
else: else:
chat = await client.get_input_entity(chat) chat = await client.get_input_entity(chat)
if isinstance(chat, types.InputPeerSelf): if isinstance(chat, _tl.InputPeerSelf):
chat = await client.get_me(input_peer=True) chat = await client.get_me(input_peer=True)
result.add(utils.get_peer_id(chat)) result.add(utils.get_peer_id(chat))
@ -166,10 +164,10 @@ class EventCommon(ChatGetter, abc.ABC):
return self._client return self._client
def __str__(self): def __str__(self):
return TLObject.pretty_format(self.to_dict()) return _tl.TLObject.pretty_format(self.to_dict())
def stringify(self): def stringify(self):
return TLObject.pretty_format(self.to_dict(), indent=0) return _tl.TLObject.pretty_format(self.to_dict(), indent=0)
def to_dict(self): def to_dict(self):
d = {k: v for k, v in self.__dict__.items() if k[0] != '_'} d = {k: v for k, v in self.__dict__.items() if k[0] != '_'}

View File

@ -4,9 +4,7 @@ import re
import asyncio import asyncio
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types, functions, custom
from ..tl.custom.sendergetter import SenderGetter
@name_inner_event @name_inner_event
@ -62,7 +60,7 @@ class InlineQuery(EventBuilder):
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, types.UpdateBotInlineQuery): if isinstance(update, _tl.UpdateBotInlineQuery):
return cls.Event(update) return cls.Event(update)
def filter(self, event): def filter(self, event):
@ -74,7 +72,7 @@ class InlineQuery(EventBuilder):
return super().filter(event) return super().filter(event)
class Event(EventCommon, SenderGetter): class Event(EventCommon, _tl.custom.sendergetter.SenderGetter):
""" """
Represents the event of a new callback query. Represents the event of a new callback query.
@ -90,8 +88,8 @@ class InlineQuery(EventBuilder):
function, which is ``re.compile(...).match`` by default. function, which is ``re.compile(...).match`` by default.
""" """
def __init__(self, query): def __init__(self, query):
super().__init__(chat_peer=types.PeerUser(query.user_id)) super().__init__(chat_peer=_tl.PeerUser(query.user_id))
SenderGetter.__init__(self, query.user_id) _tl.custom.sendergetter.SenderGetter.__init__(self, query.user_id)
self.query = query self.query = query
self.pattern_match = None self.pattern_match = None
self._answered = False self._answered = False
@ -223,10 +221,10 @@ class InlineQuery(EventBuilder):
results = [] results = []
if switch_pm: if switch_pm:
switch_pm = types.InlineBotSwitchPM(switch_pm, switch_pm_param) switch_pm = _tl.InlineBotSwitchPM(switch_pm, switch_pm_param)
return await self._client( return await self._client(
functions.messages.SetInlineBotResultsRequest( _tl.fn.messages.SetInlineBotResults(
query_id=self.query.query_id, query_id=self.query.query_id,
results=results, results=results,
cache_time=cache_time, cache_time=cache_time,

View File

@ -1,5 +1,5 @@
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from ..tl import types from .. import _tl
@name_inner_event @name_inner_event
@ -37,15 +37,15 @@ class MessageDeleted(EventBuilder):
""" """
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, types.UpdateDeleteMessages): if isinstance(update, _tl.UpdateDeleteMessages):
return cls.Event( return cls.Event(
deleted_ids=update.messages, deleted_ids=update.messages,
peer=None peer=None
) )
elif isinstance(update, types.UpdateDeleteChannelMessages): elif isinstance(update, _tl.UpdateDeleteChannelMessages):
return cls.Event( return cls.Event(
deleted_ids=update.messages, deleted_ids=update.messages,
peer=types.PeerChannel(update.channel_id) peer=_tl.PeerChannel(update.channel_id)
) )
class Event(EventCommon): class Event(EventCommon):

View File

@ -1,6 +1,6 @@
from .common import name_inner_event from .common import name_inner_event
from .newmessage import NewMessage from .newmessage import NewMessage
from ..tl import types from .. import _tl
@name_inner_event @name_inner_event
@ -44,8 +44,8 @@ class MessageEdited(NewMessage):
""" """
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, (types.UpdateEditMessage, if isinstance(update, (_tl.UpdateEditMessage,
types.UpdateEditChannelMessage)): _tl.UpdateEditChannelMessage)):
return cls.Event(update.message) return cls.Event(update.message)
class Event(NewMessage.Event): class Event(NewMessage.Event):

View File

@ -1,6 +1,5 @@
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types
@name_inner_event @name_inner_event
@ -36,21 +35,21 @@ class MessageRead(EventBuilder):
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, types.UpdateReadHistoryInbox): if isinstance(update, _tl.UpdateReadHistoryInbox):
return cls.Event(update.peer, update.max_id, False) return cls.Event(update.peer, update.max_id, False)
elif isinstance(update, types.UpdateReadHistoryOutbox): elif isinstance(update, _tl.UpdateReadHistoryOutbox):
return cls.Event(update.peer, update.max_id, True) return cls.Event(update.peer, update.max_id, True)
elif isinstance(update, types.UpdateReadChannelInbox): elif isinstance(update, _tl.UpdateReadChannelInbox):
return cls.Event(types.PeerChannel(update.channel_id), return cls.Event(_tl.PeerChannel(update.channel_id),
update.max_id, False) update.max_id, False)
elif isinstance(update, types.UpdateReadChannelOutbox): elif isinstance(update, _tl.UpdateReadChannelOutbox):
return cls.Event(types.PeerChannel(update.channel_id), return cls.Event(_tl.PeerChannel(update.channel_id),
update.max_id, True) update.max_id, True)
elif isinstance(update, types.UpdateReadMessagesContents): elif isinstance(update, _tl.UpdateReadMessagesContents):
return cls.Event(message_ids=update.messages, return cls.Event(message_ids=update.messages,
contents=True) contents=True)
elif isinstance(update, types.UpdateChannelReadMessagesContents): elif isinstance(update, _tl.UpdateChannelReadMessagesContents):
return cls.Event(types.PeerChannel(update.channel_id), return cls.Event(_tl.PeerChannel(update.channel_id),
message_ids=update.messages, message_ids=update.messages,
contents=True) contents=True)

View File

@ -1,8 +1,7 @@
import re import re
from .common import EventBuilder, EventCommon, name_inner_event, _into_id_set from .common import EventBuilder, EventCommon, name_inner_event, _into_id_set
from .. import utils from .. import utils, _tl
from ..tl import types
@name_inner_event @name_inner_event
@ -96,19 +95,19 @@ class NewMessage(EventBuilder):
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, if isinstance(update,
(types.UpdateNewMessage, types.UpdateNewChannelMessage)): (_tl.UpdateNewMessage, _tl.UpdateNewChannelMessage)):
if not isinstance(update.message, types.Message): if not isinstance(update.message, _tl.Message):
return # We don't care about MessageService's here return # We don't care about MessageService's here
event = cls.Event(update.message) event = cls.Event(update.message)
elif isinstance(update, types.UpdateShortMessage): elif isinstance(update, _tl.UpdateShortMessage):
event = cls.Event(types.Message( event = cls.Event(_tl.Message(
out=update.out, out=update.out,
mentioned=update.mentioned, mentioned=update.mentioned,
media_unread=update.media_unread, media_unread=update.media_unread,
silent=update.silent, silent=update.silent,
id=update.id, id=update.id,
peer_id=types.PeerUser(update.user_id), peer_id=_tl.PeerUser(update.user_id),
from_id=types.PeerUser(self_id if update.out else update.user_id), from_id=_tl.PeerUser(self_id if update.out else update.user_id),
message=update.message, message=update.message,
date=update.date, date=update.date,
fwd_from=update.fwd_from, fwd_from=update.fwd_from,
@ -117,15 +116,15 @@ class NewMessage(EventBuilder):
entities=update.entities, entities=update.entities,
ttl_period=update.ttl_period ttl_period=update.ttl_period
)) ))
elif isinstance(update, types.UpdateShortChatMessage): elif isinstance(update, _tl.UpdateShortChatMessage):
event = cls.Event(types.Message( event = cls.Event(_tl.Message(
out=update.out, out=update.out,
mentioned=update.mentioned, mentioned=update.mentioned,
media_unread=update.media_unread, media_unread=update.media_unread,
silent=update.silent, silent=update.silent,
id=update.id, id=update.id,
from_id=types.PeerUser(self_id if update.out else update.from_id), from_id=_tl.PeerUser(self_id if update.out else update.from_id),
peer_id=types.PeerChat(update.chat_id), peer_id=_tl.PeerChat(update.chat_id),
message=update.message, message=update.message,
date=update.date, date=update.date,
fwd_from=update.fwd_from, fwd_from=update.fwd_from,

View File

@ -2,9 +2,7 @@ import datetime
import functools import functools
from .common import EventBuilder, EventCommon, name_inner_event from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils from .. import utils, _tl
from ..tl import types
from ..tl.custom.sendergetter import SenderGetter
# TODO Either the properties are poorly named or they should be # TODO Either the properties are poorly named or they should be
@ -50,22 +48,22 @@ class UserUpdate(EventBuilder):
""" """
@classmethod @classmethod
def build(cls, update, others=None, self_id=None): def build(cls, update, others=None, self_id=None):
if isinstance(update, types.UpdateUserStatus): if isinstance(update, _tl.UpdateUserStatus):
return cls.Event(types.PeerUser(update.user_id), return cls.Event(_tl.PeerUser(update.user_id),
status=update.status) status=update.status)
elif isinstance(update, types.UpdateChannelUserTyping): elif isinstance(update, _tl.UpdateChannelUserTyping):
return cls.Event(update.from_id, return cls.Event(update.from_id,
chat_peer=types.PeerChannel(update.channel_id), chat_peer=_tl.PeerChannel(update.channel_id),
typing=update.action) typing=update.action)
elif isinstance(update, types.UpdateChatUserTyping): elif isinstance(update, _tl.UpdateChatUserTyping):
return cls.Event(update.from_id, return cls.Event(update.from_id,
chat_peer=types.PeerChat(update.chat_id), chat_peer=_tl.PeerChat(update.chat_id),
typing=update.action) typing=update.action)
elif isinstance(update, types.UpdateUserTyping): elif isinstance(update, _tl.UpdateUserTyping):
return cls.Event(update.user_id, return cls.Event(update.user_id,
typing=update.action) typing=update.action)
class Event(EventCommon, SenderGetter): class Event(EventCommon, _tl.custom.sendergetter.SenderGetter):
""" """
Represents the event of a user update Represents the event of a user update
such as gone online, started typing, etc. such as gone online, started typing, etc.
@ -87,7 +85,7 @@ class UserUpdate(EventBuilder):
""" """
def __init__(self, peer, *, status=None, chat_peer=None, typing=None): def __init__(self, peer, *, status=None, chat_peer=None, typing=None):
super().__init__(chat_peer or peer) super().__init__(chat_peer or peer)
SenderGetter.__init__(self, utils.get_peer_id(peer)) _tl.custom.sendergetter.SenderGetter.__init__(self, utils.get_peer_id(peer))
self.status = status self.status = status
self.action = typing self.action = typing
@ -126,7 +124,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if the action is typing a message. `True` if the action is typing a message.
""" """
return isinstance(self.action, types.SendMessageTypingAction) return isinstance(self.action, _tl.SendMessageTypingAction)
@property @property
@_requires_action @_requires_action
@ -135,13 +133,13 @@ class UserUpdate(EventBuilder):
`True` if the action is uploading something. `True` if the action is uploading something.
""" """
return isinstance(self.action, ( return isinstance(self.action, (
types.SendMessageChooseContactAction, _tl.SendMessageChooseContactAction,
types.SendMessageChooseStickerAction, _tl.SendMessageChooseStickerAction,
types.SendMessageUploadAudioAction, _tl.SendMessageUploadAudioAction,
types.SendMessageUploadDocumentAction, _tl.SendMessageUploadDocumentAction,
types.SendMessageUploadPhotoAction, _tl.SendMessageUploadPhotoAction,
types.SendMessageUploadRoundAction, _tl.SendMessageUploadRoundAction,
types.SendMessageUploadVideoAction _tl.SendMessageUploadVideoAction
)) ))
@property @property
@ -151,9 +149,9 @@ class UserUpdate(EventBuilder):
`True` if the action is recording something. `True` if the action is recording something.
""" """
return isinstance(self.action, ( return isinstance(self.action, (
types.SendMessageRecordAudioAction, _tl.SendMessageRecordAudioAction,
types.SendMessageRecordRoundAction, _tl.SendMessageRecordRoundAction,
types.SendMessageRecordVideoAction _tl.SendMessageRecordVideoAction
)) ))
@property @property
@ -162,7 +160,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if the action is playing a game. `True` if the action is playing a game.
""" """
return isinstance(self.action, types.SendMessageGamePlayAction) return isinstance(self.action, _tl.SendMessageGamePlayAction)
@property @property
@_requires_action @_requires_action
@ -170,7 +168,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if the action was cancelling other actions. `True` if the action was cancelling other actions.
""" """
return isinstance(self.action, types.SendMessageCancelAction) return isinstance(self.action, _tl.SendMessageCancelAction)
@property @property
@_requires_action @_requires_action
@ -178,7 +176,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if what's being uploaded is a geo. `True` if what's being uploaded is a geo.
""" """
return isinstance(self.action, types.SendMessageGeoLocationAction) return isinstance(self.action, _tl.SendMessageGeoLocationAction)
@property @property
@_requires_action @_requires_action
@ -187,8 +185,8 @@ class UserUpdate(EventBuilder):
`True` if what's being recorded/uploaded is an audio. `True` if what's being recorded/uploaded is an audio.
""" """
return isinstance(self.action, ( return isinstance(self.action, (
types.SendMessageRecordAudioAction, _tl.SendMessageRecordAudioAction,
types.SendMessageUploadAudioAction _tl.SendMessageUploadAudioAction
)) ))
@property @property
@ -198,8 +196,8 @@ class UserUpdate(EventBuilder):
`True` if what's being recorded/uploaded is a round video. `True` if what's being recorded/uploaded is a round video.
""" """
return isinstance(self.action, ( return isinstance(self.action, (
types.SendMessageRecordRoundAction, _tl.SendMessageRecordRoundAction,
types.SendMessageUploadRoundAction _tl.SendMessageUploadRoundAction
)) ))
@property @property
@ -209,8 +207,8 @@ class UserUpdate(EventBuilder):
`True` if what's being recorded/uploaded is an video. `True` if what's being recorded/uploaded is an video.
""" """
return isinstance(self.action, ( return isinstance(self.action, (
types.SendMessageRecordVideoAction, _tl.SendMessageRecordVideoAction,
types.SendMessageUploadVideoAction _tl.SendMessageUploadVideoAction
)) ))
@property @property
@ -219,7 +217,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if what's being uploaded (selected) is a contact. `True` if what's being uploaded (selected) is a contact.
""" """
return isinstance(self.action, types.SendMessageChooseContactAction) return isinstance(self.action, _tl.SendMessageChooseContactAction)
@property @property
@_requires_action @_requires_action
@ -227,7 +225,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if what's being uploaded is document. `True` if what's being uploaded is document.
""" """
return isinstance(self.action, types.SendMessageUploadDocumentAction) return isinstance(self.action, _tl.SendMessageUploadDocumentAction)
@property @property
@_requires_action @_requires_action
@ -235,7 +233,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if what's being uploaded is a sticker. `True` if what's being uploaded is a sticker.
""" """
return isinstance(self.action, types.SendMessageChooseStickerAction) return isinstance(self.action, _tl.SendMessageChooseStickerAction)
@property @property
@_requires_action @_requires_action
@ -243,7 +241,7 @@ class UserUpdate(EventBuilder):
""" """
`True` if what's being uploaded is a photo. `True` if what's being uploaded is a photo.
""" """
return isinstance(self.action, types.SendMessageUploadPhotoAction) return isinstance(self.action, _tl.SendMessageUploadPhotoAction)
@property @property
@_requires_action @_requires_action
@ -251,7 +249,7 @@ class UserUpdate(EventBuilder):
""" """
Exact `datetime.datetime` when the user was last seen if known. Exact `datetime.datetime` when the user was last seen if known.
""" """
if isinstance(self.status, types.UserStatusOffline): if isinstance(self.status, _tl.UserStatusOffline):
return self.status.was_online return self.status.was_online
@property @property
@ -260,19 +258,19 @@ class UserUpdate(EventBuilder):
""" """
The `datetime.datetime` until when the user should appear online. The `datetime.datetime` until when the user should appear online.
""" """
if isinstance(self.status, types.UserStatusOnline): if isinstance(self.status, _tl.UserStatusOnline):
return self.status.expires return self.status.expires
def _last_seen_delta(self): def _last_seen_delta(self):
if isinstance(self.status, types.UserStatusOffline): if isinstance(self.status, _tl.UserStatusOffline):
return datetime.datetime.now(tz=datetime.timezone.utc) - self.status.was_online return datetime.datetime.now(tz=datetime.timezone.utc) - self.status.was_online
elif isinstance(self.status, types.UserStatusOnline): elif isinstance(self.status, _tl.UserStatusOnline):
return datetime.timedelta(days=0) return datetime.timedelta(days=0)
elif isinstance(self.status, types.UserStatusRecently): elif isinstance(self.status, _tl.UserStatusRecently):
return datetime.timedelta(days=1) return datetime.timedelta(days=1)
elif isinstance(self.status, types.UserStatusLastWeek): elif isinstance(self.status, _tl.UserStatusLastWeek):
return datetime.timedelta(days=7) return datetime.timedelta(days=7)
elif isinstance(self.status, types.UserStatusLastMonth): elif isinstance(self.status, _tl.UserStatusLastMonth):
return datetime.timedelta(days=30) return datetime.timedelta(days=30)
else: else:
return datetime.timedelta(days=365) return datetime.timedelta(days=365)

View File

@ -1,13 +1,7 @@
from enum import Enum from enum import Enum
from .abstract import Session from .abstract import Session
from .. import utils from .. import utils, _tl
from ..tl import TLObject
from ..tl.types import (
PeerUser, PeerChat, PeerChannel,
InputPeerUser, InputPeerChat, InputPeerChannel,
InputPhoto, InputDocument
)
class _SentFileType(Enum): class _SentFileType(Enum):
@ -16,9 +10,9 @@ class _SentFileType(Enum):
@staticmethod @staticmethod
def from_type(cls): def from_type(cls):
if cls == InputDocument: if cls == _tl.InputDocument:
return _SentFileType.DOCUMENT return _SentFileType.DOCUMENT
elif cls == InputPhoto: elif cls == _tl.InputPhoto:
return _SentFileType.PHOTO return _SentFileType.PHOTO
else: else:
raise ValueError('The cls must be either InputDocument/InputPhoto') raise ValueError('The cls must be either InputDocument/InputPhoto')
@ -94,7 +88,7 @@ class MemorySession(Session):
return id, hash, username, phone, name return id, hash, username, phone, name
def _entity_to_row(self, e): def _entity_to_row(self, e):
if not isinstance(e, TLObject): if not isinstance(e, _tl.TLObject):
return return
try: try:
p = utils.get_input_peer(e, allow_self=False) p = utils.get_input_peer(e, allow_self=False)
@ -106,9 +100,9 @@ class MemorySession(Session):
# anywhere (since layer 102, there are two access hashes). # anywhere (since layer 102, there are two access hashes).
return return
if isinstance(p, (InputPeerUser, InputPeerChannel)): if isinstance(p, (_tl.InputPeerUser, _tl.InputPeerChannel)):
p_hash = p.access_hash p_hash = p.access_hash
elif isinstance(p, InputPeerChat): elif isinstance(p, _tl.InputPeerChat):
p_hash = 0 p_hash = 0
else: else:
return return
@ -123,7 +117,7 @@ class MemorySession(Session):
) )
def _entities_to_rows(self, tlo): def _entities_to_rows(self, tlo):
if not isinstance(tlo, TLObject) and utils.is_list_like(tlo): if not isinstance(tlo, _tl.TLObject) and utils.is_list_like(tlo):
# This may be a list of users already for instance # This may be a list of users already for instance
entities = tlo entities = tlo
else: else:
@ -175,9 +169,9 @@ class MemorySession(Session):
in self._entities if found_id == id) in self._entities if found_id == id)
else: else:
ids = ( ids = (
utils.get_peer_id(PeerUser(id)), utils.get_peer_id(_tl.PeerUser(id)),
utils.get_peer_id(PeerChat(id)), utils.get_peer_id(_tl.PeerChat(id)),
utils.get_peer_id(PeerChannel(id)) utils.get_peer_id(_tl.PeerChannel(id))
) )
return next((id, hash) for found_id, hash, _, _, _ return next((id, hash) for found_id, hash, _, _, _
in self._entities if found_id in ids) in self._entities if found_id in ids)
@ -194,7 +188,7 @@ class MemorySession(Session):
return utils.get_input_peer(key) return utils.get_input_peer(key)
except (AttributeError, TypeError): except (AttributeError, TypeError):
# Not a TLObject or can't be cast into InputPeer # Not a TLObject or can't be cast into InputPeer
if isinstance(key, TLObject): if isinstance(key, _tl.TLObject):
key = utils.get_peer_id(key) key = utils.get_peer_id(key)
exact = True exact = True
else: else:
@ -224,17 +218,17 @@ class MemorySession(Session):
entity_id, entity_hash = result # unpack resulting tuple entity_id, entity_hash = result # unpack resulting tuple
entity_id, kind = utils.resolve_id(entity_id) entity_id, kind = utils.resolve_id(entity_id)
# removes the mark and returns type of entity # removes the mark and returns type of entity
if kind == PeerUser: if kind == _tl.PeerUser:
return InputPeerUser(entity_id, entity_hash) return _tl.InputPeerUser(entity_id, entity_hash)
elif kind == PeerChat: elif kind == _tl.PeerChat:
return InputPeerChat(entity_id) return _tl.InputPeerChat(entity_id)
elif kind == PeerChannel: elif kind == _tl.PeerChannel:
return InputPeerChannel(entity_id, entity_hash) return _tl.InputPeerChannel(entity_id, entity_hash)
else: else:
raise ValueError('Could not find input entity with key ', key) raise ValueError('Could not find input entity with key ', key)
def cache_file(self, md5_digest, file_size, instance): def cache_file(self, md5_digest, file_size, instance):
if not isinstance(instance, (InputDocument, InputPhoto)): if not isinstance(instance, (_tl.InputDocument, _tl.InputPhoto)):
raise TypeError('Cannot cache %s instance' % type(instance)) raise TypeError('Cannot cache %s instance' % type(instance))
key = (md5_digest, file_size, _SentFileType.from_type(type(instance))) key = (md5_digest, file_size, _SentFileType.from_type(type(instance)))
value = (instance.id, instance.access_hash) value = (instance.id, instance.access_hash)

View File

@ -2,13 +2,9 @@ import datetime
import os import os
import time import time
from telethon.tl import types
from .memory import MemorySession, _SentFileType from .memory import MemorySession, _SentFileType
from .. import utils from .. import utils, _tl
from ..crypto import AuthKey from ..crypto import AuthKey
from ..tl.types import (
InputPhoto, InputDocument, PeerUser, PeerChat, PeerChannel
)
try: try:
import sqlite3 import sqlite3
@ -208,7 +204,7 @@ class SQLiteSession(MemorySession):
pts, qts, date, seq = row pts, qts, date, seq = row
date = datetime.datetime.fromtimestamp( date = datetime.datetime.fromtimestamp(
date, tz=datetime.timezone.utc) date, tz=datetime.timezone.utc)
return types.updates.State(pts, qts, date, seq, unread_count=0) return _tl.updates.State(pts, qts, date, seq, unread_count=0)
def set_update_state(self, entity_id, state): def set_update_state(self, entity_id, state):
self._execute('insert or replace into update_state values (?,?,?,?,?)', self._execute('insert or replace into update_state values (?,?,?,?,?)',
@ -325,9 +321,9 @@ class SQLiteSession(MemorySession):
else: else:
return self._execute( return self._execute(
'select id, hash from entities where id in (?,?,?)', 'select id, hash from entities where id in (?,?,?)',
utils.get_peer_id(PeerUser(id)), utils.get_peer_id(_tl.PeerUser(id)),
utils.get_peer_id(PeerChat(id)), utils.get_peer_id(_tl.PeerChat(id)),
utils.get_peer_id(PeerChannel(id)) utils.get_peer_id(_tl.PeerChannel(id))
) )
# File processing # File processing
@ -343,7 +339,7 @@ class SQLiteSession(MemorySession):
return cls(row[0], row[1]) return cls(row[0], row[1])
def cache_file(self, md5_digest, file_size, instance): def cache_file(self, md5_digest, file_size, instance):
if not isinstance(instance, (InputDocument, InputPhoto)): if not isinstance(instance, (_tl.InputDocument, _tl.InputPhoto)):
raise TypeError('Cannot cache %s instance' % type(instance)) raise TypeError('Cannot cache %s instance' % type(instance))
self._execute( self._execute(

View File

@ -695,9 +695,9 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir):
namespace_types[tlobject.namespace].append(tlobject) namespace_types[tlobject.namespace].append(tlobject)
type_constructors[tlobject.result].append(tlobject) type_constructors[tlobject.result].append(tlobject)
_write_modules(output_dir / 'functions', import_depth, 'TLRequest', _write_modules(output_dir / 'fn', import_depth, 'TLRequest',
namespace_functions, type_constructors) namespace_functions, type_constructors)
_write_modules(output_dir / 'types', import_depth, 'TLObject', _write_modules(output_dir, import_depth - 1, 'TLObject',
namespace_types, type_constructors) namespace_types, type_constructors)
filename = output_dir / 'alltlobjects.py' filename = output_dir / 'alltlobjects.py'

View File

@ -52,8 +52,7 @@ class TLObject:
assert self.id == self.infer_id(),\ assert self.id == self.infer_id(),\
'Invalid inferred ID for ' + repr(self) 'Invalid inferred ID for ' + repr(self)
self.class_name = snake_to_camel_case( self.class_name = snake_to_camel_case(self.name)
self.name, suffix='Request' if self.is_function else '')
self.real_args = list(a for a in self.sorted_args() if not self.real_args = list(a for a in self.sorted_args() if not
(a.flag_indicator or a.generic_definition)) (a.flag_indicator or a.generic_definition))

View File

@ -5,7 +5,7 @@ from telethon.tl import types, functions
def test_nested_invalid_serialization(): def test_nested_invalid_serialization():
large_long = 2**62 large_long = 2**62
request = functions.account.SetPrivacyRequest( request = _tl.fn.account.SetPrivacy(
key=types.InputPrivacyKeyChatInvite(), key=types.InputPrivacyKeyChatInvite(),
rules=[types.InputPrivacyValueDisallowUsers(users=[large_long])] rules=[types.InputPrivacyValueDisallowUsers(users=[large_long])]
) )