Merge pull request #1 from muhammedfurkan/sourcery/master

Sourcery refactored master branch
This commit is contained in:
M.Furkan 2020-10-11 18:42:13 +03:00 committed by GitHub
commit ea71213b02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 160 additions and 210 deletions

View File

@ -22,10 +22,9 @@ def make_link_node(rawtext, app, name, options):
base += '/' base += '/'
set_classes(options) set_classes(options)
node = nodes.reference(rawtext, utils.unescape(name), return nodes.reference(rawtext, utils.unescape(name),
refuri='{}?q={}'.format(base, name), refuri='{}?q={}'.format(base, name),
**options) **options)
return node
# noinspection PyUnusedLocal # noinspection PyUnusedLocal

View File

@ -109,11 +109,8 @@ class _DraftsIter(RequestIter):
r = await self.client(functions.messages.GetAllDraftsRequest()) r = await self.client(functions.messages.GetAllDraftsRequest())
items = r.updates items = r.updates
else: else:
peers = [] peers = [types.InputDialogPeer(
for entity in entities: await self.client.get_input_entity(entity)) for entity in entities]
peers.append(types.InputDialogPeer(
await self.client.get_input_entity(entity)))
r = await self.client(functions.messages.GetPeerDialogsRequest(peers)) r = await self.client(functions.messages.GetPeerDialogsRequest(peers))
items = r.dialogs items = r.dialogs
@ -437,11 +434,7 @@ class DialogMethods:
""" """
# If we have enough information (`Dialog.delete` gives it to us), # If we have enough information (`Dialog.delete` gives it to us),
# then we know we don't have to kick ourselves in deactivated chats. # then we know we don't have to kick ourselves in deactivated chats.
if isinstance(entity, types.Chat): deactivated = entity.deactivated if isinstance(entity, types.Chat) else False
deactivated = entity.deactivated
else:
deactivated = False
entity = await self.get_input_entity(entity) entity = await self.get_input_entity(entity)
ty = helpers._entity_type(entity) ty = helpers._entity_type(entity)
if ty == helpers._EntityType.CHANNEL: if ty == helpers._EntityType.CHANNEL:

View File

