Skip to content

Commit

Permalink
Reduce autocast overhead as much as possible
Browse files Browse the repository at this point in the history
Rationale: if the user is doing things right, the penalty for
being friendly (i.e. autocasting to the right version, like
User -> InputPeerUser), should be as little as possible.

Removing the redundant type() call to access .SUBCLASS_OF_ID
and assuming the user provided a TLObject (through excepting
whenever the attribute is not available) is x2 and x4 times
faster respectively.

Of course, this is a micro-optimization, but I still consider
it's good to benefit users doing things right or avoiding
redundant calls.
  • Loading branch information
Lonami committed Jan 19, 2018
1 parent 33e50aa commit e3c56b0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 54 deletions.
32 changes: 19 additions & 13 deletions telethon/telegram_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -818,10 +818,12 @@ def _get_reply_to(reply_to):
if isinstance(reply_to, int):
return reply_to

if isinstance(reply_to, TLObject) and \
type(reply_to).SUBCLASS_OF_ID == 0x790009e3:
# hex(crc32(b'Message')) = 0x790009e3
return reply_to.id
try:
if reply_to.SUBCLASS_OF_ID == 0x790009e3:
# hex(crc32(b'Message')) = 0x790009e3
return reply_to.id
except AttributeError:
pass

raise TypeError('Invalid reply_to type: {}'.format(type(reply_to)))

Expand Down Expand Up @@ -1191,9 +1193,14 @@ def download_profile_photo(self, entity, file=None, download_big=True):
"""
photo = entity
possible_names = []
if not isinstance(entity, TLObject) or type(entity).SUBCLASS_OF_ID in (
try:
is_entity = entity.SUBCLASS_OF_ID in (
0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697
):
)
except AttributeError:
return None # Not even a TLObject as attribute access failed

if is_entity:
# Maybe it is an user or a chat? Or their full versions?
#
# The hexadecimal numbers above are simply:
Expand Down Expand Up @@ -1705,14 +1712,13 @@ def get_input_entity(self, peer):
if isinstance(peer, int):
peer = PeerUser(peer)
is_peer = True

elif isinstance(peer, TLObject):
is_peer = type(peer).SUBCLASS_OF_ID == 0x2d45687 # crc32(b'Peer')
if not is_peer:
try:
else:
try:
is_peer = peer.SUBCLASS_OF_ID == 0x2d45687 # crc32(b'Peer')
if not is_peer:
return utils.get_input_peer(peer)
except TypeError:
pass
except (AttributeError, TypeError):
pass # Attribute if not TLObject, Type if not "casteable"

if not is_peer:
raise TypeError(
Expand Down
79 changes: 38 additions & 41 deletions telethon/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
to convert between an entity like an User, Chat, etc. into its Input version)
"""
import math
from mimetypes import add_type, guess_extension

import re
from mimetypes import add_type, guess_extension

from .tl import TLObject
from .tl.types import (
Channel, ChannelForbidden, Chat, ChatEmpty, ChatForbidden, ChatFull,
ChatPhoto, InputPeerChannel, InputPeerChat, InputPeerUser, InputPeerEmpty,
Expand All @@ -25,7 +23,6 @@
InputMediaUploadedPhoto, DocumentAttributeFilename, photos
)


USERNAME_RE = re.compile(
r'@|(?:https?://)?(?:telegram\.(?:me|dog)|t\.me)/(joinchat/)?'
)
Expand Down Expand Up @@ -81,12 +78,12 @@ def _raise_cast_fail(entity, target):
def get_input_peer(entity, allow_self=True):
"""Gets the input peer for the given "entity" (user, chat or channel).
A TypeError is raised if the given entity isn't a supported type."""
if not isinstance(entity, TLObject):
try:
if entity.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
return entity
except AttributeError:
_raise_cast_fail(entity, 'InputPeer')

if type(entity).SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
return entity

if isinstance(entity, User):
if entity.is_self and allow_self:
return InputPeerSelf()
Expand Down Expand Up @@ -123,12 +120,12 @@ def get_input_peer(entity, allow_self=True):

def get_input_channel(entity):
"""Similar to get_input_peer, but for InputChannel's alone"""
if not isinstance(entity, TLObject):
try:
if entity.SUBCLASS_OF_ID == 0x40f202fd: # crc32(b'InputChannel')
return entity
except AttributeError:
_raise_cast_fail(entity, 'InputChannel')

