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
/telethon/_tl/functions/
/telethon/_tl/types/
/telethon/_tl/fn/
/telethon/_tl/*.py
/telethon/_tl/alltlobjects.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'
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
DOCS_IN_RES = GENERATOR_DIR / 'data/html'

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
import typing
from .. import hints
from ..tl import types, functions, custom
from .. import hints, _tl
if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient
@ -14,14 +13,14 @@ async def inline_query(
*,
entity: 'hints.EntityLike' = 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)
if entity:
peer = await self.get_input_entity(entity)
else:
peer = types.InputPeerEmpty()
peer = _tl.InputPeerEmpty()
result = await self(functions.messages.GetInlineBotResultsRequest(
result = await self(_tl.fn.messages.GetInlineBotResults(
bot=bot,
peer=peer,
query=query,
@ -29,4 +28,4 @@ async def inline_query(
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
from .. import utils, hints
from ..tl import types, custom
from .. import utils, hints, _tl
def build_reply_markup(
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:
return None
@ -31,7 +30,7 @@ def build_reply_markup(
for row in buttons:
current = []
for button in row:
if isinstance(button, custom.Button):
if isinstance(button, _tl.custom.Button):
if button.resize is not None:
resize = button.resize
if button.single_use is not None:
@ -40,10 +39,10 @@ def build_reply_markup(
selective = button.selective
button = button.button
elif isinstance(button, custom.MessageButton):
elif isinstance(button, _tl.custom.MessageButton):
button = button.button
inline = custom.Button._is_inline(button)
inline = _tl.custom.Button._is_inline(button)
is_inline |= inline
is_normal |= not inline
@ -52,14 +51,14 @@ def build_reply_markup(
current.append(button)
if current:
rows.append(types.KeyboardButtonRow(current))
rows.append(_tl.KeyboardButtonRow(current))
if inline_only and is_normal:
raise ValueError('You cannot use non-inline buttons here')
elif is_inline == is_normal and is_normal:
raise ValueError('You cannot mix inline with normal buttons')
elif is_inline:
return types.ReplyInlineMarkup(rows)
return _tl.ReplyInlineMarkup(rows)
# elif is_normal:
return types.ReplyKeyboardMarkup(
return _tl.ReplyKeyboardMarkup(
rows, resize=resize, single_use=single_use, selective=selective)

View File

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

View File

@ -3,9 +3,8 @@ import inspect
import itertools
import typing
from .. import helpers, utils, hints, errors
from .. import helpers, utils, hints, errors, _tl
from ..requestiter import RequestIter
from ..tl import types, functions, custom
_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
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):
async def _init(
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_id=offset_id,
offset_peer=offset_peer,
@ -56,7 +55,7 @@ class _DialogsIter(RequestIter):
entities = {utils.get_peer_id(x): x
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 = {}
for m in r.messages:
@ -80,7 +79,7 @@ class _DialogsIter(RequestIter):
# Real world example: https://t.me/TelethonChat/271471
continue
cd = custom.Dialog(self.client, d, entities, message)
cd = _tl.custom.Dialog(self.client, d, entities, message)
if cd.dialog.pts:
self.client._channel_pts[cd.id] = cd.dialog.pts
@ -89,7 +88,7 @@ class _DialogsIter(RequestIter):
self.buffer.append(cd)
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
# we didn't get a DialogsSlice which means we got all.
return True
@ -112,15 +111,15 @@ class _DialogsIter(RequestIter):
class _DraftsIter(RequestIter):
async def _init(self, entities, **kwargs):
if not entities:
r = await self.client(functions.messages.GetAllDraftsRequest())
r = await self.client(_tl.fn.messages.GetAllDrafts())
items = r.updates
else:
peers = []
for entity in entities:
peers.append(types.InputDialogPeer(
peers.append(_tl.InputDialogPeer(
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
# 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)}
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
)
@ -142,7 +141,7 @@ def iter_dialogs(
*,
offset_date: 'hints.DateLike' = None,
offset_id: int = 0,
offset_peer: 'hints.EntityLike' = types.InputPeerEmpty(),
offset_peer: 'hints.EntityLike' = _tl.InputPeerEmpty(),
ignore_pinned: bool = False,
ignore_migrated: bool = False,
folder: int = None,
@ -192,12 +191,12 @@ async def edit_folder(
folder: typing.Union[int, typing.Sequence[int]] = None,
*,
unpack=None
) -> types.Updates:
) -> _tl.Updates:
if (entity is None) == (unpack is None):
raise ValueError('You can only set either entities or unpack, not both')
if unpack is not None:
return await self(functions.folders.DeleteFolderRequest(
return await self(_tl.fn.folders.DeleteFolder(
folder_id=unpack
))
@ -214,8 +213,8 @@ async def edit_folder(
elif len(entities) != len(folder):
raise ValueError('Number of folders does not match number of entities')
return await self(functions.folders.EditPeerFoldersRequest([
types.InputFolderPeer(x, folder_id=y)
return await self(_tl.fn.folders.EditPeerFolders([
_tl.InputFolderPeer(x, folder_id=y)
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),
# 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
else:
deactivated = False
@ -235,12 +234,12 @@ async def delete_dialog(
entity = await self.get_input_entity(entity)
ty = helpers._entity_type(entity)
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:
try:
result = await self(functions.messages.DeleteChatUserRequest(
entity.chat_id, types.InputUserSelf(), revoke_history=revoke
result = await self(_tl.fn.messages.DeleteChatUser(
entity.chat_id, _tl.InputUserSelf(), revoke_history=revoke
))
except errors.PeerIdInvalidError:
# Happens if we didn't have the deactivated information
@ -249,6 +248,6 @@ async def delete_dialog(
result = None
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

View File

@ -8,9 +8,8 @@ import asyncio
from ..crypto import AES
from .. import utils, helpers, errors, hints
from .. import utils, helpers, errors, hints, _tl
from ..requestiter import RequestIter
from ..tl import TLObject, types, functions
try:
import aiohttp
@ -31,7 +30,7 @@ class _DirectDownloadIter(RequestIter):
async def _init(
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)
self.total = file_size
@ -50,7 +49,7 @@ class _DirectDownloadIter(RequestIter):
self._sender = await self.client._borrow_exported_sender(dc_id)
except errors.DcIdInvalidError:
# 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:
if option.ip_address == self.client.session.server_address:
self.client.session.set_dc(
@ -75,7 +74,7 @@ class _DirectDownloadIter(RequestIter):
try:
result = await self.client._call(self._sender, self.request)
self._timed_out = False
if isinstance(result, types.upload.FileCdnRedirect):
if isinstance(result, _tl.upload.FileCdnRedirect):
raise NotImplementedError # TODO Implement
else:
return result.bytes
@ -99,7 +98,7 @@ class _DirectDownloadIter(RequestIter):
except errors.FilerefUpgradeNeededError as e:
# Only implemented for documents which are the ones that may take that long to download
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 != '':
raise
@ -107,7 +106,7 @@ class _DirectDownloadIter(RequestIter):
chat, msg_id = self._msg_data
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
document = msg.media.document
@ -200,7 +199,7 @@ async def download_profile_photo(
ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697)
# ('InputPeer', 'InputUser', 'InputChannel')
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)
thumb = -1 if download_big else 0
@ -225,9 +224,9 @@ async def download_profile_photo(
photo = entity.photo
if isinstance(photo, (types.UserProfilePhoto, types.ChatPhoto)):
if isinstance(photo, (_tl.UserProfilePhoto, _tl.ChatPhoto)):
dc_id = photo.dc_id
loc = types.InputPeerPhotoFileLocation(
loc = _tl.InputPeerPhotoFileLocation(
peer=await self.get_input_entity(entity),
photo_id=photo.photo_id,
big=download_big
@ -253,7 +252,7 @@ async def download_profile_photo(
ie = await self.get_input_entity(entity)
ty = helpers._entity_type(ie)
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(
full.full_chat.chat_photo, file,
date=None, progress_callback=None,
@ -268,7 +267,7 @@ async def download_media(
message: 'hints.MessageLike',
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]]:
# 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
@ -276,7 +275,7 @@ async def download_media(
msg_data = None
# TODO This won't work for messageService
if isinstance(message, types.Message):
if isinstance(message, _tl.Message):
date = message.date
media = message.media
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):
media = utils.resolve_bot_file_id(media)
if isinstance(media, types.MessageService):
if isinstance(media, _tl.MessageService):
if isinstance(message.action,
types.MessageActionChatEditPhoto):
_tl.MessageActionChatEditPhoto):
media = media.photo
if isinstance(media, types.MessageMediaWebPage):
if isinstance(media.webpage, types.WebPage):
if isinstance(media, _tl.MessageMediaWebPage):
if isinstance(media.webpage, _tl.WebPage):
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(
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(
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(
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(
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
# sizes sorted correctly with a custom function.
def sort_thumbs(thumb):
if isinstance(thumb, types.PhotoStrippedSize):
if isinstance(thumb, _tl.PhotoStrippedSize):
return 1, len(thumb.bytes)
if isinstance(thumb, types.PhotoCachedSize):
if isinstance(thumb, _tl.PhotoCachedSize):
return 1, len(thumb.bytes)
if isinstance(thumb, types.PhotoSize):
if isinstance(thumb, _tl.PhotoSize):
return 1, thumb.size
if isinstance(thumb, types.PhotoSizeProgressive):
if isinstance(thumb, _tl.PhotoSizeProgressive):
return 1, max(thumb.sizes)
if isinstance(thumb, types.VideoSize):
if isinstance(thumb, _tl.VideoSize):
return 2, thumb.size
# 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
# a SVG path of the outline. Users expect thumbnails to be JPEG files, so pretend this
# thumb size doesn't actually exist (#1655).
if isinstance(thumbs[i], types.PhotoPathSize):
if isinstance(thumbs[i], _tl.PhotoPathSize):
thumbs.pop(i)
if thumb is None:
@ -517,15 +516,15 @@ def _get_thumb(thumbs, thumb):
return thumbs[thumb]
elif isinstance(thumb, str):
return next((t for t in thumbs if t.type == thumb), None)
elif isinstance(thumb, (types.PhotoSize, types.PhotoCachedSize,
types.PhotoStrippedSize, types.VideoSize)):
elif isinstance(thumb, (_tl.PhotoSize, _tl.PhotoCachedSize,
_tl.PhotoStrippedSize, _tl.VideoSize)):
return thumb
else:
return None
def _download_cached_photo_size(self: 'TelegramClient', size, file):
# 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)
else:
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):
"""Specialized version of .download_media() for photos"""
# Determine the photo and its largest size
if isinstance(photo, types.MessageMediaPhoto):
if isinstance(photo, _tl.MessageMediaPhoto):
photo = photo.photo
if not isinstance(photo, types.Photo):
if not isinstance(photo, _tl.Photo):
return
# 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)
if not size or isinstance(size, types.PhotoSizeEmpty):
if not size or isinstance(size, _tl.PhotoSizeEmpty):
return
if isinstance(size, types.VideoSize):
if isinstance(size, _tl.VideoSize):
file = self._get_proper_filename(file, 'video', '.mp4', date=date)
else:
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)
if isinstance(size, types.PhotoSizeProgressive):
if isinstance(size, _tl.PhotoSizeProgressive):
file_size = max(size.sizes)
else:
file_size = size.size
result = await self.download_file(
types.InputPhotoFileLocation(
_tl.InputPhotoFileLocation(
id=photo.id,
access_hash=photo.access_hash,
file_reference=photo.file_reference,
@ -589,10 +588,10 @@ def _get_kind_and_names(attributes):
kind = 'document'
possible_names = []
for attr in attributes:
if isinstance(attr, types.DocumentAttributeFilename):
if isinstance(attr, _tl.DocumentAttributeFilename):
possible_names.insert(0, attr.file_name)
elif isinstance(attr, types.DocumentAttributeAudio):
elif isinstance(attr, _tl.DocumentAttributeAudio):
kind = 'audio'
if attr.performer and attr.title:
possible_names.append('{} - {}'.format(
@ -610,9 +609,9 @@ def _get_kind_and_names(attributes):
async def _download_document(
self, document, file, date, thumb, progress_callback, msg_data):
"""Specialized version of .download_media() for documents."""
if isinstance(document, types.MessageMediaDocument):
if isinstance(document, _tl.MessageMediaDocument):
document = document.document
if not isinstance(document, types.Document):
if not isinstance(document, _tl.Document):
return
if thumb is None:
@ -625,11 +624,11 @@ async def _download_document(
else:
file = self._get_proper_filename(file, 'photo', '.jpg', date=date)
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)
result = await self._download_file(
types.InputDocumentFileLocation(
_tl.InputDocumentFileLocation(
id=document.id,
access_hash=document.access_hash,
file_reference=document.file_reference,

View File

@ -2,8 +2,7 @@ import itertools
import re
import typing
from .. import helpers, utils
from ..tl import types
from .. import helpers, utils, _tl
if typing.TYPE_CHECKING:
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.
"""
try:
entities[i] = types.InputMessageEntityMentionName(
entities[i] = _tl.InputMessageEntityMentionName(
entities[i].offset, entities[i].length,
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))):
e = msg_entities[i]
if isinstance(e, types.MessageEntityTextUrl):
if isinstance(e, _tl.MessageEntityTextUrl):
m = re.match(r'^@|\+|tg://user\?id=(\d+)', e.url)
if m:
user = int(m.group(1)) if m.group(1) else e.url
is_mention = await self._replace_with_mention(msg_entities, i, user)
if not is_mention:
del msg_entities[i]
elif isinstance(e, (types.MessageEntityMentionName,
types.InputMessageEntityMentionName)):
elif isinstance(e, (_tl.MessageEntityMentionName,
_tl.InputMessageEntityMentionName)):
is_mention = await self._replace_with_mention(msg_entities, i, e.user_id)
if not is_mention:
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 isinstance(result, types.UpdateShort):
if isinstance(result, _tl.UpdateShort):
updates = [result.update]
entities = {}
elif isinstance(result, (types.Updates, types.UpdatesCombined)):
elif isinstance(result, (_tl.Updates, _tl.UpdatesCombined)):
updates = result.updates
entities = {utils.get_peer_id(x): x
for x in
@ -90,11 +89,11 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
random_to_id = {}
id_to_message = {}
for update in updates:
if isinstance(update, types.UpdateMessageID):
if isinstance(update, _tl.UpdateMessageID):
random_to_id[update.random_id] = update.id
elif isinstance(update, (
types.UpdateNewChannelMessage, types.UpdateNewMessage)):
_tl.UpdateNewChannelMessage, _tl.UpdateNewMessage)):
update.message._finish_init(self, entities, input_chat)
# Pinning a message with `updatePinnedMessage` seems to
@ -109,7 +108,7 @@ def _get_response_message(self: 'TelegramClient', request, result, input_chat):
else:
return update.message
elif (isinstance(update, types.UpdateEditMessage)
elif (isinstance(update, _tl.UpdateEditMessage)
and helpers._entity_type(request.peer) != helpers._EntityType.CHANNEL):
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:
return update.message
elif (isinstance(update, types.UpdateEditChannelMessage)
elif (isinstance(update, _tl.UpdateEditChannelMessage)
and utils.get_peer_id(request.peer) ==
utils.get_peer_id(update.message.peer_id)):
if request.id == update.message.id:
update.message._finish_init(self, entities, input_chat)
return update.message
elif isinstance(update, types.UpdateNewScheduledMessage):
elif isinstance(update, _tl.UpdateNewScheduledMessage):
update.message._finish_init(self, entities, input_chat)
# Scheduled IDs may collide with normal IDs. However, for a
# single request there *shouldn't* be a mix between "some
# scheduled and some not".
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:
m = types.Message(
m = _tl.Message(
id=request.id,
peer_id=utils.get_peer(request.peer),
media=types.MessageMediaPoll(
media=_tl.MessageMediaPoll(
poll=update.poll,
results=update.results
)

View File

@ -3,9 +3,8 @@ import itertools
import typing
import warnings
from .. import helpers, utils, errors, hints
from .. import helpers, utils, errors, hints, _tl
from ..requestiter import RequestIter
from ..tl import types, functions
_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
# a normal `messages.search`, *but* we can make the entity be `inputPeerEmpty`.
if not self.entity and from_user:
self.entity = types.InputPeerEmpty()
self.entity = _tl.InputPeerEmpty()
if filter is None:
filter = types.InputMessagesFilterEmpty()
filter = _tl.InputMessagesFilterEmpty()
else:
filter = filter() if isinstance(filter, type) else filter
if not self.entity:
self.request = functions.messages.SearchGlobalRequest(
self.request = _tl.fn.messages.SearchGlobal(
q=search or '',
filter=filter,
min_date=None,
max_date=offset_date,
offset_rate=0,
offset_peer=types.InputPeerEmpty(),
offset_peer=_tl.InputPeerEmpty(),
offset_id=offset_id,
limit=1
)
elif scheduled:
self.request = functions.messages.GetScheduledHistoryRequest(
self.request = _tl.fn.messages.GetScheduledHistory(
peer=entity,
hash=0
)
elif reply_to is not None:
self.request = functions.messages.GetRepliesRequest(
self.request = _tl.fn.messages.GetReplies(
peer=self.entity,
msg_id=reply_to,
offset_id=offset_id,
@ -102,7 +101,7 @@ class _MessagesIter(RequestIter):
min_id=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
ty = helpers._entity_type(self.entity)
if ty == helpers._EntityType.USER:
@ -114,7 +113,7 @@ class _MessagesIter(RequestIter):
# and set `from_id` to None to avoid checking it locally.
self.from_id = None
self.request = functions.messages.SearchRequest(
self.request = _tl.fn.messages.Search(
peer=self.entity,
q=search or '',
filter=filter,
@ -136,13 +135,13 @@ class _MessagesIter(RequestIter):
#
# Even better, using `filter` and `from_id` seems to always
# 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:
async for m in self.client.iter_messages(
self.entity, 1, offset_date=offset_date):
self.request.offset_id = m.id + 1
else:
self.request = functions.messages.GetHistoryRequest(
self.request = _tl.fn.messages.GetHistory(
peer=self.entity,
limit=1,
offset_date=offset_date,
@ -156,7 +155,7 @@ class _MessagesIter(RequestIter):
if self.limit <= 0:
# No messages, but we still need to know the total message count
result = await self.client(self.request)
if isinstance(result, types.messages.MessagesNotModified):
if isinstance(result, _tl.messages.MessagesNotModified):
self.total = result.count
else:
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
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):
continue
@ -245,7 +244,7 @@ class _MessagesIter(RequestIter):
# We want to skip the one we already have
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,
# 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
@ -255,11 +254,11 @@ class _MessagesIter(RequestIter):
# getHistory, searchGlobal and getReplies call it offset_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:
self.request.offset_peer = last_message.input_chat
else:
self.request.offset_peer = types.InputPeerEmpty()
self.request.offset_peer = _tl.InputPeerEmpty()
self.request.offset_rate = getattr(response, 'next_rate', 0)
@ -287,16 +286,16 @@ class _IDsIter(RequestIter):
if self._ty == helpers._EntityType.CHANNEL:
try:
r = await self.client(
functions.channels.GetMessagesRequest(self._entity, ids))
_tl.fn.channels.GetMessages(self._entity, ids))
except errors.MessageIdsEmptyError:
# All IDs were invalid, use a dummy result
r = types.messages.MessagesNotModified(len(ids))
r = _tl.messages.MessagesNotModified(len(ids))
else:
r = await self.client(functions.messages.GetMessagesRequest(ids))
r = await self.client(_tl.fn.messages.GetMessages(ids))
if 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)
return
@ -312,7 +311,7 @@ class _IDsIter(RequestIter):
# since the user can enter arbitrary numbers which can belong to
# arbitrary chats. Validate these unless ``from_id is None``.
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):
self.buffer.append(None)
else:
@ -331,7 +330,7 @@ def iter_messages(
min_id: int = 0,
add_offset: int = 0,
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,
wait_time: float = 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(
self: 'TelegramClient',
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,
msg_id=utils.get_message_id(message)
))
@ -408,10 +407,10 @@ async def send_message(
entity: 'hints.EntityLike',
message: 'hints.MessageLike' = '',
*,
reply_to: 'typing.Union[int, types.Message]' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None,
reply_to: 'typing.Union[int, _tl.Message]' = None,
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
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,
file: 'typing.Union[hints.FileLike, typing.Sequence[hints.FileLike]]' = None,
thumb: 'hints.FileLike' = None,
@ -422,8 +421,8 @@ async def send_message(
background: bool = None,
supports_streaming: bool = False,
schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None
) -> 'types.Message':
comment_to: 'typing.Union[int, _tl.Message]' = None
) -> '_tl.Message':
if file is not None:
return await self.send_file(
entity, file, caption=message, reply_to=reply_to,
@ -439,7 +438,7 @@ async def send_message(
if comment_to is not None:
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:
markup = message.reply_markup
else:
@ -449,7 +448,7 @@ async def send_message(
silent = message.silent
if (message.media and not isinstance(
message.media, types.MessageMediaWebPage)):
message.media, _tl.MessageMediaWebPage)):
return await self.send_file(
entity,
message.media,
@ -462,7 +461,7 @@ async def send_message(
schedule=schedule
)
request = functions.messages.SendMessageRequest(
request = _tl.fn.messages.SendMessage(
peer=entity,
message=message.message or '',
silent=silent,
@ -472,7 +471,7 @@ async def send_message(
entities=message.entities,
clear_draft=clear_draft,
no_webpage=not isinstance(
message.media, types.MessageMediaWebPage),
message.media, _tl.MessageMediaWebPage),
schedule_date=schedule
)
message = message.message
@ -484,7 +483,7 @@ async def send_message(
'The message cannot be empty unless a file is provided'
)
request = functions.messages.SendMessageRequest(
request = _tl.fn.messages.SendMessage(
peer=entity,
message=message,
entities=formatting_entities,
@ -498,8 +497,8 @@ async def send_message(
)
result = await self(request)
if isinstance(result, types.UpdateShortSentMessage):
message = types.Message(
if isinstance(result, _tl.UpdateShortSentMessage):
message = _tl.Message(
id=result.id,
peer_id=await self._get_peer(entity),
message=message,
@ -526,7 +525,7 @@ async def forward_messages(
silent: bool = None,
as_album: bool = None,
schedule: 'hints.DateLike' = None
) -> 'typing.Sequence[types.Message]':
) -> 'typing.Sequence[_tl.Message]':
if as_album is not None:
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
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
else:
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()
chunk = [m.id for m in chunk]
req = functions.messages.ForwardMessagesRequest(
req = _tl.fn.messages.ForwardMessages(
from_peer=chat,
id=chunk,
to_peer=entity,
@ -578,13 +577,13 @@ async def forward_messages(
async def edit_message(
self: 'TelegramClient',
entity: 'typing.Union[hints.EntityLike, types.Message]',
entity: 'typing.Union[hints.EntityLike, _tl.Message]',
message: 'hints.MessageLike' = None,
text: str = None,
*,
parse_mode: str = (),
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None,
formatting_entities: typing.Optional[typing.List[types.TypeMessageEntity]] = None,
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None,
link_preview: bool = True,
file: 'hints.FileLike' = None,
thumb: 'hints.FileLike' = None,
@ -592,11 +591,11 @@ async def edit_message(
buttons: 'hints.MarkupLike' = None,
supports_streaming: bool = False,
schedule: 'hints.DateLike' = None
) -> 'types.Message':
if isinstance(entity, types.InputBotInlineMessageID):
) -> '_tl.Message':
if isinstance(entity, _tl.InputBotInlineMessageID):
text = text or message
message = entity
elif isinstance(entity, types.Message):
elif isinstance(entity, _tl.Message):
text = message # Shift the parameters to the right
message = entity
entity = entity.peer_id
@ -609,8 +608,8 @@ async def edit_message(
attributes=attributes,
force_document=force_document)
if isinstance(entity, types.InputBotInlineMessageID):
request = functions.messages.EditInlineBotMessageRequest(
if isinstance(entity, _tl.InputBotInlineMessageID):
request = _tl.fn.messages.EditInlineBotMessage(
id=entity,
message=text,
no_webpage=not link_preview,
@ -631,7 +630,7 @@ async def edit_message(
return await self(request)
entity = await self.get_input_entity(entity)
request = functions.messages.EditMessageRequest(
request = _tl.fn.messages.EditMessage(
peer=entity,
id=utils.get_message_id(message),
message=text,
@ -649,13 +648,13 @@ async def delete_messages(
entity: 'hints.EntityLike',
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):
message_ids = (message_ids,)
message_ids = (
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
)
@ -667,10 +666,10 @@ async def delete_messages(
ty = helpers._EntityType.USER
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)])
else:
return await self([functions.messages.DeleteMessagesRequest(
return await self([_tl.fn.messages.DeleteMessages(
list(c), revoke) for c in utils.chunks(message_ids)])
async def send_read_acknowledge(
@ -691,16 +690,16 @@ async def send_read_acknowledge(
entity = await self.get_input_entity(entity)
if clear_mentions:
await self(functions.messages.ReadMentionsRequest(entity))
await self(_tl.fn.messages.ReadMentions(entity))
if max_id is None:
return True
if max_id is not None:
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))
else:
return await self(functions.messages.ReadHistoryRequest(
return await self(_tl.fn.messages.ReadHistory(
entity, max_id=max_id))
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
entity = await self.get_input_entity(entity)
if message <= 0: # old behaviour accepted negative IDs to unpin
await self(functions.messages.UnpinAllMessagesRequest(entity))
await self(_tl.fn.messages.UnpinAllMessages(entity))
return
request = functions.messages.UpdatePinnedMessageRequest(
request = _tl.fn.messages.UpdatePinnedMessage(
peer=entity,
id=message,
silent=not notify,

View File

@ -7,15 +7,13 @@ import platform
import time
import typing
from .. import version, helpers, __name__ as __base_name__
from .. import version, helpers, __name__ as __base_name__, _tl
from ..crypto import rsa
from ..entitycache import EntityCache
from ..extensions import markdown
from ..network import MTProtoSender, Connection, ConnectionTcpFull, TcpMTProxy
from ..sessions import Session, SQLiteSession, MemorySession
from ..statecache import StateCache
from ..tl import functions, types
from ..tl.alltlobjects import LAYER
DEFAULT_DC_ID = 2
DEFAULT_IPV4_IP = '149.154.167.51'
@ -122,7 +120,7 @@ def init(
import warnings
warnings.warn(
'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'
'You will need to re-login every time unless '
'you use another session storage'
@ -198,7 +196,7 @@ def init(
assert isinstance(connection, type)
self._connection = connection
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
# exporting clients need to create this InvokeWithLayerRequest.
@ -212,7 +210,7 @@ def init(
default_device_model = system.machine
default_system_version = re.sub(r'-.+','',system.release)
self._init_request = functions.InitConnectionRequest(
self._init_request = _tl.fn.InitConnection(
api_id=self.api_id,
device_model=device_model or default_device_model or 'Unknown',
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.save()
self._init_request.query = functions.help.GetConfigRequest()
self._init_request.query = _tl.fn.help.GetConfig()
await self._sender.send(functions.InvokeWithLayerRequest(
LAYER, self._init_request
await self._sender.send(_tl.fn.InvokeWithLayer(
_tl.alltlobjects.LAYER, self._init_request
))
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]):
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._proxy = proxy
@ -386,7 +384,7 @@ async def _disconnect_coro(self: 'TelegramClient'):
pts, date = self._state_cache[None]
if pts and date:
self.session.set_update_state(0, types.updates.State(
self.session.set_update_state(0, _tl.updates.State(
pts=pts,
qts=0,
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'"""
cls = self.__class__
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:
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:
rsa.add_key(pk.public_key)
@ -481,9 +479,9 @@ async def _create_exported_sender(self: 'TelegramClient', dc_id):
local_addr=self._local_addr
))
self._log[__name__].info('Exporting auth for new borrowed sender in %s', dc)
auth = await self(functions.auth.ExportAuthorizationRequest(dc_id))
self._init_request.query = functions.auth.ImportAuthorizationRequest(id=auth.id, bytes=auth.bytes)
req = functions.InvokeWithLayerRequest(LAYER, self._init_request)
auth = await self(_tl.fn.auth.ExportAuthorization(dc_id))
self._init_request.query = _tl.fn.auth.ImportAuthorization(id=auth.id, bytes=auth.bytes)
req = _tl.fn.InvokeWithLayer(LAYER, self._init_request)
await sender.send(req)
return sender

View File

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

View File

@ -8,9 +8,8 @@ import traceback
import typing
import logging
from .. import events, utils, errors
from .. import events, utils, errors, _tl
from ..events.common import EventBuilder, EventCommon
from ..tl import types, functions
if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient
@ -22,7 +21,7 @@ Callback = typing.Callable[[typing.Any], typing.Any]
async def _run_until_disconnected(self: 'TelegramClient'):
try:
# 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
except KeyboardInterrupt:
pass
@ -32,7 +31,7 @@ async def _run_until_disconnected(self: 'TelegramClient'):
async def set_receive_updates(self: 'TelegramClient', receive_updates):
self._no_updates = not receive_updates
if receive_updates:
await self(functions.updates.GetStateRequest())
await self(_tl.fn.updates.GetState())
async def run_until_disconnected(self: 'TelegramClient'):
return await self._run_until_disconnected()
@ -91,24 +90,24 @@ async def catch_up(self: 'TelegramClient'):
self.session.catching_up = True
try:
while True:
d = await self(functions.updates.GetDifferenceRequest(
d = await self(_tl.fn.updates.GetDifference(
pts, date, 0
))
if isinstance(d, (types.updates.DifferenceSlice,
types.updates.Difference)):
if isinstance(d, types.updates.Difference):
if isinstance(d, (_tl.updates.DifferenceSlice,
_tl.updates.Difference)):
if isinstance(d, _tl.updates.Difference):
state = d.state
else:
state = d.intermediate_state
pts, date = state.pts, state.date
self._handle_update(types.Updates(
self._handle_update(_tl.Updates(
users=d.users,
chats=d.chats,
date=state.date,
seq=state.seq,
updates=d.other_updates + [
types.UpdateNewMessage(m, 0, 0)
_tl.UpdateNewMessage(m, 0, 0)
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.
# it would return an update we have already seen).
else:
if isinstance(d, types.updates.DifferenceEmpty):
if isinstance(d, _tl.updates.DifferenceEmpty):
date = d.date
elif isinstance(d, types.updates.DifferenceTooLong):
elif isinstance(d, _tl.updates.DifferenceTooLong):
pts = d.pts
break
except (ConnectionError, asyncio.CancelledError):
@ -148,12 +147,12 @@ def _handle_update(self: 'TelegramClient', update):
self.session.process_entities(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
itertools.chain(update.users, update.chats)}
for u in update.updates:
self._process_update(u, update.updates, entities=entities)
elif isinstance(update, types.UpdateShort):
elif isinstance(update, _tl.UpdateShort):
self._process_update(update.update, None)
else:
self._process_update(update, None)
@ -230,7 +229,7 @@ async def _update_loop(self: 'TelegramClient'):
continue
try:
await self(functions.updates.GetStateRequest())
await self(_tl.fn.updates.GetState())
except (ConnectionError, asyncio.CancelledError):
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)
try:
# 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:
# There's a high chance that this fails, since
# 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:
# 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)
))
self._state_cache[channel_id] = result.full_chat.pts
return
result = await self(functions.updates.GetChannelDifferenceRequest(
result = await self(_tl.fn.updates.GetChannelDifference(
channel=where,
filter=types.ChannelMessagesFilterEmpty(),
filter=_tl.ChannelMessagesFilterEmpty(),
pts=pts_date, # just pts
limit=100,
force=True
@ -383,20 +382,20 @@ async def _get_difference(self: 'TelegramClient', update, channel_id, pts_date):
else:
if not pts_date[0]:
# 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
return
result = await self(functions.updates.GetDifferenceRequest(
result = await self(_tl.fn.updates.GetDifference(
pts=pts_date[0],
date=pts_date[1],
qts=0
))
if isinstance(result, (types.updates.Difference,
types.updates.DifferenceSlice,
types.updates.ChannelDifference,
types.updates.ChannelDifferenceTooLong)):
if isinstance(result, (_tl.updates.Difference,
_tl.updates.DifferenceSlice,
_tl.updates.ChannelDifference,
_tl.updates.ChannelDifferenceTooLong)):
update._entities.update({
utils.get_peer_id(x): x for x in
itertools.chain(result.users, result.chats)

View File

@ -9,8 +9,7 @@ from io import BytesIO
from ..crypto import AES
from .. import utils, helpers, hints
from ..tl import types, functions, custom
from .. import utils, helpers, hints, _tl
try:
import PIL
@ -99,11 +98,11 @@ async def send_file(
clear_draft: bool = False,
progress_callback: 'hints.ProgressCallback' = None,
reply_to: 'hints.MessageIDLike' = None,
attributes: 'typing.Sequence[types.TypeDocumentAttribute]' = None,
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None,
thumb: 'hints.FileLike' = None,
allow_cache: bool = True,
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,
video_note: bool = False,
buttons: 'hints.MarkupLike' = None,
@ -111,9 +110,9 @@ async def send_file(
background: bool = None,
supports_streaming: bool = False,
schedule: 'hints.DateLike' = None,
comment_to: 'typing.Union[int, types.Message]' = None,
comment_to: 'typing.Union[int, _tl.Message]' = None,
ttl: int = None,
**kwargs) -> 'types.Message':
**kwargs) -> '_tl.Message':
# TODO Properly implement allow_cache to reuse the sha256 of the file
# i.e. `None` was used
if not file:
@ -182,7 +181,7 @@ async def send_file(
raise TypeError('Cannot use {!r} as file'.format(file))
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,
entities=msg_entities, reply_markup=markup, silent=silent,
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(
file, supports_streaming=supports_streaming,
force_document=force_document, ttl=ttl)
if isinstance(fm, (types.InputMediaUploadedPhoto, types.InputMediaPhotoExternal)):
r = await self(functions.messages.UploadMediaRequest(
if isinstance(fm, (_tl.InputMediaUploadedPhoto, _tl.InputMediaPhotoExternal)):
r = await self(_tl.fn.messages.UploadMedia(
entity, media=fm
))
fm = utils.get_input_media(r.photo)
elif isinstance(fm, types.InputMediaUploadedDocument):
r = await self(functions.messages.UploadMediaRequest(
elif isinstance(fm, _tl.InputMediaUploadedDocument):
r = await self(_tl.fn.messages.UploadMedia(
entity, media=fm
))
@ -243,7 +242,7 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
caption, msg_entities = captions.pop()
else:
caption, msg_entities = '', None
media.append(types.InputSingleMedia(
media.append(_tl.InputSingleMedia(
fm,
message=caption,
entities=msg_entities
@ -251,7 +250,7 @@ async def _send_album(self: 'TelegramClient', entity, files, caption='',
))
# 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,
silent=silent, schedule_date=schedule, clear_draft=clear_draft,
background=background
@ -271,8 +270,8 @@ async def upload_file(
use_cache: type = None,
key: bytes = None,
iv: bytes = None,
progress_callback: 'hints.ProgressCallback' = None) -> 'types.TypeInputFile':
if isinstance(file, (types.InputFile, types.InputFileBig)):
progress_callback: 'hints.ProgressCallback' = None) -> '_tl.TypeInputFile':
if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
return file # Already uploaded
pos = 0
@ -343,10 +342,10 @@ async def upload_file(
# The SavePartRequest is different depending on whether
# the file is too large or not (over or less than 10MB)
if is_big:
request = functions.upload.SaveBigFilePartRequest(
request = _tl.fn.upload.SaveBigFilePart(
file_id, part_index, part_count, part)
else:
request = functions.upload.SaveFilePartRequest(
request = _tl.fn.upload.SaveFilePart(
file_id, part_index, part)
result = await self(request)
@ -360,9 +359,9 @@ async def upload_file(
'Failed to upload file part {}.'.format(part_index))
if is_big:
return types.InputFileBig(file_id, part_count, file_name)
return _tl.InputFileBig(file_id, part_count, file_name)
else:
return custom.InputSizedFile(
return _tl.custom.InputSizedFile(
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
# 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'):
# The user may pass a Message containing media (or the media,
# or anything similar) that should be treated as a file. Try
@ -411,7 +410,7 @@ async def _file_to_media(
media = None
file_handle = None
if isinstance(file, (types.InputFile, types.InputFileBig)):
if isinstance(file, (_tl.InputFile, _tl.InputFileBig)):
file_handle = file
elif not isinstance(file, str) or os.path.isfile(file):
file_handle = await self.upload_file(
@ -421,9 +420,9 @@ async def _file_to_media(
)
elif re.match('https?://', file):
if as_image:
media = types.InputMediaPhotoExternal(file, ttl_seconds=ttl)
media = _tl.InputMediaPhotoExternal(file, ttl_seconds=ttl)
else:
media = types.InputMediaDocumentExternal(file, ttl_seconds=ttl)
media = _tl.InputMediaDocumentExternal(file, ttl_seconds=ttl)
else:
bot_file = utils.resolve_bot_file_id(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)
)
elif as_image:
media = types.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl)
media = _tl.InputMediaUploadedPhoto(file_handle, ttl_seconds=ttl)
else:
attributes, mime_type = utils.get_attributes(
file,
@ -457,7 +456,7 @@ async def _file_to_media(
thumb = str(thumb.absolute())
thumb = await self.upload_file(thumb, file_size=file_size)
media = types.InputMediaUploadedDocument(
media = _tl.InputMediaUploadedDocument(
file=file_handle,
mime_type=mime_type,
attributes=attributes,

View File

@ -4,10 +4,9 @@ import itertools
import time
import typing
from .. import errors, helpers, utils, hints
from .. import errors, helpers, utils, hints, _tl
from ..errors import MultiError, RPCError
from ..helpers import retry_range
from ..tl import TLRequest, types, functions
_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)
if self._no_updates:
r = functions.InvokeWithoutUpdatesRequest(r)
r = _tl.fn.InvokeWithoutUpdates(r)
request_index = 0
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) \
-> 'typing.Union[types.User, types.InputPeerUser]':
-> 'typing.Union[_tl.User, _tl.InputPeerUser]':
if input_peer and self._self_input_peer:
return self._self_input_peer
try:
me = (await self(
functions.users.GetUsersRequest([types.InputUserSelf()])))[0]
_tl.fn.users.GetUsers([_tl.InputUserSelf()])))[0]
self._bot = me.bot
if not self._self_input_peer:
@ -165,7 +164,7 @@ async def is_user_authorized(self: 'TelegramClient') -> bool:
if self._authorized is None:
try:
# Any request that requires authorization will work
await self(functions.updates.GetStateRequest())
await self(_tl.fn.updates.GetState())
self._authorized = True
except errors.RPCError:
self._authorized = False
@ -209,14 +208,14 @@ async def get_entity(
tmp = []
while users:
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
if chats: # TODO Handle chats slice?
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:
channels = (await self(
functions.channels.GetChannelsRequest(channels))).chats
_tl.fn.channels.GetChannels(channels))).chats
# Merge users, chats and channels into a single dictionary
id_entity = {
@ -232,19 +231,19 @@ async def get_entity(
for x in inputs:
if isinstance(x, str):
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)])
else:
result.append(next(
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
async def get_input_entity(
self: 'TelegramClient',
peer: 'hints.EntityLike') -> 'types.TypeInputPeer':
peer: 'hints.EntityLike') -> '_tl.TypeInputPeer':
# Short-circuit if the input parameter directly maps to an InputPeer
try:
return utils.get_input_peer(peer)
@ -261,7 +260,7 @@ async def get_input_entity(
# Then come known strings that take precedence
if peer in ('me', 'self'):
return types.InputPeerSelf()
return _tl.InputPeerSelf()
# No InputPeer, cached peer, or known string. Fetch from disk cache
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
# regardless. These are the only two special-cased requests.
peer = utils.get_peer(peer)
if isinstance(peer, types.PeerUser):
users = await self(functions.users.GetUsersRequest([
types.InputUser(peer.user_id, access_hash=0)]))
if users and not isinstance(users[0], types.UserEmpty):
if isinstance(peer, _tl.PeerUser):
users = await self(_tl.fn.users.GetUsers([
_tl.InputUser(peer.user_id, access_hash=0)]))
if users and not isinstance(users[0], _tl.UserEmpty):
# If the user passed a valid ID they expect to work for
# channels but would be valid for users, we get UserEmpty.
# 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
# another request, but that becomes too much work.
return utils.get_input_peer(users[0])
elif isinstance(peer, types.PeerChat):
return types.InputPeerChat(peer.chat_id)
elif isinstance(peer, types.PeerChannel):
elif isinstance(peer, _tl.PeerChat):
return _tl.InputPeerChat(peer.chat_id)
elif isinstance(peer, _tl.PeerChannel):
try:
channels = await self(functions.channels.GetChannelsRequest([
types.InputChannel(peer.channel_id, access_hash=0)]))
channels = await self(_tl.fn.channels.GetChannels([
_tl.InputChannel(peer.channel_id, access_hash=0)]))
return utils.get_input_peer(channels.chats[0])
except errors.ChannelInvalidError:
pass
@ -326,7 +325,7 @@ async def get_peer_id(
except AttributeError:
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)
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:
try:
for user in (await self(
functions.contacts.GetContactsRequest(0))).users:
_tl.fn.contacts.GetContacts(0))).users:
if user.phone == phone:
return user
except errors.BotMethodInvalidError:
@ -360,26 +359,26 @@ async def _get_entity_from_string(self: 'TelegramClient', string):
username, is_join_chat = utils.parse_username(string)
if is_join_chat:
invite = await self(
functions.messages.CheckChatInviteRequest(username))
_tl.fn.messages.CheckChatInvite(username))
if isinstance(invite, types.ChatInvite):
if isinstance(invite, _tl.ChatInvite):
raise ValueError(
'Cannot get entity from a channel (or group) '
'that you are not part of. Join the group and retry'
)
elif isinstance(invite, types.ChatInviteAlready):
elif isinstance(invite, _tl.ChatInviteAlready):
return invite.chat
elif username:
try:
result = await self(
functions.contacts.ResolveUsernameRequest(username))
_tl.fn.contacts.ResolveUsername(username))
except errors.UsernameNotOccupiedError as e:
raise ValueError('No user has "{}" as username'
.format(username)) from e
try:
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)
else:
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)
return dialog
elif dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
return types.InputDialogPeer(dialog)
return _tl.InputDialogPeer(dialog)
except AttributeError:
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):
"""
@ -421,10 +420,10 @@ async def _get_input_notify(self: 'TelegramClient', notify):
"""
try:
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)
return notify
except AttributeError:
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 ..tl.functions.upload import GetCdnFileRequest, ReuploadCdnFileRequest
from ..tl.types.upload import CdnFileReuploadNeeded, CdnFile
from .. import _tl
from ..crypto import AESModeCTR
from ..errors import CdnFileTamperedError
@ -52,14 +51,14 @@ class CdnDecrypter:
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,
offset=cdn_redirect.cdn_file_hashes[0].offset,
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
await client(ReuploadCdnFileRequest(
await client(_tl.fn.upload.ReuploadCdnFile(
file_token=cdn_redirect.file_token,
request_token=cdn_file.request_token
))
@ -82,13 +81,13 @@ class CdnDecrypter:
"""
if self.cdn_file_hashes:
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
))
cdn_file.bytes = self.cdn_aes.encrypt(cdn_file.bytes)
self.check(cdn_file.bytes, cdn_hash)
else:
cdn_file = CdnFile(bytes(0))
cdn_file = _tl.upload.CdnFile(bytes(0))
return cdn_file

View File

@ -11,7 +11,7 @@ except ImportError:
rsa = None
raise ImportError('Missing module "rsa", please install via pip.')
from ..tl import TLObject
from .. import _tl
# {fingerprint: (Crypto.PublicKey.RSA._RSAobj, old)} dictionary
@ -41,8 +41,8 @@ def _compute_fingerprint(key):
:param key: the Crypto.RSA key.
:return: its 8-bytes-long fingerprint.
"""
n = TLObject.serialize_bytes(get_byte_array(key.n))
e = TLObject.serialize_bytes(get_byte_array(key.e))
n = _tl.TLObject.serialize_bytes(get_byte_array(key.n))
e = _tl.TLObject.serialize_bytes(get_byte_array(key.e))
# Telegram uses the last 8 bytes as the fingerprint
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 ..errors import TypeNotFoundError
from ..tl.alltlobjects import tlobjects
from ..tl.core import core_objects
from .. import _tl
_EPOCH_NAIVE = datetime(*time.gmtime(0)[:6])
_EPOCH = _EPOCH_NAIVE.replace(tzinfo=timezone.utc)
@ -118,7 +117,7 @@ class BinaryReader:
def tgread_object(self):
"""Reads a Telegram object."""
constructor_id = self.read_int(signed=False)
clazz = tlobjects.get(constructor_id, None)
clazz = _tl.tlobjects.get(constructor_id, None)
if clazz is None:
# The class was None, but there's still a
# chance of it being a manually parsed value like bool!
@ -130,7 +129,7 @@ class BinaryReader:
elif value == 0x1cb5c415: # Vector
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 there was still no luck, give up
self.seek(-4) # Go back

View File

@ -1,8 +1,7 @@
import inspect
import itertools
from . import utils
from .tl import types
from . import utils, _tl
# Which updates have the following fields?
_has_field = {
@ -25,8 +24,8 @@ _has_field = {
def _fill():
for name in dir(types):
update = getattr(types, name)
for name in dir(_tl):
update = getattr(_tl, name)
if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e:
cid = update.CONSTRUCTOR_ID
sig = inspect.signature(update.__init__)
@ -84,7 +83,7 @@ class EntityCache:
except TypeError:
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)))
if result:
return result
@ -111,7 +110,7 @@ class EntityCache:
"""
# This method is called pretty often and we want it to have the lowest
# 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.
dct = self.__dict__
cid = update.CONSTRUCTOR_ID
@ -120,11 +119,11 @@ class EntityCache:
return False
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
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
if cid in has_peer and \

View File

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

View File

@ -7,14 +7,7 @@ from html import escape
from html.parser import HTMLParser
from typing import Iterable, Optional, Tuple, List
from .. import helpers
from ..tl.types import (
MessageEntityBold, MessageEntityItalic, MessageEntityCode,
MessageEntityPre, MessageEntityEmail, MessageEntityUrl,
MessageEntityTextUrl, MessageEntityMentionName,
MessageEntityUnderline, MessageEntityStrike, MessageEntityBlockquote,
TypeMessageEntity
)
from .. import helpers, _tl
# Helpers from markdown.py
@ -46,15 +39,15 @@ class HTMLToTelegramParser(HTMLParser):
EntityType = None
args = {}
if tag == 'strong' or tag == 'b':
EntityType = MessageEntityBold
EntityType = _tl.MessageEntityBold
elif tag == 'em' or tag == 'i':
EntityType = MessageEntityItalic
EntityType = _tl.MessageEntityItalic
elif tag == 'u':
EntityType = MessageEntityUnderline
EntityType = _tl.MessageEntityUnderline
elif tag == 'del' or tag == 's':
EntityType = MessageEntityStrike
EntityType = _tl.MessageEntityStrike
elif tag == 'blockquote':
EntityType = MessageEntityBlockquote
EntityType = _tl.MessageEntityBlockquote
elif tag == 'code':
try:
# If we're in the middle of a <pre> tag, this <code> tag is
@ -69,9 +62,9 @@ class HTMLToTelegramParser(HTMLParser):
except KeyError:
pass
except KeyError:
EntityType = MessageEntityCode
EntityType = _tl.MessageEntityCode
elif tag == 'pre':
EntityType = MessageEntityPre
EntityType = _tl.MessageEntityPre
args['language'] = ''
elif tag == 'a':
try:
@ -80,12 +73,12 @@ class HTMLToTelegramParser(HTMLParser):
return
if url.startswith('mailto:'):
url = url[len('mailto:'):]
EntityType = MessageEntityEmail
EntityType = _tl.MessageEntityEmail
else:
if self.get_starttag_text() == url:
EntityType = MessageEntityUrl
EntityType = _tl.MessageEntityUrl
else:
EntityType = MessageEntityTextUrl
EntityType = _tl.MessageEntityTextUrl
args['url'] = url
url = None
self._open_tags_meta.popleft()
@ -121,10 +114,10 @@ class HTMLToTelegramParser(HTMLParser):
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
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.
: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
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:
"""
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 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.
"""
if not text:
@ -185,19 +178,19 @@ def unparse(text: str, entities: Iterable[TypeMessageEntity], _offset: int = 0,
_offset=entity.offset, _length=length)
entity_type = type(entity)
if entity_type == MessageEntityBold:
if entity_type == _tl.MessageEntityBold:
html.append('<strong>{}</strong>'.format(entity_text))
elif entity_type == MessageEntityItalic:
elif entity_type == _tl.MessageEntityItalic:
html.append('<em>{}</em>'.format(entity_text))
elif entity_type == MessageEntityCode:
elif entity_type == _tl.MessageEntityCode:
html.append('<code>{}</code>'.format(entity_text))
elif entity_type == MessageEntityUnderline:
elif entity_type == _tl.MessageEntityUnderline:
html.append('<u>{}</u>'.format(entity_text))
elif entity_type == MessageEntityStrike:
elif entity_type == _tl.MessageEntityStrike:
html.append('<del>{}</del>'.format(entity_text))
elif entity_type == MessageEntityBlockquote:
elif entity_type == _tl.MessageEntityBlockquote:
html.append('<blockquote>{}</blockquote>'.format(entity_text))
elif entity_type == MessageEntityPre:
elif entity_type == _tl.MessageEntityPre:
if entity.language:
html.append(
"<pre>\n"
@ -208,14 +201,14 @@ def unparse(text: str, entities: Iterable[TypeMessageEntity], _offset: int = 0,
else:
html.append('<pre><code>{}</code></pre>'
.format(entity_text))
elif entity_type == MessageEntityEmail:
elif entity_type == _tl.MessageEntityEmail:
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))
elif entity_type == MessageEntityTextUrl:
elif entity_type == _tl.MessageEntityTextUrl:
html.append('<a href="{}">{}</a>'
.format(escape(entity.url), entity_text))
elif entity_type == MessageEntityMentionName:
elif entity_type == _tl.MessageEntityMentionName:
html.append('<a href="tg://user?id={}">{}</a>'
.format(entity.user_id, entity_text))
else:

View File

@ -7,19 +7,14 @@ import re
import warnings
from ..helpers import add_surrogate, del_surrogate, within_surrogate, strip_text
from ..tl import TLObject
from ..tl.types import (
MessageEntityBold, MessageEntityItalic, MessageEntityCode,
MessageEntityPre, MessageEntityTextUrl, MessageEntityMentionName,
MessageEntityStrike
)
from .. import _tl
DEFAULT_DELIMITERS = {
'**': MessageEntityBold,
'__': MessageEntityItalic,
'~~': MessageEntityStrike,
'`': MessageEntityCode,
'```': MessageEntityPre
'**': _tl.MessageEntityBold,
'__': _tl.MessageEntityItalic,
'~~': _tl.MessageEntityStrike,
'`': _tl.MessageEntityCode,
'```': _tl.MessageEntityPre
}
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):
"""
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 delimiters: the delimiters to be used, {delimiter: type}.
@ -98,13 +93,13 @@ def parse(message, delimiters=None, url_re=None):
# Append the found entity
ent = delimiters[delim]
if ent == MessageEntityPre:
if ent == _tl.MessageEntityPre:
result.append(ent(i, end - i - len(delim), '')) # has 'lang'
else:
result.append(ent(i, end - i - len(delim)))
# No nested entities inside code blocks
if ent in (MessageEntityCode, MessageEntityPre):
if ent in (_tl.MessageEntityCode, _tl.MessageEntityPre):
i = end - len(delim)
continue
@ -125,7 +120,7 @@ def parse(message, delimiters=None, url_re=None):
if ent.offset + ent.length > m.start():
ent.length -= delim_size
result.append(MessageEntityTextUrl(
result.append(_tl.MessageEntityTextUrl(
offset=m.start(), length=len(m.group(1)),
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):
"""
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 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.
"""
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:
warnings.warn('url_fmt is deprecated') # since it complicates everything *a lot*
if isinstance(entities, TLObject):
if isinstance(entities, _tl.TLObject):
entities = (entities,)
text = add_surrogate(text)
@ -173,9 +168,9 @@ def unparse(text, entities, delimiters=None, url_fmt=None):
insert_at.append((e, delimiter))
else:
url = None
if isinstance(entity, MessageEntityTextUrl):
if isinstance(entity, _tl.MessageEntityTextUrl):
url = entity.url
elif isinstance(entity, MessageEntityMentionName):
elif isinstance(entity, _tl.MessageEntityMentionName):
url = 'tg://user?id={}'.format(entity.user_id)
if url:
insert_at.append((s, '['))

View File

@ -2,7 +2,7 @@ import hashlib
import os
from .crypto import factorization
from .tl import types
from . import _tl
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)
def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
def compute_hash(algo: _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
password: str):
hash1 = sha256(algo.salt1, password.encode('utf-8'), algo.salt1)
hash2 = sha256(algo.salt2, hash1, algo.salt2)
@ -118,7 +118,7 @@ def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter1000
return sha256(algo.salt2, hash3, algo.salt2)
def compute_digest(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
def compute_digest(algo: _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
password: str):
try:
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
def compute_check(request: types.account.Password, password: str):
def compute_check(request: _tl.account.Password, password: str):
algo = request.current_algo
if not isinstance(algo, types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow):
if not isinstance(algo, _tl.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow):
raise ValueError('unsupported password algorithm {}'
.format(algo.__class__.__name__))
@ -190,5 +190,5 @@ def compute_check(request: types.account.Password, password: str):
K
)
return types.InputCheckPasswordSRP(
return _tl.InputCheckPasswordSRP(
request.srp_id, bytes(a_for_hash), bytes(M1))

View File

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

View File

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

View File

@ -6,17 +6,10 @@ import os
import time
from hashlib import sha1
from ..tl.types import (
ResPQ, PQInnerData, ServerDHParamsFail, ServerDHParamsOk,
ServerDHInnerData, ClientDHInnerData, DhGenOk, DhGenRetry, DhGenFail
)
from .. import helpers
from .. import helpers, _tl
from ..crypto import AES, AuthKey, Factorization, rsa
from ..errors import SecurityError
from ..extensions import BinaryReader
from ..tl.functions import (
ReqPqMultiRequest, ReqDHParamsRequest, SetClientDHParamsRequest
)
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
nonce = int.from_bytes(os.urandom(16), 'big', signed=True)
res_pq = await sender.send(ReqPqMultiRequest(nonce))
assert isinstance(res_pq, ResPQ), 'Step 1 answer was %s' % res_pq
res_pq = await sender.send(_tl.fn.ReqPqMulti(nonce))
assert isinstance(res_pq, _tl.ResPQ), 'Step 1 answer was %s' % res_pq
if res_pq.nonce != nonce:
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)
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,
nonce=res_pq.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,
server_nonce=res_pq.server_nonce,
p=p, q=q,
@ -81,7 +74,7 @@ async def do_authentication(sender):
))
assert isinstance(
server_dh_params, (ServerDHParamsOk, ServerDHParamsFail)),\
server_dh_params, (_tl.ServerDHParamsOk, _tl.ServerDHParamsFail)),\
'Step 2.1 answer was %s' % server_dh_params
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:
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(
sha1(new_nonce.to_bytes(32, 'little', signed=True)).digest()[4:20],
'little', signed=True
@ -98,7 +91,7 @@ async def do_authentication(sender):
if server_dh_params.new_nonce_hash != nnh:
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 3 sending: Complete DH Exchange
@ -116,7 +109,7 @@ async def do_authentication(sender):
with BinaryReader(plain_text_answer) as reader:
reader.read(20) # hash sum
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
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})')
# Prepare client DH Inner Data
client_dh_inner = bytes(ClientDHInnerData(
client_dh_inner = bytes(_tl.ClientDHInnerData(
nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce,
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)
# Prepare Set client DH params
dh_gen = await sender.send(SetClientDHParamsRequest(
dh_gen = await sender.send(_tl.fn.SetClientDHParams(
nonce=res_pq.nonce,
server_nonce=res_pq.server_nonce,
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
name = dh_gen.__class__.__name__
if dh_gen.nonce != res_pq.nonce:
@ -194,7 +187,7 @@ async def do_authentication(sender):
if dh_hash != 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)
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
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)
]))

View File

@ -1,8 +1,6 @@
import datetime
from .. import TLObject
from ..functions.messages import SaveDraftRequest
from ..types import DraftMessage
from ... import _tl
from ...errors import RPCError
from ...extensions import markdown
from ...utils import get_input_peer, get_peer
@ -30,8 +28,8 @@ class Draft:
self._entity = entity
self._input_entity = get_input_peer(entity) if entity else None
if not draft or not isinstance(draft, DraftMessage):
draft = DraftMessage('', None, None, None, None)
if not draft or not isinstance(draft, _tl.DraftMessage):
draft = _tl.DraftMessage('', None, None, None, None)
self._text = markdown.unparse(draft.message, draft.entities)
self._raw_text = draft.message
@ -134,7 +132,7 @@ class Draft:
raw_text, entities =\
await self._client._parse_message_text(text, parse_mode)
result = await self._client(SaveDraftRequest(
result = await self._client(_tl.fn.SaveDraftRequest(
peer=self._peer,
message=raw_text,
no_webpage=not link_preview,
@ -184,7 +182,7 @@ class Draft:
}
def __str__(self):
return TLObject.pretty_format(self.to_dict())
return _tl.TLObject.pretty_format(self.to_dict())
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):
fh = media
else:
r = await self._client(functions.messages.UploadMediaRequest(
r = await self._client(_tl.fn.messages.UploadMedia(
types.InputPeerSelf(), media=media
))
fh = utils.get_input_photo(r.photo)
@ -317,7 +317,7 @@ class InlineBuilder:
if isinstance(media, types.InputDocument):
fh = media
else:
r = await self._client(functions.messages.UploadMediaRequest(
r = await self._client(_tl.fn.messages.UploadMedia(
types.InputPeerSelf(), media=media
))
fh = utils.get_input_document(r.document)

View File

@ -150,7 +150,7 @@ class InlineResult:
else:
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,
query_id=self._query_id,
id=self.result.id,

View File

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

View File

@ -96,10 +96,10 @@ class MessageButton:
self._chat, self.button.text, parse_mode=None)
elif isinstance(self.button, types.KeyboardButtonCallback):
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)
req = functions.messages.GetBotCallbackAnswerRequest(
req = _tl.fn.messages.GetBotCallbackAnswer(
peer=self._chat, msg_id=self._msg_id, data=self.button.data,
password=password
)
@ -108,13 +108,13 @@ class MessageButton:
except BotResponseTimeoutError:
return None
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
))
elif isinstance(self.button, types.KeyboardButtonUrl):
return webbrowser.open(self.button.url)
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
)
try:

View File

@ -15,7 +15,7 @@ class QRLogin:
"""
def __init__(self, client, ignored_ids):
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._resp = None
@ -108,7 +108,7 @@ class QRLogin:
resp = await self._client(self._request)
if isinstance(resp, types.auth.LoginTokenMigrateTo):
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
if isinstance(resp, types.auth.LoginTokenSuccess):

View File

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

View File

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

View File

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

View File

@ -2,9 +2,7 @@ import re
import struct
from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils
from ..tl import types, functions
from ..tl.custom.sendergetter import SenderGetter
from .. import utils, _tl
@name_inner_event
@ -88,13 +86,13 @@ class CallbackQuery(EventBuilder):
@classmethod
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)
elif isinstance(update, types.UpdateInlineBotCallbackQuery):
elif isinstance(update, _tl.UpdateInlineBotCallbackQuery):
# See https://github.com/LonamiWebs/Telethon/pull/1005
# The long message ID is actually just msg_id + peer_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)
def filter(self, event):
@ -123,7 +121,7 @@ class CallbackQuery(EventBuilder):
return self.func(event)
return True
class Event(EventCommon, SenderGetter):
class Event(EventCommon, _tl.custom.sendergetter.SenderGetter):
"""
Represents the event of a new callback query.
@ -141,7 +139,7 @@ class CallbackQuery(EventBuilder):
"""
def __init__(self, query, peer, 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.data_match = None
self.pattern_match = None
@ -242,7 +240,7 @@ class CallbackQuery(EventBuilder):
self._answered = True
return await self._client(
functions.messages.SetBotCallbackAnswerRequest(
_tl.fn.messages.SetBotCallbackAnswerRequest(
query_id=self.query.query_id,
cache_time=cache_time,
alert=alert,
@ -264,7 +262,7 @@ class CallbackQuery(EventBuilder):
chat, so methods like `respond` or `delete` won't work (but
`edit` will always work).
"""
return isinstance(self.query, types.UpdateInlineBotCallbackQuery)
return isinstance(self.query, _tl.UpdateInlineBotCallbackQuery)
async def respond(self, *args, **kwargs):
"""
@ -312,7 +310,7 @@ class CallbackQuery(EventBuilder):
since the message object is normally not present.
"""
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(
self.query.msg_id, *args, **kwargs
)

View File

@ -1,6 +1,5 @@
from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils
from ..tl import types
from .. import utils, _tl
@name_inner_event
@ -36,23 +35,23 @@ class ChatAction(EventBuilder):
# Rely on specific pin updates for unpins, but otherwise ignore them
# for new pins (we'd rather handle the new service message with pin,
# so that we can act on that message').
if isinstance(update, types.UpdatePinnedChannelMessages) and not update.pinned:
return cls.Event(types.PeerChannel(update.channel_id),
if isinstance(update, _tl.UpdatePinnedChannelMessages) and not update.pinned:
return cls.Event(_tl.PeerChannel(update.channel_id),
pin_ids=update.messages,
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,
pin_ids=update.messages,
pin=update.pinned)
elif isinstance(update, types.UpdateChatParticipantAdd):
return cls.Event(types.PeerChat(update.chat_id),
elif isinstance(update, _tl.UpdateChatParticipantAdd):
return cls.Event(_tl.PeerChat(update.chat_id),
added_by=update.inviter_id or True,
users=update.user_id)
elif isinstance(update, types.UpdateChatParticipantDelete):
return cls.Event(types.PeerChat(update.chat_id),
elif isinstance(update, _tl.UpdateChatParticipantDelete):
return cls.Event(_tl.PeerChat(update.chat_id),
kicked_by=True,
users=update.user_id)
@ -61,50 +60,50 @@ class ChatAction(EventBuilder):
# better not to rely on this. Rely only in MessageActionChatDeleteUser.
elif (isinstance(update, (
types.UpdateNewMessage, types.UpdateNewChannelMessage))
and isinstance(update.message, types.MessageService)):
_tl.UpdateNewMessage, _tl.UpdateNewChannelMessage))
and isinstance(update.message, _tl.MessageService)):
msg = update.message
action = update.message.action
if isinstance(action, types.MessageActionChatJoinedByLink):
if isinstance(action, _tl.MessageActionChatJoinedByLink):
return cls.Event(msg,
added_by=True,
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
added_by = ([msg.sender_id] == action.users) or msg.from_id
return cls.Event(msg,
added_by=added_by,
users=action.users)
elif isinstance(action, types.MessageActionChatDeleteUser):
elif isinstance(action, _tl.MessageActionChatDeleteUser):
return cls.Event(msg,
kicked_by=utils.get_peer_id(msg.from_id) if msg.from_id else True,
users=action.user_id)
elif isinstance(action, types.MessageActionChatCreate):
elif isinstance(action, _tl.MessageActionChatCreate):
return cls.Event(msg,
users=action.users,
created=True,
new_title=action.title)
elif isinstance(action, types.MessageActionChannelCreate):
elif isinstance(action, _tl.MessageActionChannelCreate):
return cls.Event(msg,
created=True,
users=msg.from_id,
new_title=action.title)
elif isinstance(action, types.MessageActionChatEditTitle):
elif isinstance(action, _tl.MessageActionChatEditTitle):
return cls.Event(msg,
users=msg.from_id,
new_title=action.title)
elif isinstance(action, types.MessageActionChatEditPhoto):
elif isinstance(action, _tl.MessageActionChatEditPhoto):
return cls.Event(msg,
users=msg.from_id,
new_photo=action.photo)
elif isinstance(action, types.MessageActionChatDeletePhoto):
elif isinstance(action, _tl.MessageActionChatDeletePhoto):
return cls.Event(msg,
users=msg.from_id,
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,
pin_ids=[msg.reply_to_msg_id])
elif isinstance(action, types.MessageActionGameScore):
elif isinstance(action, _tl.MessageActionGameScore):
return cls.Event(msg,
new_score=action.score)
@ -142,7 +141,7 @@ class ChatAction(EventBuilder):
new_title (`str`, optional):
The new title string for the chat, if applicable.
new_score (`str`, optional):
The new score string for the game, if applicable.
@ -153,7 +152,7 @@ class ChatAction(EventBuilder):
def __init__(self, where, new_photo=None,
added_by=None, kicked_by=None, created=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
where = where.peer_id
else:
@ -169,7 +168,7 @@ class ChatAction(EventBuilder):
self.new_photo = new_photo is not None
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._kicked_by = None
@ -283,7 +282,7 @@ class ChatAction(EventBuilder):
"""
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))
if aby:
self._added_by = aby
@ -304,7 +303,7 @@ class ChatAction(EventBuilder):
"""
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))
if kby:
self._kicked_by = kby
@ -393,7 +392,7 @@ class ChatAction(EventBuilder):
await self.action_message._reload_message()
self._users = [
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
@ -433,7 +432,7 @@ class ChatAction(EventBuilder):
self._input_users = [
utils.get_input_peer(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._input_users or []

View File

@ -2,9 +2,7 @@ import abc
import asyncio
import warnings
from .. import utils
from ..tl import TLObject, types
from ..tl.custom.chatgetter import ChatGetter
from .. import utils, _tl
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
else:
result.update({ # Support all valid types of peers
utils.get_peer_id(types.PeerUser(chat)),
utils.get_peer_id(types.PeerChat(chat)),
utils.get_peer_id(types.PeerChannel(chat)),
utils.get_peer_id(_tl.PeerUser(chat)),
utils.get_peer_id(_tl.PeerChat(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')
result.add(utils.get_peer_id(chat))
else:
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)
result.add(utils.get_peer_id(chat))
@ -166,10 +164,10 @@ class EventCommon(ChatGetter, abc.ABC):
return self._client
def __str__(self):
return TLObject.pretty_format(self.to_dict())
return _tl.TLObject.pretty_format(self.to_dict())
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):
d = {k: v for k, v in self.__dict__.items() if k[0] != '_'}

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
from .common import EventBuilder, EventCommon, name_inner_event
from .. import utils
from ..tl import types
from .. import utils, _tl
@name_inner_event
@ -36,21 +35,21 @@ class MessageRead(EventBuilder):
@classmethod
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)
elif isinstance(update, types.UpdateReadHistoryOutbox):
elif isinstance(update, _tl.UpdateReadHistoryOutbox):
return cls.Event(update.peer, update.max_id, True)
elif isinstance(update, types.UpdateReadChannelInbox):
return cls.Event(types.PeerChannel(update.channel_id),
elif isinstance(update, _tl.UpdateReadChannelInbox):
return cls.Event(_tl.PeerChannel(update.channel_id),
update.max_id, False)
elif isinstance(update, types.UpdateReadChannelOutbox):
return cls.Event(types.PeerChannel(update.channel_id),
elif isinstance(update, _tl.UpdateReadChannelOutbox):
return cls.Event(_tl.PeerChannel(update.channel_id),
update.max_id, True)
elif isinstance(update, types.UpdateReadMessagesContents):
elif isinstance(update, _tl.UpdateReadMessagesContents):
return cls.Event(message_ids=update.messages,
contents=True)
elif isinstance(update, types.UpdateChannelReadMessagesContents):
return cls.Event(types.PeerChannel(update.channel_id),
elif isinstance(update, _tl.UpdateChannelReadMessagesContents):
return cls.Event(_tl.PeerChannel(update.channel_id),
message_ids=update.messages,
contents=True)

View File

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

View File

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

View File

@ -1,13 +1,7 @@
from enum import Enum
from .abstract import Session
from .. import utils
from ..tl import TLObject
from ..tl.types import (
PeerUser, PeerChat, PeerChannel,
InputPeerUser, InputPeerChat, InputPeerChannel,
InputPhoto, InputDocument
)
from .. import utils, _tl
class _SentFileType(Enum):
@ -16,9 +10,9 @@ class _SentFileType(Enum):
@staticmethod
def from_type(cls):
if cls == InputDocument:
if cls == _tl.InputDocument:
return _SentFileType.DOCUMENT
elif cls == InputPhoto:
elif cls == _tl.InputPhoto:
return _SentFileType.PHOTO
else:
raise ValueError('The cls must be either InputDocument/InputPhoto')
@ -94,7 +88,7 @@ class MemorySession(Session):
return id, hash, username, phone, name
def _entity_to_row(self, e):
if not isinstance(e, TLObject):
if not isinstance(e, _tl.TLObject):
return
try:
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).
return
if isinstance(p, (InputPeerUser, InputPeerChannel)):
if isinstance(p, (_tl.InputPeerUser, _tl.InputPeerChannel)):
p_hash = p.access_hash
elif isinstance(p, InputPeerChat):
elif isinstance(p, _tl.InputPeerChat):
p_hash = 0
else:
return
@ -123,7 +117,7 @@ class MemorySession(Session):
)
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
entities = tlo
else:
@ -175,9 +169,9 @@ class MemorySession(Session):
in self._entities if found_id == id)
else:
ids = (
utils.get_peer_id(PeerUser(id)),
utils.get_peer_id(PeerChat(id)),
utils.get_peer_id(PeerChannel(id))
utils.get_peer_id(_tl.PeerUser(id)),
utils.get_peer_id(_tl.PeerChat(id)),
utils.get_peer_id(_tl.PeerChannel(id))
)
return next((id, hash) for found_id, hash, _, _, _
in self._entities if found_id in ids)
@ -194,7 +188,7 @@ class MemorySession(Session):
return utils.get_input_peer(key)
except (AttributeError, TypeError):
# 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)
exact = True
else:
@ -224,17 +218,17 @@ class MemorySession(Session):
entity_id, entity_hash = result # unpack resulting tuple
entity_id, kind = utils.resolve_id(entity_id)
# removes the mark and returns type of entity
if kind == PeerUser:
return InputPeerUser(entity_id, entity_hash)
elif kind == PeerChat:
return InputPeerChat(entity_id)
elif kind == PeerChannel:
return InputPeerChannel(entity_id, entity_hash)
if kind == _tl.PeerUser:
return _tl.InputPeerUser(entity_id, entity_hash)
elif kind == _tl.PeerChat:
return _tl.InputPeerChat(entity_id)
elif kind == _tl.PeerChannel:
return _tl.InputPeerChannel(entity_id, entity_hash)
else:
raise ValueError('Could not find input entity with key ', key)
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))
key = (md5_digest, file_size, _SentFileType.from_type(type(instance)))
value = (instance.id, instance.access_hash)

View File

@ -2,13 +2,9 @@ import datetime
import os
import time
from telethon.tl import types
from .memory import MemorySession, _SentFileType
from .. import utils
from .. import utils, _tl
from ..crypto import AuthKey
from ..tl.types import (
InputPhoto, InputDocument, PeerUser, PeerChat, PeerChannel
)
try:
import sqlite3
@ -208,7 +204,7 @@ class SQLiteSession(MemorySession):
pts, qts, date, seq = row
date = datetime.datetime.fromtimestamp(
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):
self._execute('insert or replace into update_state values (?,?,?,?,?)',
@ -325,9 +321,9 @@ class SQLiteSession(MemorySession):
else:
return self._execute(
'select id, hash from entities where id in (?,?,?)',
utils.get_peer_id(PeerUser(id)),
utils.get_peer_id(PeerChat(id)),
utils.get_peer_id(PeerChannel(id))
utils.get_peer_id(_tl.PeerUser(id)),
utils.get_peer_id(_tl.PeerChat(id)),
utils.get_peer_id(_tl.PeerChannel(id))
)
# File processing
@ -343,7 +339,7 @@ class SQLiteSession(MemorySession):
return cls(row[0], row[1])
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))
self._execute(

View File

@ -695,9 +695,9 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir):
namespace_types[tlobject.namespace].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)
_write_modules(output_dir / 'types', import_depth, 'TLObject',
_write_modules(output_dir, import_depth - 1, 'TLObject',
namespace_types, type_constructors)
filename = output_dir / 'alltlobjects.py'

View File

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

View File

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