@ -385,9 +385,10 @@ class DownloadMethods:
if isinstance(media, str): if isinstance(media, str):
media = utils.resolve_bot_file_id(media) media = utils.resolve_bot_file_id(media)
if isinstance(media, types.MessageMediaWebPage): if isinstance(media, types.MessageMediaWebPage) and isinstance(
if isinstance(media.webpage, types.WebPage): media.webpage, types.WebPage
media = media.webpage.document or media.webpage.photo ):
media = media.webpage.document or media.webpage.photo
if isinstance(media, (types.MessageMediaPhoto, types.Photo)): if isinstance(media, (types.MessageMediaPhoto, types.Photo)):
return await self._download_photo( return await self._download_photo(

View File

@ -521,11 +521,7 @@ class MessageMethods:
message_1337 = await client.get_messages(chat, ids=1337) message_1337 = await client.get_messages(chat, ids=1337)
""" """
if len(args) == 1 and 'limit' not in kwargs: if len(args) == 1 and 'limit' not in kwargs:
if 'min_id' in kwargs and 'max_id' in kwargs: kwargs['limit'] = None if 'min_id' in kwargs and 'max_id' in kwargs else 1
kwargs['limit'] = None
else:
kwargs['limit'] = 1
it = self.iter_messages(*args, **kwargs) it = self.iter_messages(*args, **kwargs)
ids = kwargs.get('ids') ids = kwargs.get('ids')
@ -1045,8 +1041,7 @@ class MessageMethods:
reply_markup=self.build_reply_markup(buttons), reply_markup=self.build_reply_markup(buttons),
schedule_date=schedule schedule_date=schedule
) )
msg = self._get_response_message(request, await self(request), entity) return self._get_response_message(request, await self(request), entity)
return msg
async def delete_messages( async def delete_messages(
self: 'TelegramClient', self: 'TelegramClient',

View File

@ -311,18 +311,14 @@ class UploadMethods:
# we may want to send as an album if all are photo files. # we may want to send as an album if all are photo files.
if utils.is_list_like(file): if utils.is_list_like(file):
media_captions = [] media_captions = []
document_captions = [] captions = caption if utils.is_list_like(caption) else [caption]
if utils.is_list_like(caption):
captions = caption
else:
captions = [caption]
# TODO Fix progress_callback # TODO Fix progress_callback
media = [] media = []
if force_document: if force_document:
documents = file documents = file
else: else:
documents = [] documents = []
document_captions = []
for doc, cap in itertools.zip_longest(file, captions): for doc, cap in itertools.zip_longest(file, captions):
if utils.is_image(doc) or utils.is_video(doc): if utils.is_image(doc) or utils.is_video(doc):
media.append(doc) media.append(doc)

View File

@ -86,7 +86,9 @@ class UserMethods:
last_error = e last_error = e
self._log[__name__].warning( self._log[__name__].warning(
'Telegram is having internal issues %s: %s', 'Telegram is having internal issues %s: %s',
e.__class__.__name__, e) last_error.__class__.__name__,
last_error,
)
await asyncio.sleep(2) await asyncio.sleep(2)
except (errors.FloodWaitError, errors.SlowModeWaitError, errors.FloodTestPhoneWaitError) as e: except (errors.FloodWaitError, errors.SlowModeWaitError, errors.FloodTestPhoneWaitError) as e:

View File

@ -27,13 +27,13 @@ class Factorization:
while g == 1: while g == 1:
x = y x = y
for i in range(r): for _ in range(r):
y = (pow(y, 2, pq) + c) % pq y = (pow(y, 2, pq) + c) % pq
k = 0 k = 0
while k < r and g == 1: while k < r and g == 1:
ys = y ys = y
for i in range(min(m, r - k)): for _ in range(min(m, r - k)):
y = (pow(y, 2, pq) + c) % pq y = (pow(y, 2, pq) + c) % pq
q = q * (abs(x - y)) % pq q = q * (abs(x - y)) % pq

View File

@ -67,10 +67,10 @@ class CallbackQuery(EventBuilder):
if isinstance(pattern, str): if isinstance(pattern, str):
pattern = pattern.encode('utf-8') pattern = pattern.encode('utf-8')
match = data if data else pattern match = data or pattern
if isinstance(match, bytes): if isinstance(match, bytes):
self.match = data if data else re.compile(pattern).match self.match = data or re.compile(pattern).match
elif not match or callable(match): elif not match or callable(match):
self.match = match self.match = match
elif hasattr(match, 'match') and callable(match.match): elif hasattr(match, 'match') and callable(match.match):

View File

@ -95,9 +95,8 @@ class EventBuilder(abc.ABC):
self._resolve_lock = asyncio.Lock() self._resolve_lock = asyncio.Lock()
async with self._resolve_lock: async with self._resolve_lock:
if not self.resolved: await self._resolve(client)
await self._resolve(client) self.resolved = True
self.resolved = True
async def _resolve(self, client): async def _resolve(self, client):
self.chats = await _into_id_set(client, self.chats) self.chats = await _into_id_set(client, self.chats)

View File

@ -151,13 +151,16 @@ class NewMessage(EventBuilder):
return return
if self.outgoing and not event.message.out: if self.outgoing and not event.message.out:
return return
if self.forwards is not None: if self.forwards is not None and bool(self.forwards) != bool(
if bool(self.forwards) != bool(event.message.fwd_from): event.message.fwd_from
return ):
return
if self.from_users is not None: if (
if event.message.sender_id not in self.from_users: self.from_users is not None
return and event.message.sender_id not in self.from_users
):
return
if self.pattern: if self.pattern:
match = self.pattern(event.message.message or '') match = self.pattern(event.message.message or '')

View File

@ -131,19 +131,19 @@ class BinaryReader:
return [self.tgread_object() for _ in range(self.read_int())] return [self.tgread_object() for _ in range(self.read_int())]
clazz = core_objects.get(constructor_id, None) clazz = core_objects.get(constructor_id, None)
if clazz is None: if clazz is None:
# If there was still no luck, give up # If there was still no luck, give up
self.seek(-4) # Go back self.seek(-4) # Go back
pos = self.tell_position() pos = self.tell_position()
error = TypeNotFoundError(constructor_id, self.read()) error = TypeNotFoundError(constructor_id, self.read())
self.set_position(pos) self.set_position(pos)
raise error raise error
return clazz.from_reader(self) return clazz.from_reader(self)
def tgread_vector(self): def tgread_vector(self):
"""Reads a vector (a list) of Telegram objects.""" """Reads a vector (a list) of Telegram objects."""
if 0x1cb5c415 != self.read_int(signed=False): if self.read_int(signed=False) != 0x1CB5C415:
raise RuntimeError('Invalid constructor code, vector was expected') raise RuntimeError('Invalid constructor code, vector was expected')
count = self.read_int() count = self.read_int()

View File

@ -45,13 +45,13 @@ class HTMLToTelegramParser(HTMLParser):
attrs = dict(attrs) attrs = dict(attrs)
EntityType = None EntityType = None
args = {} args = {}
if tag == 'strong' or tag == 'b': if tag in ['strong', 'b']:
EntityType = MessageEntityBold EntityType = MessageEntityBold
elif tag == 'em' or tag == 'i': elif tag in ['em', 'i']:
EntityType = MessageEntityItalic EntityType = MessageEntityItalic
elif tag == 'u': elif tag == 'u':
EntityType = MessageEntityUnderline EntityType = MessageEntityUnderline
elif tag == 'del' or tag == 's': elif tag in ['del', 's']:
EntityType = MessageEntityStrike EntityType = MessageEntityStrike
elif tag == 'blockquote': elif tag == 'blockquote':
EntityType = MessageEntityBlockquote EntityType = MessageEntityBlockquote

View File

@ -91,11 +91,7 @@ def parse(message, delimiters=None, url_re=None):
# If the end is after our start, it is affected # If the end is after our start, it is affected
if ent.offset + ent.length > i: if ent.offset + ent.length > i:
# If the old start is also before ours, it is fully enclosed # If the old start is also before ours, it is fully enclosed
if ent.offset <= i: ent.length -= len(delim) * 2 if ent.offset <= i else len(delim)
ent.length -= len(delim) * 2
else:
ent.length -= len(delim)
# Append the found entity # Append the found entity
ent = delimiters[delim] ent = delimiters[delim]
if ent == MessageEntityPre: if ent == MessageEntityPre:

View File

@ -111,7 +111,7 @@ def retry_range(retries, force_retry=True):
# We need at least one iteration even if the retries are 0 # We need at least one iteration even if the retries are 0
# when force_retry is True. # when force_retry is True.
if force_retry and not (retries is None or retries < 0): if force_retry and retries is not None and retries >= 0:
retries += 1 retries += 1
attempt = 0 attempt = 0
@ -170,11 +170,7 @@ def _sync_enter(self):
Helps to cut boilerplate on async context Helps to cut boilerplate on async context
managers that offer synchronous variants. managers that offer synchronous variants.
""" """
if hasattr(self, 'loop'): loop = self.loop if hasattr(self, 'loop') else self._client.loop
loop = self.loop
else:
loop = self._client.loop
if loop.is_running(): if loop.is_running():
raise RuntimeError( raise RuntimeError(
'You must use "async with" if the event loop ' 'You must use "async with" if the event loop '
@ -185,11 +181,7 @@ def _sync_enter(self):
def _sync_exit(self, *args): def _sync_exit(self, *args):
if hasattr(self, 'loop'): loop = self.loop if hasattr(self, 'loop') else self._client.loop
loop = self.loop
else:
loop = self._client.loop
return loop.run_until_complete(self.__aexit__(*args)) return loop.run_until_complete(self.__aexit__(*args))

View File

@ -47,11 +47,7 @@ class Connection(abc.ABC):
async def _connect(self, timeout=None, ssl=None): async def _connect(self, timeout=None, ssl=None):
if not self._proxy: if not self._proxy:
if self._local_addr is not None: local_addr = (self._local_addr, None) if self._local_addr is not None else None
local_addr = (self._local_addr, None)
else:
local_addr = None
self._reader, self._writer = await asyncio.wait_for( self._reader, self._writer = await asyncio.wait_for(
asyncio.open_connection(self._ip, self._port, ssl=ssl, local_addr=local_addr), asyncio.open_connection(self._ip, self._port, ssl=ssl, local_addr=local_addr),
timeout=timeout timeout=timeout
@ -89,7 +85,7 @@ class Connection(abc.ABC):
ssl_version=ssl_mod.PROTOCOL_SSLv23, ssl_version=ssl_mod.PROTOCOL_SSLv23,
ciphers='ADH-AES256-SHA' ciphers='ADH-AES256-SHA'
) )
s.setblocking(False) s.setblocking(False)
self._reader, self._writer = await asyncio.open_connection(sock=s) self._reader, self._writer = await asyncio.open_connection(sock=s)

View File

@ -44,8 +44,8 @@ class MTProxyIO:
# Obfuscated messages secrets cannot start with any of these # Obfuscated messages secrets cannot start with any of these
keywords = (b'PVrG', b'GET ', b'POST', b'\xee\xee\xee\xee') keywords = (b'PVrG', b'GET ', b'POST', b'\xee\xee\xee\xee')
random = os.urandom(64)
while True: while True:
random = os.urandom(64)
if (random[0] != 0xef and if (random[0] != 0xef and
random[:4] not in keywords and random[:4] not in keywords and
random[4:4] != b'\0\0\0\0'): random[4:4] != b'\0\0\0\0'):

View File

@ -21,8 +21,8 @@ class ObfuscatedIO:
def init_header(packet_codec): def init_header(packet_codec):
# Obfuscated messages secrets cannot start with any of these # Obfuscated messages secrets cannot start with any of these
keywords = (b'PVrG', b'GET ', b'POST', b'\xee\xee\xee\xee') keywords = (b'PVrG', b'GET ', b'POST', b'\xee\xee\xee\xee')
random = os.urandom(64)
while True: while True:
random = os.urandom(64)
if (random[0] != 0xef and if (random[0] != 0xef and
random[:4] not in keywords and random[:4] not in keywords and
random[4:8] != b'\0\0\0\0'): random[4:8] != b'\0\0\0\0'):

View File

@ -358,7 +358,7 @@ class MTProtoSender:
self._state.reset() self._state.reset()
retries = self._retries if self._auto_reconnect else 0 retries = self._retries if self._auto_reconnect else 0
attempt = 0 attempt = 0
ok = True ok = True
# We're already "retrying" to connect, so we don't want to force retries # We're already "retrying" to connect, so we don't want to force retries
@ -367,8 +367,12 @@ class MTProtoSender:
await self._connect() await self._connect()
except (IOError, asyncio.TimeoutError) as e: except (IOError, asyncio.TimeoutError) as e:
last_error = e last_error = e
self._log.info('Failed reconnection attempt %d with %s', self._log.info(
attempt, e.__class__.__name__) 'Failed reconnection attempt %d with %s',
attempt,
last_error.__class__.__name__,
)
await asyncio.sleep(self._delay) await asyncio.sleep(self._delay)
except BufferError as e: except BufferError as e:
# TODO there should probably only be one place to except all these errors # TODO there should probably only be one place to except all these errors
@ -546,10 +550,11 @@ class MTProtoSender:
if state: if state:
return [state] return [state]
to_pop = [] to_pop = [
for state in self._pending_state.values(): state.msg_id
if state.container_id == msg_id: for state in self._pending_state.values()
to_pop.append(state.msg_id) if state.container_id == msg_id
]
if to_pop: if to_pop:
return [self._pending_state.pop(x) for x in to_pop] return [self._pending_state.pop(x) for x in to_pop]

View File

@ -61,9 +61,8 @@ def check_prime_and_good(prime_bytes: bytes, g: int):
0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE, 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF, 0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE, 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03, 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B)) 0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03, 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B))
if good_prime == prime_bytes: if good_prime == prime_bytes and g in (3, 4, 5, 7):
if g in (3, 4, 5, 7): return # It's good
return # It's good
check_prime_and_good_check(int.from_bytes(prime_bytes, 'big'), g) check_prime_and_good_check(int.from_bytes(prime_bytes, 'big'), g)
@ -94,12 +93,12 @@ def is_good_mod_exp_first(modexp, prime) -> bool:
diff = prime - modexp diff = prime - modexp
min_diff_bits_count = 2048 - 64 min_diff_bits_count = 2048 - 64
max_mod_exp_size = 256 max_mod_exp_size = 256
if diff < 0 or \ return (
diff.bit_length() < min_diff_bits_count or \ diff >= 0
modexp.bit_length() < min_diff_bits_count or \ and diff.bit_length() >= min_diff_bits_count
(modexp.bit_length() + 7) // 8 > max_mod_exp_size: and modexp.bit_length() >= min_diff_bits_count
return False and (modexp.bit_length() + 7) // 8 <= max_mod_exp_size
return True )
def xor(a: bytes, b: bytes) -> bytes: def xor(a: bytes, b: bytes) -> bytes:

