Make lint happier

This commit is contained in:
Lonami Exo 2017-09-04 17:10:04 +02:00
parent 7f700c3bc1
commit 97cab7347b
22 changed files with 210 additions and 117 deletions

View File

@ -8,9 +8,10 @@ class DocsWriter:
"""Initializes the writer to the specified output file,
creating the parent directories when used if required.
'type_to_path_function' should be a function which, given a type name
and a named argument relative_to, returns the file path for the specified
type, relative to the given filename"""
'type_to_path_function' should be a function which, given a type
name and a named argument relative_to, returns the file path for
the specified type, relative to the given filename
"""
self.filename = filename
self.handle = None
@ -18,7 +19,9 @@ class DocsWriter:
self.menu_separator_tag = None
# Utility functions TODO There must be a better way
self.type_to_path = lambda t: type_to_path_function(t, relative_to=self.filename)
self.type_to_path = lambda t: type_to_path_function(
t, relative_to=self.filename
)
# Control signals
self.menu_began = False
@ -28,7 +31,9 @@ class DocsWriter:
# High level writing
def write_head(self, title, relative_css_path):
"""Writes the head part for the generated document, with the given title and CSS"""
"""Writes the head part for the generated document,
with the given title and CSS
"""
self.write('''<!DOCTYPE html>
<html>
<head>
@ -50,9 +55,12 @@ class DocsWriter:
<div id="main_div">''')
def set_menu_separator(self, relative_image_path):
"""Sets the menu separator. Must be called before adding entries to the menu"""
"""Sets the menu separator.
Must be called before adding entries to the menu
"""
if relative_image_path:
self.menu_separator_tag = '<img src="%s" alt="/" />' % relative_image_path
self.menu_separator_tag = \
'<img src="{}" alt="/" />'.format(relative_image_path)
else:
self.menu_separator_tag = None
@ -86,13 +94,17 @@ class DocsWriter:
self.write('</ul>')
def write_title(self, title, level=1):
"""Writes a title header in the document body, with an optional depth level"""
"""Writes a title header in the document body,
with an optional depth level
"""
self.write('<h%d>' % level)
self.write(title)
self.write('</h%d>' % level)
def write_code(self, tlobject):
"""Writes the code for the given 'tlobject' properly formatted ith with hyperlinks"""
"""Writes the code for the given 'tlobject' properly
formatted with hyperlinks
"""
self.write('<pre>---')
self.write('functions' if tlobject.is_function else 'types')
self.write('---\n')
@ -127,7 +139,9 @@ class DocsWriter:
self.write('!')
if arg.is_vector:
self.write('<a href="%s">Vector</a>&lt;' % self.type_to_path('vector'))
self.write(
'<a href="%s">Vector</a>&lt;' % self.type_to_path('vector')
)
# Argument type
if arg.type:
@ -146,7 +160,7 @@ class DocsWriter:
if arg.generic_definition:
self.write('}')
# Now write the resulting type (result from a function, or type for a constructor)
# Now write the resulting type (result from a function/type)
self.write(' = ')
generic_name = next((arg.name for arg in tlobject.args
if arg.generic_definition), None)

View File

@ -16,7 +16,7 @@ from telethon_generator.parser import TLParser, TLObject
# TLObject -> Python class name
def get_class_name(tlobject):
"""Gets the class name following the Python style guidelines, in ThisClassFormat"""
"""Gets the class name following the Python style guidelines"""
# Courtesy of http://stackoverflow.com/a/31531797/4759433
name = tlobject.name if isinstance(tlobject, TLObject) else tlobject
result = re.sub(r'_([a-z])', lambda m: m.group(1).upper(), name)
@ -93,9 +93,9 @@ def get_path_for_type(type_, relative_to='.'):
elif '.' in type_:
# If it's not a core type, then it has to be a custom Telegram type
namespace, name = type_.split('.')
path = 'types/%s/%s' % (namespace, get_file_name(name, add_extension=True))
path = 'types/%s/%s' % (namespace, get_file_name(name, True))
else:
path = 'types/%s' % get_file_name(type_, add_extension=True)
path = 'types/%s' % get_file_name(type_, True)
return get_relative_path(path, relative_to)
@ -116,7 +116,7 @@ def get_relative_paths(original, relative_to):
# Generate a index.html file for the given folder
def find_title(html_file):
"""Finds the <title> for the given HTML file, returns (Unknown) if not found"""
"""Finds the <title> for the given HTML file, or (Unknown)"""
with open(html_file) as handle:
for line in handle:
if '<title>' in line:
@ -196,8 +196,25 @@ def generate_index(folder, original_paths):
docs.end_body()
def get_description(arg):
"""Generates a proper description for the given argument"""
desc = []
if arg.can_be_inferred:
desc.append('If left to None, it will be inferred automatically.')
if arg.is_vector:
desc.append('A list must be supplied for this argument.')
if arg.is_generic:
desc.append('A different Request must be supplied for this argument.')
if arg.is_flag:
desc.append('This argument can be omitted.')
return ' '.join(desc)
def generate_documentation(scheme_file):
"""Generates the documentation HTML files from from scheme.tl to /methods and /constructors, etc."""
"""Generates the documentation HTML files from from scheme.tl to
/methods and /constructors, etc.
"""
original_paths = {
'css': 'css/docs.css',
'arrow': 'img/arrow.svg',
@ -234,7 +251,8 @@ def generate_documentation(scheme_file):
# Determine the relative paths for this file
paths = get_relative_paths(original_paths, relative_to=filename)
with DocsWriter(filename, type_to_path_function=get_path_for_type) as docs:
with DocsWriter(filename, type_to_path_function=get_path_for_type) \
as docs:
docs.write_head(
title=get_class_name(tlobject),
relative_css_path=paths['css'])
@ -274,8 +292,9 @@ def generate_documentation(scheme_file):
inner = tlobject.result
docs.begin_table(column_count=1)
docs.add_row(inner,
link=get_path_for_type(inner, relative_to=filename))
docs.add_row(inner, link=get_path_for_type(
inner, relative_to=filename
))
docs.end_table()
constructors = tltypes.get(inner, [])
@ -294,9 +313,12 @@ def generate_documentation(scheme_file):
docs.end_table()
# Return (or similar types) written. Now parameters/members
docs.write_title('Parameters' if tlobject.is_function else 'Members', level=3)
docs.write_title(
'Parameters' if tlobject.is_function else 'Members', level=3
)
# Sort the arguments in the same way they're sorted on the generated code (flags go last)
# Sort the arguments in the same way they're sorted
# on the generated code (flags go last)
args = [
a for a in tlobject.sorted_args()
if not a.flag_indicator and not a.generic_definition
@ -315,22 +337,13 @@ def generate_documentation(scheme_file):
if arg.is_generic:
docs.add_row('!' + arg.type, align='center')
else:
docs.add_row(arg.type,
link=get_path_for_type(arg.type, relative_to=filename),
align='center')
docs.add_row(
arg.type, align='center', link=
get_path_for_type(arg.type, relative_to=filename)
)
# Create a description for this argument
description = ''
if arg.can_be_inferred:
description += 'If left to None, it will be inferred automatically. '
if arg.is_vector:
description += 'A list must be supplied for this argument. '
if arg.is_generic:
description += 'A different MTProtoRequest must be supplied for this argument. '
if arg.is_flag:
description += 'This argument can be omitted. '
docs.add_row(description.strip())
# Add a description for this argument
docs.add_row(get_description(arg))
docs.end_table()
else:
@ -342,14 +355,14 @@ def generate_documentation(scheme_file):
docs.end_body()
# Find all the available types (which are not the same as the constructors)
# Each type has a list of constructors associated to it, so it should be a map
# Each type has a list of constructors associated to it, hence is a map
print('Generating types documentation...')
for tltype, constructors in tltypes.items():
filename = get_path_for_type(tltype)
out_dir = os.path.dirname(filename)
os.makedirs(out_dir, exist_ok=True)
# Since we don't have access to the full TLObject, split the type into namespace.name
# Since we don't have access to the full TLObject, split the type
if '.' in tltype:
namespace, name = tltype.split('.')
else:
@ -358,7 +371,8 @@ def generate_documentation(scheme_file):
# Determine the relative paths for this file
paths = get_relative_paths(original_paths, relative_to=out_dir)
with DocsWriter(filename, type_to_path_function=get_path_for_type) as docs:
with DocsWriter(filename, type_to_path_function=get_path_for_type) \
as docs:
docs.write_head(
title=get_class_name(name),
relative_css_path=paths['css'])
@ -376,7 +390,8 @@ def generate_documentation(scheme_file):
elif len(constructors) == 1:
docs.write_text('This type has one constructor available.')
else:
docs.write_text('This type has %d constructors available.' % len(constructors))
docs.write_text('This type has %d constructors available.' %
len(constructors))
docs.begin_table(2)
for constructor in constructors:
@ -394,7 +409,10 @@ def generate_documentation(scheme_file):
elif len(functions) == 1:
docs.write_text('Only the following method returns this type.')
else:
docs.write_text('The following %d methods return this type as a result.' % len(functions))
docs.write_text(
'The following %d methods return this type as a result.' %
len(functions)
)
docs.begin_table(2)
for func in functions:
@ -456,8 +474,8 @@ def generate_documentation(scheme_file):
docs.end_table()
docs.end_body()
# After everything's been written, generate an index.html file for every folder.
# This will be done automatically and not taking into account any additional
# After everything's been written, generate an index.html per folder.
# This will be done automatically and not taking into account any extra
# information that we have available, simply a file listing all the others
# accessible by clicking on their title
print('Generating indices...')
@ -485,13 +503,16 @@ def generate_documentation(scheme_file):
methods = sorted(methods, key=lambda m: m.name)
constructors = sorted(constructors, key=lambda c: c.name)
request_names = ', '.join('"' + get_class_name(m) + '"' for m in methods)
type_names = ', '.join('"' + get_class_name(t) + '"' for t in types)
constructor_names = ', '.join('"' + get_class_name(t) + '"' for t in constructors)
def fmt(xs, formatter):
return ', '.join('"{}"'.format(formatter(x)) for x in xs)
request_urls = ', '.join('"' + get_create_path_for(m) + '"' for m in methods)
type_urls = ', '.join('"' + get_path_for_type(t) + '"' for t in types)
constructor_urls = ', '.join('"' + get_create_path_for(t) + '"' for t in constructors)
request_names = fmt(methods, get_class_name)
type_names = fmt(types, get_class_name)
constructor_names = fmt(constructors, get_class_name)
request_urls = fmt(methods, get_create_path_for)
type_urls = fmt(types, get_create_path_for)
constructor_urls = fmt(constructors, get_create_path_for)
replace_dict = {
'type_count': len(types),

View File

@ -2,7 +2,9 @@
import unittest
if __name__ == '__main__':
from telethon_tests import CryptoTests, ParserTests, TLTests, UtilsTests, NetworkTests
from telethon_tests import \
CryptoTests, ParserTests, TLTests, UtilsTests, NetworkTests
test_classes = [CryptoTests, ParserTests, TLTests, UtilsTests]
network = input('Run network tests (y/n)?: ').lower() == 'y'

View File

@ -14,7 +14,9 @@ class AuthKey:
self.key_id = reader.read_long(signed=False)
def calc_new_nonce_hash(self, new_nonce, number):
"""Calculates the new nonce hash based on the current class fields' values"""
"""Calculates the new nonce hash based on
the current class fields' values
"""
with BinaryWriter() as writer:
writer.write(new_nonce)
writer.write_byte(number)