if type(entity).SUBCLASS_OF_ID == 0x40f202fd: # crc32(b'InputChannel')
return entity

if isinstance(entity, (Channel, ChannelForbidden)):
return InputChannel(entity.id, entity.access_hash or 0)

Expand All @@ -140,12 +137,12 @@ def get_input_channel(entity):

def get_input_user(entity):
"""Similar to get_input_peer, but for InputUser's alone"""
if not isinstance(entity, TLObject):
try:
if entity.SUBCLASS_OF_ID == 0xe669bf46: # crc32(b'InputUser'):
return entity
except AttributeError:
_raise_cast_fail(entity, 'InputUser')

if type(entity).SUBCLASS_OF_ID == 0xe669bf46: # crc32(b'InputUser')
return entity

if isinstance(entity, User):
if entity.is_self:
return InputUserSelf()
Expand All @@ -169,12 +166,12 @@ def get_input_user(entity):

def get_input_document(document):
"""Similar to get_input_peer, but for documents"""
if not isinstance(document, TLObject):
try:
if document.SUBCLASS_OF_ID == 0xf33fdb68: # crc32(b'InputDocument'):
return document
except AttributeError:
_raise_cast_fail(document, 'InputDocument')

if type(document).SUBCLASS_OF_ID == 0xf33fdb68: # crc32(b'InputDocument')
return document

if isinstance(document, Document):
return InputDocument(id=document.id, access_hash=document.access_hash)

Expand All @@ -192,12 +189,12 @@ def get_input_document(document):

def get_input_photo(photo):
"""Similar to get_input_peer, but for documents"""
if not isinstance(photo, TLObject):
try:
if photo.SUBCLASS_OF_ID == 0x846363e0: # crc32(b'InputPhoto'):
return photo
except AttributeError:
_raise_cast_fail(photo, 'InputPhoto')

if type(photo).SUBCLASS_OF_ID == 0x846363e0: # crc32(b'InputPhoto')
return photo

if isinstance(photo, photos.Photo):
photo = photo.photo

Expand All @@ -212,12 +209,12 @@ def get_input_photo(photo):

def get_input_geo(geo):
"""Similar to get_input_peer, but for geo points"""
if not isinstance(geo, TLObject):
try:
if geo.SUBCLASS_OF_ID == 0x430d225: # crc32(b'InputGeoPoint'):
return geo
except AttributeError:
_raise_cast_fail(geo, 'InputGeoPoint')

if type(geo).SUBCLASS_OF_ID == 0x430d225: # crc32(b'InputGeoPoint')
return geo

if isinstance(geo, GeoPoint):
return InputGeoPoint(lat=geo.lat, long=geo.long)

Expand All @@ -239,12 +236,12 @@ def get_input_media(media, user_caption=None, is_photo=False):
If the media is a file location and is_photo is known to be True,
it will be treated as an InputMediaUploadedPhoto.
"""
if not isinstance(media, TLObject):
try:
if media.SUBCLASS_OF_ID == 0xfaf846f4: # crc32(b'InputMedia'):
return media
except AttributeError:
_raise_cast_fail(media, 'InputMedia')

if type(media).SUBCLASS_OF_ID == 0xfaf846f4: # crc32(b'InputMedia')
return media

if isinstance(media, MessageMediaPhoto):
return InputMediaPhoto(
id=get_input_photo(media.photo),
Expand Down Expand Up @@ -357,15 +354,15 @@ def get_peer_id(peer):
a call to utils.resolve_id(marked_id).
"""
# First we assert it's a Peer TLObject, or early return for integers
if not isinstance(peer, TLObject):
if isinstance(peer, int):
return peer
else:
_raise_cast_fail(peer, 'int')

elif type(peer).SUBCLASS_OF_ID not in {0x2d45687, 0xc91c90b6}:
# Not a Peer or an InputPeer, so first get its Input version
peer = get_input_peer(peer, allow_self=False)
if isinstance(peer, int):
return peer

try:
if peer.SUBCLASS_OF_ID not in (0x2d45687, 0xc91c90b6):
# Not a Peer or an InputPeer, so first get its Input version
peer = get_input_peer(peer, allow_self=False)
except AttributeError:
_raise_cast_fail(peer, 'int')

# Set the right ID/kind, or raise if the TLObject is not recognised
if isinstance(peer, (PeerUser, InputPeerUser)):
Expand Down

0 comments on commit e3c56b0

Please sign in to comment.