View File

@ -169,10 +169,7 @@ class SQLiteSession(MemorySession):
# Fetch the auth_key corresponding to this data center # Fetch the auth_key corresponding to this data center
row = self._execute('select auth_key from sessions') row = self._execute('select auth_key from sessions')
if row and row[0]: self._auth_key = AuthKey(data=row[0]) if row and row[0] else None
self._auth_key = AuthKey(data=row[0])
else:
self._auth_key = None
@MemorySession.auth_key.setter @MemorySession.auth_key.setter
def auth_key(self, value): def auth_key(self, value):
@ -242,11 +239,10 @@ class SQLiteSession(MemorySession):
def close(self): def close(self):
"""Closes the connection unless we're working in-memory""" """Closes the connection unless we're working in-memory"""
if self.filename != ':memory:': if self.filename != ':memory:' and self._conn is not None:
if self._conn is not None: self._conn.commit()
self._conn.commit() self._conn.close()
self._conn.close() self._conn = None
self._conn = None
def delete(self): def delete(self):
"""Deletes the current session file""" """Deletes the current session file"""

View File

@ -35,10 +35,7 @@ class StateCache:
# is lightweight and immutable we can easily copy them around to # is lightweight and immutable we can easily copy them around to
# each update in case they need to fetch missing entities. # each update in case they need to fetch missing entities.
self._logger = loggers[__name__] self._logger = loggers[__name__]
if initial: self._pts_date = (initial.pts, initial.date) if initial else (None, None)
self._pts_date = initial.pts, initial.date
else:
self._pts_date = None, None
def reset(self): def reset(self):
self.__dict__.clear() self.__dict__.clear()