View File

@ -31,7 +31,8 @@ class CdnDecrypter:
# https://core.telegram.org/cdn
cdn_aes = AESModeCTR(
key=cdn_redirect.encryption_key,
iv=cdn_redirect.encryption_iv[:12] + (offset >> 4).to_bytes(4, 'big')
iv=
cdn_redirect.encryption_iv[:12] + (offset >> 4).to_bytes(4, 'big')
)
# Create a new client on said CDN

View File

@ -61,7 +61,9 @@ class Factorization:
@staticmethod
def factorize(pq):
"""Factorizes the given number and returns both the divisor and the number divided by the divisor"""
"""Factorizes the given number and returns both
the divisor and the number divided by the divisor
"""
if sympy:
return tuple(sympy.ntheory.factorint(pq).keys())
else:

View File

@ -30,7 +30,8 @@ class InvalidChecksumError(Exception):
def __init__(self, checksum, valid_checksum):
super().__init__(
self,
'Invalid checksum ({} when {} was expected). This packet should be skipped.'
'Invalid checksum ({} when {} was expected). '
'This packet should be skipped.'
.format(checksum, valid_checksum))
self.checksum = checksum

View File

@ -26,7 +26,8 @@ class BinaryReader:
# region Reading
# "All numbers are written as little endian." |> Source: https://core.telegram.org/mtproto
# "All numbers are written as little endian."
# https://core.telegram.org/mtproto
def read_byte(self):
"""Reads a single byte value"""
return self.read(1)[0]
@ -56,8 +57,7 @@ class BinaryReader:
"""Read the given amount of bytes"""
result = self.reader.read(length)
if len(result) != length:
raise BufferError(
'Trying to read outside the data bounds (no more data left to read)')
raise BufferError('No more data left to read')
return result
@ -70,7 +70,9 @@ class BinaryReader:
# region Telegram custom reading
def tgread_bytes(self):
"""Reads a Telegram-encoded byte array, without the need of specifying its length"""
"""Reads a Telegram-encoded byte array,
without the need of specifying its length
"""
first_byte = self.read_byte()
if first_byte == 254:
length = self.read_byte() | (self.read_byte() << 8) | (
@ -102,7 +104,9 @@ class BinaryReader:
raise ValueError('Invalid boolean code {}'.format(hex(value)))
def tgread_date(self):
"""Reads and converts Unix time (used by Telegram) into a Python datetime object"""
"""Reads and converts Unix time (used by Telegram)
into a Python datetime object
"""
value = self.read_int()
return None if value == 0 else datetime.fromtimestamp(value)
@ -152,7 +156,9 @@ class BinaryReader:
self.reader.seek(position)
def seek(self, offset):
"""Seeks the stream position given an offset from the current position. May be negative"""
"""Seeks the stream position given an offset from the
current position. The offset may be negative
"""
self.reader.seek(offset, os.SEEK_CUR)
# endregion

View File

@ -22,21 +22,22 @@ class BinaryWriter:
# region Writing
# "All numbers are written as little endian." |> Source: https://core.telegram.org/mtproto
# "All numbers are written as little endian."
# https://core.telegram.org/mtproto
def write_byte(self, value):
"""Writes a single byte value"""
self.writer.write(pack('B', value))
self.written_count += 1
def write_int(self, value, signed=True):
"""Writes an integer value (4 bytes), which can or cannot be signed"""
"""Writes an integer value (4 bytes), optionally signed"""
self.writer.write(
int.to_bytes(
value, length=4, byteorder='little', signed=signed))
self.written_count += 4
def write_long(self, value, signed=True):
"""Writes a long integer value (8 bytes), which can or cannot be signed"""
"""Writes a long integer value (8 bytes), optionally signed"""
self.writer.write(
int.to_bytes(
value, length=8, byteorder='little', signed=signed))
@ -101,7 +102,9 @@ class BinaryWriter:
self.write_int(0x997275b5 if boolean else 0xbc799737, signed=False)
def tgwrite_date(self, datetime):
"""Converts a Python datetime object into Unix time (used by Telegram) and writes it"""
"""Converts a Python datetime object into Unix time
(used by Telegram) and writes it
"""
value = 0 if datetime is None else int(datetime.timestamp())
self.write_int(value)
@ -127,14 +130,18 @@ class BinaryWriter:
self.writer.close()
def get_bytes(self, flush=True):
"""Get the current bytes array content from the buffer, optionally flushing first"""
"""Get the current bytes array content from the buffer,
optionally flushing first
"""
if flush:
self.writer.flush()
return self.writer.raw.getvalue()
def get_written_bytes_count(self):
"""Gets the count of bytes written in the buffer.
This may NOT be equal to the stream length if one was provided when initializing the writer"""
This may NOT be equal to the stream length if one
was provided when initializing the writer
"""
return self.written_count
# with block

View File

@ -22,7 +22,9 @@ def ensure_parent_dir_exists(file_path):
def calc_key(shared_key, msg_key, client):
"""Calculate the key based on Telegram guidelines, specifying whether it's the client or not"""
"""Calculate the key based on Telegram guidelines,
specifying whether it's the client or not
"""
x = 0 if client else 8
sha1a = sha1(msg_key + shared_key[x:x + 32]).digest()
@ -56,7 +58,9 @@ def generate_key_data_from_nonce(server_nonce, new_nonce):
def get_password_hash(pw, current_salt):
"""Gets the password hash for the two-step verification.
current_salt should be the byte array provided by invoking GetPasswordRequest()"""
current_salt should be the byte array provided by
invoking GetPasswordRequest()
"""
# Passwords are encoded as UTF-8
# At https://github.com/DrKLO/Telegram/blob/e31388

View File

@ -217,6 +217,8 @@ def do_authentication(connection):
def get_int(byte_array, signed=True):
"""Gets the specified integer from its byte array. This should be used by the authenticator,
who requires the data to be in big endian"""
"""Gets the specified integer from its byte array.
This should be used by the authenticator,
who requires the data to be in big endian
"""
return int.from_bytes(byte_array, byteorder='big', signed=signed)

View File

@ -61,7 +61,8 @@ class Connection:
setattr(self, 'send', self._send_intermediate)
setattr(self, 'recv', self._recv_intermediate)
elif mode in (ConnectionMode.TCP_ABRIDGED, ConnectionMode.TCP_OBFUSCATED):
elif mode in (ConnectionMode.TCP_ABRIDGED,
ConnectionMode.TCP_OBFUSCATED):
setattr(self, 'send', self._send_abridged)
setattr(self, 'recv', self._recv_abridged)

View File

@ -4,7 +4,9 @@ from ..extensions import BinaryReader, BinaryWriter
class MtProtoPlainSender:
"""MTProto Mobile Protocol plain sender (https://core.telegram.org/mtproto/description#unencrypted-messages)"""
"""MTProto Mobile Protocol plain sender
(https://core.telegram.org/mtproto/description#unencrypted-messages)
"""
def __init__(self, connection):
self._sequence = 0
@ -19,7 +21,9 @@ class MtProtoPlainSender:
self._connection.close()
def send(self, data):
"""Sends a plain packet (auth_key_id = 0) containing the given message body (data)"""
"""Sends a plain packet (auth_key_id = 0) containing the
given message body (data)
"""
with BinaryWriter(known_length=len(data) + 20) as writer:
writer.write_long(0)
writer.write_long(self._get_new_msg_id())

View File

@ -31,7 +31,7 @@ class MtProtoSender:
# Store an RLock instance to make this class safely multi-threaded
self._lock = RLock()
# Used when logging out, the only request that seems to use 'ack' requests
# Used when logging out, the only request that seems to use 'ack'
# TODO There might be a better way to handle msgs_ack requests
self.logging_out = False
@ -114,7 +114,10 @@ class MtProtoSender:
def _send_packet(self, packet, request):
"""Sends the given packet bytes with the additional
information of the original request. This does NOT lock the threads!"""
information of the original request.
This does NOT lock the threads!
"""
request.request_msg_id = self.session.get_new_msg_id()
# First calculate plain_text to encrypt it
@ -183,7 +186,7 @@ class MtProtoSender:
reader.seek(-4)
# The following codes are "parsed manually"
if code == 0xf35c6d01: # rpc_result, (response of an RPC call, i.e., we sent a request)
if code == 0xf35c6d01: # rpc_result, (response of an RPC call)
return self._handle_rpc_result(msg_id, sequence, reader)
if code == 0x347773c5: # pong
@ -219,11 +222,15 @@ class MtProtoSender:
if code in tlobjects:
result = reader.tgread_object()
if self.unhandled_callbacks:
self._logger.debug('Passing TLObject to callbacks %s', repr(result))
self._logger.debug(
'Passing TLObject to callbacks %s', repr(result)
)
for callback in self.unhandled_callbacks:
callback(result)
else:
self._logger.debug('Ignoring unhandled TLObject %s', repr(result))
self._logger.debug(
'Ignoring unhandled TLObject %s', repr(result)
)
return True

View File

@ -184,8 +184,9 @@ class TelegramBareClient:
except (RPCError, ConnectionError) as error:
# Probably errors from the previous session, ignore them
self.disconnect()
self._logger.debug('Could not stabilise initial connection: {}'
.format(error))
self._logger.debug(
'Could not stabilise initial connection: {}'.format(error)
)
return None if initial_query else False
def disconnect(self):
@ -515,8 +516,10 @@ class TelegramBareClient:
progress_callback(f.tell(), file_size)
finally:
if cdn_decrypter:
try: cdn_decrypter.client.disconnect()
except: pass
try:
cdn_decrypter.client.disconnect()
except:
pass
if isinstance(file, str):
f.close()

View File

@ -124,7 +124,6 @@ class TelegramClient(TelegramBareClient):
# Constantly read for results and updates from within the main client
self._recv_thread = None
# endregion
# region Connecting

View File

@ -73,7 +73,7 @@ class Session:
'time_offset': self.time_offset,
'server_address': self.server_address,
'auth_key_data':
b64encode(self.auth_key.key).decode('ascii')\
b64encode(self.auth_key.key).decode('ascii')
if self.auth_key else None
}, file)

View File

@ -11,21 +11,27 @@ class SourceBuilder:
self.auto_added_line = False
def indent(self):
"""Indents the current source code line by the current indentation level"""
"""Indents the current source code line
by the current indentation level
"""
self.write(' ' * (self.current_indent * self.indent_size))
def write(self, string):
"""Writes a string into the source code, applying indentation if required"""
"""Writes a string into the source code,
applying indentation if required
"""
if self.on_new_line:
self.on_new_line = False # We're not on a new line anymore
if string.strip(
): # If the string was not empty, indent; Else it probably was a new line
# If the string was not empty, indent; Else probably a new line
if string.strip():
self.indent()
self.out_stream.write(string)
def writeln(self, string=''):
"""Writes a string into the source code _and_ appends a new line, applying indentation if required"""
"""Writes a string into the source code _and_ appends a new line,
applying indentation if required
"""
self.write(string + '\n')
self.on_new_line = True

View File

@ -11,7 +11,8 @@ class TLParser:
"""This method yields TLObjects from a given .tl file"""
with open(file_path, encoding='utf-8') as file:
# Start by assuming that the next found line won't be a function (and will hence be a type)
# Start by assuming that the next found line won't
# be a function (and will hence be a type)
is_function = False
# Read all the lines from the .tl file
@ -21,7 +22,8 @@ class TLParser:
# Ensure that the line is not a comment
if line and not line.startswith('//'):
# Check whether the line is a type change (types ⋄ functions) or not
# Check whether the line is a type change
# (types <-> functions) or not
match = re.match('---(\w+)---', line)
if match:
following_types = match.group(1)

View File

@ -405,15 +405,14 @@ class TLGenerator:
@staticmethod
def get_class_name(tlobject):
"""Gets the class name following the Python style guidelines, in ThisClassFormat"""
"""Gets the class name following the Python style guidelines"""
# Courtesy of http://stackoverflow.com/a/31531797/4759433
# Also, '_' could be replaced for ' ', then use .title(), and then remove ' '
result = re.sub(r'_([a-z])', lambda m: m.group(1).upper(),
tlobject.name)
result = result[:1].upper() + result[1:].replace(
'_', '') # Replace again to fully ensure!
# If it's a function, let it end with "Request" to identify them more easily
# If it's a function, let it end with "Request" to identify them
if tlobject.is_function:
result += 'Request'
return result
@ -436,9 +435,11 @@ class TLGenerator:
Writes the write code for the given argument
:param builder: The source code builder
:param arg: The argument to write
:param args: All the other arguments in TLObject same on_send. This is required to determine the flags value
:param args: All the other arguments in TLObject same on_send.
This is required to determine the flags value
:param name: The name of the argument. Defaults to "self.argname"
This argument is an option because it's required when writing Vectors<>
This argument is an option because it's required when
writing Vectors<>
"""
if arg.generic_definition:
@ -447,8 +448,10 @@ class TLGenerator:
if name is None:
name = 'self.{}'.format(arg.name)
# The argument may be a flag, only write if it's not None AND if it's not a True type
# True types are not actually sent, but instead only used to determine the flags
# The argument may be a flag, only write if it's not None AND
# if it's not a True type.
# True types are not actually sent, but instead only used to
# determine the flags.
if arg.is_flag:
if arg.type == 'true':
return # Exit, since True type is never written
@ -457,8 +460,7 @@ class TLGenerator:
if arg.is_vector:
if arg.use_vector_id:
builder.writeln(
"writer.write_int(0x1cb5c415, signed=False) # Vector's constructor ID")
builder.writeln('writer.write_int(0x1cb5c415, signed=False)')
builder.writeln('writer.write_int(len({}))'.format(name))
builder.writeln('for _x in {}:'.format(name))
@ -501,7 +503,7 @@ class TLGenerator:
elif 'Bool' == arg.type:
builder.writeln('writer.tgwrite_bool({})'.format(name))
elif 'true' == arg.type: # Awkwardly enough, Telegram has both bool and "true", used in flags
elif 'true' == arg.type:
pass # These are actually NOT written! Only used for flags
elif 'bytes' == arg.type:
@ -528,9 +530,11 @@ class TLGenerator:
:param builder: The source code builder
:param arg: The argument to write
:param args: All the other arguments in TLObject same on_send. This is required to determine the flags value
:param args: All the other arguments in TLObject same on_send.
This is required to determine the flags value
:param name: The name of the argument. Defaults to "self.argname"
This argument is an option because it's required when writing Vectors<>
This argument is an option because it's required when
writing Vectors<>
"""
if arg.generic_definition:
@ -544,8 +548,10 @@ class TLGenerator:
if arg.is_flag:
was_flag = True
builder.writeln('if (flags & (1 << {})) != 0:'.format(
arg.flag_index))
# Temporary disable .is_flag not to enter this if again when calling the method recursively
arg.flag_index
))
# Temporary disable .is_flag not to enter this if
# again when calling the method recursively
arg.is_flag = False
if arg.is_vector:
@ -621,7 +627,8 @@ class TLGenerator:
Writes the receive code for the given function
:param builder: The source code builder
:param tlobject: The TLObject for which the 'self.result = ' will be written
:param tlobject: The TLObject for which the 'self.result = '
will be written
"""
if tlobject.result.startswith('Vector<'):
# Vector results are a bit special since they can also be composed
@ -631,13 +638,15 @@ class TLGenerator:
if tlobject.result == 'Vector<int>':
builder.writeln('reader.read_int() # Vector id')
builder.writeln('count = reader.read_int()')
builder.writeln('self.result = [reader.read_int() for _ in range(count)]')
builder.writeln(
'self.result = [reader.read_int() for _ in range(count)]'
)
elif tlobject.result == 'Vector<long>':
builder.writeln('reader.read_int() # Vector id')
builder.writeln('count = reader.read_long()')
builder.writeln('self.result = [reader.read_long() for _ in range(count)]')
builder.writeln(
'self.result = [reader.read_long() for _ in range(count)]'
)
else:
builder.writeln('self.result = reader.tgread_vector()')
else:

View File

@ -13,8 +13,8 @@ api_hash = None
if not api_id or not api_hash:
raise ValueError('Please fill in both your api_id and api_hash.')
class HigherLevelTests(unittest.TestCase):
class HigherLevelTests(unittest.TestCase):
@staticmethod
def test_cdn_download():
client = TelegramClient(None, api_id, api_hash)
@ -24,7 +24,7 @@ class HigherLevelTests(unittest.TestCase):
try:
phone = '+999662' + str(randint(0, 9999)).zfill(4)
client.send_code_request(phone)
client.sign_up(phone, '22222', 'Test', 'DC')
client.sign_up('22222', 'Test', 'DC')
me = client.get_me()
data = os.urandom(2 ** 17)