mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-07 20:42:32 +00:00
Many code-style improvements
This commit is contained in:
@@ -2,7 +2,7 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from parser import SourceBuilder, TLParser
|
||||
from .parser import SourceBuilder, TLParser
|
||||
|
||||
|
||||
def get_output_path(normal_path):
|
||||
@@ -60,8 +60,8 @@ class TLGenerator:
|
||||
continue
|
||||
|
||||
# Determine the output directory and create it
|
||||
out_dir = get_output_path('functions' if tlobject.is_function
|
||||
else 'types')
|
||||
out_dir = get_output_path('functions'
|
||||
if tlobject.is_function else 'types')
|
||||
|
||||
if tlobject.namespace:
|
||||
out_dir = os.path.join(out_dir, tlobject.namespace)
|
||||
@@ -77,39 +77,51 @@ class TLGenerator:
|
||||
TLGenerator.get_class_name(tlobject)))
|
||||
|
||||
# Create the file for this TLObject
|
||||
filename = os.path.join(out_dir, TLGenerator.get_file_name(tlobject, add_extension=True))
|
||||
filename = os.path.join(
|
||||
out_dir,
|
||||
TLGenerator.get_file_name(
|
||||
tlobject, add_extension=True))
|
||||
with open(filename, 'w', encoding='utf-8') as file:
|
||||
# Let's build the source code!
|
||||
with SourceBuilder(file) as builder:
|
||||
# Both types and functions inherit from MTProtoRequest so they all can be sent
|
||||
builder.writeln('from telethon.tl.mtproto_request import MTProtoRequest')
|
||||
builder.writeln(
|
||||
'from telethon.tl.mtproto_request import MTProtoRequest')
|
||||
builder.writeln()
|
||||
builder.writeln()
|
||||
builder.writeln('class {}(MTProtoRequest):'.format(TLGenerator.get_class_name(tlobject)))
|
||||
builder.writeln('class {}(MTProtoRequest):'.format(
|
||||
TLGenerator.get_class_name(tlobject)))
|
||||
|
||||
# Write the original .tl definition, along with a "generated automatically" message
|
||||
builder.writeln('"""Class generated by TLObjects\' generator. '
|
||||
'All changes will be ERASED. Original .tl definition below.')
|
||||
builder.writeln(
|
||||
'"""Class generated by TLObjects\' generator. '
|
||||
'All changes will be ERASED. Original .tl definition below.')
|
||||
builder.writeln('{}"""'.format(repr(tlobject)))
|
||||
builder.writeln()
|
||||
|
||||
# Create an class-level variable that stores the TLObject's constructor ID
|
||||
builder.writeln("# Telegram's constructor ID (and unique identifier) for this class")
|
||||
builder.writeln('constructor_id = {}'.format(hex(tlobject.id)))
|
||||
builder.writeln(
|
||||
"# Telegram's constructor ID (and unique identifier) for this class")
|
||||
builder.writeln('constructor_id = {}'.format(
|
||||
hex(tlobject.id)))
|
||||
builder.writeln()
|
||||
|
||||
# First sort the arguments so that those not being a flag come first
|
||||
args = sorted([arg for arg in tlobject.args if not arg.flag_indicator],
|
||||
key=lambda x: x.is_flag)
|
||||
args = sorted(
|
||||
[arg for arg in tlobject.args
|
||||
if not arg.flag_indicator],
|
||||
key=lambda x: x.is_flag)
|
||||
|
||||
# Then convert the args to string parameters, the flags having =None
|
||||
args = [(arg.name if not arg.is_flag
|
||||
else '{}=None'.format(arg.name)) for arg in args
|
||||
if not arg.flag_indicator and not arg.generic_definition]
|
||||
args = [(arg.name if not arg.is_flag else
|
||||
'{}=None'.format(arg.name)) for arg in args
|
||||
if not arg.flag_indicator and
|
||||
not arg.generic_definition]
|
||||
|
||||
# Write the __init__ function
|
||||
if args:
|
||||
builder.writeln('def __init__(self, {}):'.format(', '.join(args)))
|
||||
builder.writeln('def __init__(self, {}):'.format(
|
||||
', '.join(args)))
|
||||
else:
|
||||
builder.writeln('def __init__(self):')
|
||||
|
||||
@@ -117,18 +129,23 @@ class TLGenerator:
|
||||
# those which are generated automatically: flag indicator and generic definitions.
|
||||
# We don't need the generic definitions in Python because arguments can be any type
|
||||
args = [arg for arg in tlobject.args
|
||||
if not arg.flag_indicator and not arg.generic_definition]
|
||||
if not arg.flag_indicator and
|
||||
not arg.generic_definition]
|
||||
|
||||
if args:
|
||||
# Write the docstring, so we know the type of the arguments
|
||||
builder.writeln('"""')
|
||||
for arg in args:
|
||||
if not arg.flag_indicator:
|
||||
builder.write(':param {}: Telegram type: «{}».'.format(arg.name, arg.type))
|
||||
builder.write(
|
||||
':param {}: Telegram type: «{}».'.format(
|
||||
arg.name, arg.type))
|
||||
if arg.is_vector:
|
||||
builder.write(' Must be a list.'.format(arg.name))
|
||||
builder.write(' Must be a list.'.format(
|
||||
arg.name))
|
||||
if arg.is_generic:
|
||||
builder.write(' This should be another MTProtoRequest.')
|
||||
builder.write(
|
||||
' This should be another MTProtoRequest.')
|
||||
builder.writeln()
|
||||
builder.writeln('"""')
|
||||
|
||||
@@ -136,7 +153,8 @@ class TLGenerator:
|
||||
# Functions have a result object and are confirmed by default
|
||||
if tlobject.is_function:
|
||||
builder.writeln('self.result = None')
|
||||
builder.writeln('self.confirmed = True # Confirmed by default')
|
||||
builder.writeln(
|
||||
'self.confirmed = True # Confirmed by default')
|
||||
|
||||
# Set the arguments
|
||||
if args:
|
||||
@@ -148,22 +166,24 @@ class TLGenerator:
|
||||
|
||||
# Write the on_send(self, writer) function
|
||||
builder.writeln('def on_send(self, writer):')
|
||||
builder.writeln('writer.write_int({}.constructor_id, signed=False)'
|
||||
.format(TLGenerator.get_class_name(tlobject)))
|
||||
builder.writeln(
|
||||
'writer.write_int({}.constructor_id, signed=False)'
|
||||
.format(TLGenerator.get_class_name(tlobject)))
|
||||
|
||||
for arg in tlobject.args:
|
||||
TLGenerator.write_onsend_code(builder, arg, tlobject.args)
|
||||
TLGenerator.write_onsend_code(builder, arg,
|
||||
tlobject.args)
|
||||
builder.end_block()
|
||||
|
||||
# Write the empty() function, which returns an "empty"
|
||||
# instance, in which all attributes are set to None
|
||||
builder.writeln('@staticmethod')
|
||||
builder.writeln('def empty():')
|
||||
builder.writeln('"""Returns an "empty" instance (all attributes are None)"""')
|
||||
builder.writeln(
|
||||
'"""Returns an "empty" instance (all attributes are None)"""')
|
||||
builder.writeln('return {}({})'.format(
|
||||
TLGenerator.get_class_name(tlobject),
|
||||
', '.join('None' for _ in range(len(args)))
|
||||
))
|
||||
TLGenerator.get_class_name(tlobject), ', '.join(
|
||||
'None' for _ in range(len(args)))))
|
||||
builder.end_block()
|
||||
|
||||
# Write the on_response(self, reader) function
|
||||
@@ -174,7 +194,8 @@ class TLGenerator:
|
||||
else:
|
||||
if tlobject.args:
|
||||
for arg in tlobject.args:
|
||||
TLGenerator.write_onresponse_code(builder, arg, tlobject.args)
|
||||
TLGenerator.write_onresponse_code(
|
||||
builder, arg, tlobject.args)
|
||||
else:
|
||||
# If there were no arguments, we still need an on_response method, and hence "pass" if empty
|
||||
builder.writeln('pass')
|
||||
@@ -186,23 +207,26 @@ class TLGenerator:
|
||||
builder.end_block()
|
||||
|
||||
builder.writeln('def __str__(self):')
|
||||
builder.writeln("return {}".format(str(tlobject)))
|
||||
builder.writeln('return {}'.format(str(tlobject)))
|
||||
# builder.end_block() # There is no need to end the last block
|
||||
|
||||
# Step 3: Once all the objects have been generated, we can now group them in a single file
|
||||
# Step 3: Once all the objects have been generated, we can now group them in a single file
|
||||
filename = os.path.join(get_output_path('all_tlobjects.py'))
|
||||
with open(filename, 'w', encoding='utf-8') as file:
|
||||
with SourceBuilder(file) as builder:
|
||||
builder.writeln('"""File generated by TLObjects\' generator. All changes will be ERASED"""')
|
||||
builder.writeln(
|
||||
'"""File generated by TLObjects\' generator. All changes will be ERASED"""')
|
||||
builder.writeln()
|
||||
|
||||
# First add imports
|
||||
for tlobject in tlobjects:
|
||||
builder.writeln('import {}'.format(TLGenerator.get_full_file_name(tlobject)))
|
||||
builder.writeln('import {}'.format(
|
||||
TLGenerator.get_full_file_name(tlobject)))
|
||||
builder.writeln()
|
||||
|
||||
# Create a variable to indicate which layer this is
|
||||
builder.writeln('layer = {} # Current generated layer'.format(TLParser.find_layer(scheme_file)))
|
||||
builder.writeln('layer = {} # Current generated layer'.format(
|
||||
TLParser.find_layer(scheme_file)))
|
||||
builder.writeln()
|
||||
|
||||
# Then create the dictionary containing constructor_id: class
|
||||
@@ -211,10 +235,9 @@ class TLGenerator:
|
||||
|
||||
# Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
|
||||
for tlobject in tlobjects:
|
||||
builder.writeln('{}: {}.{},'
|
||||
.format(hex(tlobject.id),
|
||||
TLGenerator.get_full_file_name(tlobject),
|
||||
TLGenerator.get_class_name(tlobject)))
|
||||
builder.writeln('{}: {}.{},'.format(
|
||||
hex(tlobject.id), TLGenerator.get_full_file_name(
|
||||
tlobject), TLGenerator.get_class_name(tlobject)))
|
||||
|
||||
builder.current_indent -= 1
|
||||
builder.writeln('}')
|
||||
@@ -225,8 +248,10 @@ class TLGenerator:
|
||||
|
||||
# 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!
|
||||
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 tlobject.is_function:
|
||||
result += 'Request'
|
||||
@@ -283,22 +308,25 @@ class TLGenerator:
|
||||
builder.writeln('if {}:'.format(name))
|
||||
|
||||
if arg.is_vector:
|
||||
builder.writeln("writer.write_int(0x1cb5c415, signed=False) # Vector's constructor ID")
|
||||
builder.writeln(
|
||||
"writer.write_int(0x1cb5c415, signed=False) # Vector's constructor ID")
|
||||
builder.writeln('writer.write_int(len({}))'.format(name))
|
||||
builder.writeln('for {}_item in {}:'.format(arg.name, name))
|
||||
# Temporary disable .is_vector, not to enter this if again
|
||||
arg.is_vector = False
|
||||
TLGenerator.write_onsend_code(builder, arg, args, name='{}_item'.format(arg.name))
|
||||
TLGenerator.write_onsend_code(
|
||||
builder, arg, args, name='{}_item'.format(arg.name))
|
||||
arg.is_vector = True
|
||||
|
||||
elif arg.flag_indicator:
|
||||
# Calculate the flags with those items which are not None
|
||||
builder.writeln('# Calculate the flags. This equals to those flag arguments which are NOT None')
|
||||
builder.writeln(
|
||||
'# Calculate the flags. This equals to those flag arguments which are NOT None')
|
||||
builder.writeln('flags = 0')
|
||||
for flag in args:
|
||||
if flag.is_flag:
|
||||
builder.writeln('flags |= (1 << {}) if {} else 0'
|
||||
.format(flag.flag_index, 'self.{}'.format(flag.name)))
|
||||
builder.writeln('flags |= (1 << {}) if {} else 0'.format(
|
||||
flag.flag_index, 'self.{}'.format(flag.name)))
|
||||
|
||||
builder.writeln('writer.write_int(flags)')
|
||||
builder.writeln()
|
||||
@@ -310,10 +338,12 @@ class TLGenerator:
|
||||
builder.writeln('writer.write_long({})'.format(name))
|
||||
|
||||
elif 'int128' == arg.type:
|
||||
builder.writeln('writer.write_large_int({}, bits=128)'.format(name))
|
||||
builder.writeln('writer.write_large_int({}, bits=128)'.format(
|
||||
name))
|
||||
|
||||
elif 'int256' == arg.type:
|
||||
builder.writeln('writer.write_large_int({}, bits=256)'.format(name))
|
||||
builder.writeln('writer.write_large_int({}, bits=256)'.format(
|
||||
name))
|
||||
|
||||
elif 'double' == arg.type:
|
||||
builder.writeln('writer.write_double({})'.format(name))
|
||||
@@ -366,7 +396,8 @@ class TLGenerator:
|
||||
was_flag = False
|
||||
if arg.is_flag:
|
||||
was_flag = True
|
||||
builder.writeln('if (flags & (1 << {})) != 0:'.format(arg.flag_index))
|
||||
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.is_flag = False
|
||||
|
||||
@@ -377,7 +408,8 @@ class TLGenerator:
|
||||
builder.writeln('for _ in range({}_len):'.format(arg.name))
|
||||
# Temporary disable .is_vector, not to enter this if again
|
||||
arg.is_vector = False
|
||||
TLGenerator.write_onresponse_code(builder, arg, args, name='{}_item'.format(arg.name))
|
||||
TLGenerator.write_onresponse_code(
|
||||
builder, arg, args, name='{}_item'.format(arg.name))
|
||||
builder.writeln('{}.append({}_item)'.format(name, arg.name))
|
||||
arg.is_vector = True
|
||||
|
||||
@@ -393,10 +425,12 @@ class TLGenerator:
|
||||
builder.writeln('{} = reader.read_long()'.format(name))
|
||||
|
||||
elif 'int128' == arg.type:
|
||||
builder.writeln('{} = reader.read_large_int(bits=128)'.format(name))
|
||||
builder.writeln('{} = reader.read_large_int(bits=128)'.format(
|
||||
name))
|
||||
|
||||
elif 'int256' == arg.type:
|
||||
builder.writeln('{} = reader.read_large_int(bits=256)'.format(name))
|
||||
builder.writeln('{} = reader.read_large_int(bits=256)'.format(
|
||||
name))
|
||||
|
||||
elif 'double' == arg.type:
|
||||
builder.writeln('{} = reader.read_double()'.format(name))
|
||||
@@ -408,7 +442,9 @@ class TLGenerator:
|
||||
builder.writeln('{} = reader.tgread_bool()'.format(name))
|
||||
|
||||
elif 'true' == arg.type: # Awkwardly enough, Telegram has both bool and "true", used in flags
|
||||
builder.writeln('{} = True # Arbitrary not-None value, no need to read since it is a flag'.format(name))
|
||||
builder.writeln(
|
||||
'{} = True # Arbitrary not-None value, no need to read since it is a flag'.
|
||||
format(name))
|
||||
|
||||
elif 'bytes' == arg.type:
|
||||
builder.writeln('{} = reader.tgread_bytes()'.format(name))
|
||||
@@ -429,6 +465,7 @@ class TLGenerator:
|
||||
# Restore .is_flag
|
||||
arg.is_flag = True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if TLGenerator.tlobjects_exist():
|
||||
print('Detected previous TLObjects. Cleaning...')
|
||||
|
Reference in New Issue
Block a user