View File

@ -54,9 +54,10 @@ def syncify(*types):
# about asyncgenfunction's here. # about asyncgenfunction's here.
for t in types: for t in types:
for name in dir(t): for name in dir(t):
if not name.startswith('_') or name == '__call__': if (
if inspect.iscoroutinefunction(getattr(t, name)): not name.startswith('_') or name == '__call__'
_syncify_wrap(t, name) ) and inspect.iscoroutinefunction(getattr(t, name)):
_syncify_wrap(t, name)
syncify(TelegramClient, _TakeoutClient, Draft, Dialog, MessageButton, syncify(TelegramClient, _TakeoutClient, Draft, Dialog, MessageButton,

View File

@ -71,11 +71,7 @@ class Conversation(ChatGetter):
# The user is able to expect two responses for the same message. # The user is able to expect two responses for the same message.
# {desired message ID: next incoming index} # {desired message ID: next incoming index}
self._response_indices = {} self._response_indices = {}
if replies_are_responses: self._reply_indices = self._response_indices if replies_are_responses else {}
self._reply_indices = self._response_indices
else:
self._reply_indices = {}
self._edit_dates = {} self._edit_dates = {}
@_checks_cancelled @_checks_cancelled
@ -120,10 +116,7 @@ class Conversation(ChatGetter):
<telethon.client.messages.MessageMethods.send_read_acknowledge>`. <telethon.client.messages.MessageMethods.send_read_acknowledge>`.
""" """
if message is None: if message is None:
if self._incoming: message = self._incoming[-1].id if self._incoming else 0
message = self._incoming[-1].id
else:
message = 0
elif not isinstance(message, int): elif not isinstance(message, int):
message = message.id message = message.id

View File

@ -189,11 +189,7 @@ class InlineBuilder:
See "Type of the result" in https://core.telegram.org/bots/api. See "Type of the result" in https://core.telegram.org/bots/api.
""" """
if type is None: if type is None:
if voice_note: type = 'voice' if voice_note else 'document'
type = 'voice'
else:
type = 'document'
try: try:
fh = utils.get_input_document(file) fh = utils.get_input_document(file)
except TypeError: except TypeError:

View File

@ -453,9 +453,10 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
""" """
The :tl:`WebPage` media in this message, if any. The :tl:`WebPage` media in this message, if any.
""" """
if isinstance(self.media, types.MessageMediaWebPage): if isinstance(self.media, types.MessageMediaWebPage) and isinstance(
if isinstance(self.media.webpage, types.WebPage): self.media.webpage, types.WebPage
return self.media.webpage ):
return self.media.webpage
@property @property
def audio(self): def audio(self):
@ -920,14 +921,14 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
return [answers[idx].option for idx in i] return [answers[idx].option for idx in i]
return [answers[i].option] return [answers[i].option]
if text is not None: if text is not None:
if callable(text): for answer in answers:
for answer in answers: if (
if text(answer.text): callable(text)
return [answer.option] and text(answer.text)
else: or not callable(text)
for answer in answers: and answer.text == text
if answer.text == text: ):
return [answer.option] return [answer.option]
return return
if filter is not None: if filter is not None:
@ -953,14 +954,14 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
def find_button(): def find_button():
nonlocal i nonlocal i
if text is not None: if text is not None:
if callable(text): for button in self._buttons_flat:
for button in self._buttons_flat: if (
if text(button.text): callable(text)
return button and text(button.text)
else: or not callable(text)
for button in self._buttons_flat: and button.text == text
if button.text == text: ):
return button return button
return return
if filter is not None: if filter is not None:

View File

@ -37,10 +37,10 @@ class TLObject:
Pretty formats the given object as a string which is returned. Pretty formats the given object as a string which is returned.
If indent is None, a single line will be returned. If indent is None, a single line will be returned.
""" """
if indent is None: if isinstance(obj, TLObject):
if isinstance(obj, TLObject): obj = obj.to_dict()
obj = obj.to_dict()
if indent is None:
if isinstance(obj, dict): if isinstance(obj, dict):
return '{}({})'.format(obj.get('_', 'dict'), ', '.join( return '{}({})'.format(obj.get('_', 'dict'), ', '.join(
'{}={}'.format(k, TLObject.pretty_format(v)) '{}={}'.format(k, TLObject.pretty_format(v))
@ -56,9 +56,6 @@ class TLObject:
return repr(obj) return repr(obj)
else: else:
result = [] result = []
if isinstance(obj, TLObject):
obj = obj.to_dict()
if isinstance(obj, dict): if isinstance(obj, dict):
result.append(obj.get('_', 'dict')) result.append(obj.get('_', 'dict'))
result.append('(') result.append('(')
@ -115,8 +112,6 @@ class TLObject:
padding = 4 - padding padding = 4 - padding
r.append(bytes([len(data)])) r.append(bytes([len(data)]))
r.append(data)
else: else:
padding = len(data) % 4 padding = len(data) % 4
if padding != 0: if padding != 0:
@ -128,7 +123,7 @@ class TLObject:
(len(data) >> 8) % 256, (len(data) >> 8) % 256,
(len(data) >> 16) % 256 (len(data) >> 16) % 256
])) ]))
r.append(data) r.append(data)
r.append(bytes(padding)) r.append(bytes(padding))
return b''.join(r) return b''.join(r)

View File

@ -621,11 +621,7 @@ def _get_metadata(file):
else: else:
stream = file stream = file
close_stream = False close_stream = False
if getattr(file, 'seekable', None): seekable = file.seekable() if getattr(file, 'seekable', None) else False
seekable = file.seekable()
else:
seekable = False
if not seekable: if not seekable:
return None return None
@ -645,10 +641,12 @@ def _get_metadata(file):
_log.warning('Failed to analyze %s: %s %s', file, e.__class__, e) _log.warning('Failed to analyze %s: %s %s', file, e.__class__, e)
finally: finally:
if stream and close_stream: if close_stream:
stream.close() if stream:
elif stream and seekable: stream.close()
stream.seek(pos) elif seekable:
if stream:
stream.seek(pos)
def get_attributes(file, *, attributes=None, mime_type=None, def get_attributes(file, *, attributes=None, mime_type=None,

View File

@ -158,13 +158,13 @@ class InteractiveTelegramClient(TelegramClient):
# are much easier to use. # are much easier to use.
self.add_event_handler(self.message_handler, events.NewMessage) self.add_event_handler(self.message_handler, events.NewMessage)
# Retrieve the top dialogs. You can set the limit to None to
# retrieve all of them if you wish, but beware that may take
# a long time if you have hundreds of them.
dialog_count = 15
# Enter a while loop to chat as long as the user wants # Enter a while loop to chat as long as the user wants
while True: while True:
# Retrieve the top dialogs. You can set the limit to None to
# retrieve all of them if you wish, but beware that may take
# a long time if you have hundreds of them.
dialog_count = 15
# Entities represent the user, chat or channel # Entities represent the user, chat or channel
# corresponding to the dialog on the same index. # corresponding to the dialog on the same index.
dialogs = await self.get_dialogs(limit=dialog_count) dialogs = await self.get_dialogs(limit=dialog_count)
@ -198,7 +198,7 @@ class InteractiveTelegramClient(TelegramClient):
return return
try: try:
i = int(i if i else 0) - 1 i = int(i or 0) - 1
# Ensure it is inside the bounds, otherwise retry # Ensure it is inside the bounds, otherwise retry
if not 0 <= i < dialog_count: if not 0 <= i < dialog_count:
i = None i = None

View File

@ -67,16 +67,15 @@ async def handler(event):
await event.reply('> chrome\nneeds more firefox') await event.reply('> chrome\nneeds more firefox')
# Reply always responds as a reply. We can respond without replying too # Reply always responds as a reply. We can respond without replying too
if 'shrug' in event.raw_text: if 'shrug' in event.raw_text and can_react(event.chat_id):
if can_react(event.chat_id): await event.respond(r'¯\_(ツ)_/¯')
await event.respond(r'¯\_(ツ)_/¯')
# We can also use client methods from here
client = event.client
# If we sent the message, we are replying to someone, # If we sent the message, we are replying to someone,
# and we said "save pic" in the message # and we said "save pic" in the message
if event.out and event.is_reply and 'save pic' in event.raw_text: if event.out and event.is_reply and 'save pic' in event.raw_text:
# We can also use client methods from here
client = event.client
reply_msg = await event.get_reply_message() reply_msg = await event.get_reply_message()
replied_to_user = await reply_msg.get_input_sender() replied_to_user = await reply_msg.get_input_sender()

View File

@ -261,36 +261,42 @@ def _write_class_init(tlobject, kind, type_constructors, builder):
def _write_resolve(tlobject, builder): def _write_resolve(tlobject, builder):
if tlobject.is_function and any( if not tlobject.is_function or not any(
(arg.type in AUTO_CASTS (
or ((arg.name, arg.type) in NAMED_AUTO_CASTS arg.type in AUTO_CASTS
and tlobject.fullname not in NAMED_BLACKLIST)) or (
for arg in tlobject.real_args (arg.name, arg.type) in NAMED_AUTO_CASTS
and tlobject.fullname not in NAMED_BLACKLIST
)
)
for arg in tlobject.real_args
): ):
builder.writeln('async def resolve(self, client, utils):') return
for arg in tlobject.real_args:
ac = AUTO_CASTS.get(arg.type)
if not ac:
ac = NAMED_AUTO_CASTS.get((arg.name, arg.type))
if not ac:
continue
if arg.is_flag: builder.writeln('async def resolve(self, client, utils):')
builder.writeln('if self.{}:', arg.name) for arg in tlobject.real_args:
ac = AUTO_CASTS.get(arg.type)
if not ac:
ac = NAMED_AUTO_CASTS.get((arg.name, arg.type))
if not ac:
continue
if arg.is_vector: if arg.is_flag:
builder.writeln('_tmp = []') builder.writeln('if self.{}:', arg.name)
builder.writeln('for _x in self.{0}:', arg.name)
builder.writeln('_tmp.append({})', ac.format('_x'))
builder.end_block()
builder.writeln('self.{} = _tmp', arg.name)
else:
builder.writeln('self.{} = {}', arg.name,
ac.format('self.' + arg.name))
if arg.is_flag: if arg.is_vector:
builder.end_block() builder.writeln('_tmp = []')
builder.end_block() builder.writeln('for _x in self.{0}:', arg.name)
builder.writeln('_tmp.append({})', ac.format('_x'))
builder.end_block()
builder.writeln('self.{} = _tmp', arg.name)
else:
builder.writeln('self.{} = {}', arg.name,
ac.format('self.' + arg.name))
if arg.is_flag:
builder.end_block()
builder.end_block()
def _write_to_dict(tlobject, builder): def _write_to_dict(tlobject, builder):

View File

@ -55,8 +55,8 @@ class TLObject:
self.class_name = snake_to_camel_case( self.class_name = snake_to_camel_case(
self.name, suffix='Request' if self.is_function else '') self.name, suffix='Request' if self.is_function else '')
self.real_args = list(a for a in self.sorted_args() if not self.real_args = [a for a in self.sorted_args() if not
(a.flag_indicator or a.generic_definition)) (a.flag_indicator or a.generic_definition)]
@property @property
def innermost_result(self): def innermost_result(self):
@ -75,16 +75,8 @@ class TLObject:
key=lambda x: x.is_flag or x.can_be_inferred) key=lambda x: x.is_flag or x.can_be_inferred)
def __repr__(self, ignore_id=False): def __repr__(self, ignore_id=False):
if self.id is None or ignore_id: hex_id = '' if self.id is None or ignore_id else '#{:08x}'.format(self.id)
hex_id = '' args = ' ' + ' '.join([repr(arg) for arg in self.args]) if self.args else ''
else:
hex_id = '#{:08x}'.format(self.id)
if self.args:
args = ' ' + ' '.join([repr(arg) for arg in self.args])
else:
args = ''
return '{}{}{} = {}'.format(self.fullname, hex_id, args, self.result) return '{}{}{} = {}'.format(self.fullname, hex_id, args, self.result)
def infer_id(self): def infer_id(self):