mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-13 04:56:35 +03:00
Revisit telethon_generator (closes #724)
This commit is contained in:
parent
7bc021bba4
commit
cb226e7f45
|
@ -16,7 +16,7 @@ class SourceBuilder:
|
||||||
"""
|
"""
|
||||||
self.write(' ' * (self.current_indent * self.indent_size))
|
self.write(' ' * (self.current_indent * self.indent_size))
|
||||||
|
|
||||||
def write(self, string):
|
def write(self, string, *args, **kwargs):
|
||||||
"""Writes a string into the source code,
|
"""Writes a string into the source code,
|
||||||
applying indentation if required
|
applying indentation if required
|
||||||
"""
|
"""
|
||||||
|
@ -26,13 +26,16 @@ class SourceBuilder:
|
||||||
if string.strip():
|
if string.strip():
|
||||||
self.indent()
|
self.indent()
|
||||||
|
|
||||||
self.out_stream.write(string)
|
if args or kwargs:
|
||||||
|
self.out_stream.write(string.format(*args, **kwargs))
|
||||||
|
else:
|
||||||
|
self.out_stream.write(string)
|
||||||
|
|
||||||
def writeln(self, string=''):
|
def writeln(self, string='', *args, **kwargs):
|
||||||
"""Writes a string into the source code _and_ appends a new line,
|
"""Writes a string into the source code _and_ appends a new line,
|
||||||
applying indentation if required
|
applying indentation if required
|
||||||
"""
|
"""
|
||||||
self.write(string + '\n')
|
self.write(string + '\n', *args, **kwargs)
|
||||||
self.on_new_line = True
|
self.on_new_line = True
|
||||||
|
|
||||||
# If we're writing a block, increment indent for the next time
|
# If we're writing a block, increment indent for the next time
|
||||||
|
|
|
@ -24,9 +24,11 @@ class TLGenerator:
|
||||||
self.output_dir = output_dir
|
self.output_dir = output_dir
|
||||||
|
|
||||||
def _get_file(self, *paths):
|
def _get_file(self, *paths):
|
||||||
|
"""Wrapper around ``os.path.join()`` with output as first path."""
|
||||||
return os.path.join(self.output_dir, *paths)
|
return os.path.join(self.output_dir, *paths)
|
||||||
|
|
||||||
def _rm_if_exists(self, filename):
|
def _rm_if_exists(self, filename):
|
||||||
|
"""Recursively deletes the given filename if it exists."""
|
||||||
file = self._get_file(filename)
|
file = self._get_file(filename)
|
||||||
if os.path.exists(file):
|
if os.path.exists(file):
|
||||||
if os.path.isdir(file):
|
if os.path.isdir(file):
|
||||||
|
@ -35,19 +37,21 @@ class TLGenerator:
|
||||||
os.remove(file)
|
os.remove(file)
|
||||||
|
|
||||||
def tlobjects_exist(self):
|
def tlobjects_exist(self):
|
||||||
"""Determines whether the TLObjects were previously
|
"""
|
||||||
generated (hence exist) or not
|
Determines whether the TLObjects were previously
|
||||||
|
generated (hence exist) or not.
|
||||||
"""
|
"""
|
||||||
return os.path.isfile(self._get_file('all_tlobjects.py'))
|
return os.path.isfile(self._get_file('all_tlobjects.py'))
|
||||||
|
|
||||||
def clean_tlobjects(self):
|
def clean_tlobjects(self):
|
||||||
"""Cleans the automatically generated TLObjects from disk"""
|
"""Cleans the automatically generated TLObjects from disk."""
|
||||||
for name in ('functions', 'types', 'all_tlobjects.py'):
|
for name in ('functions', 'types', 'all_tlobjects.py'):
|
||||||
self._rm_if_exists(name)
|
self._rm_if_exists(name)
|
||||||
|
|
||||||
def generate_tlobjects(self, scheme_file, import_depth):
|
def generate_tlobjects(self, scheme_file, import_depth):
|
||||||
"""Generates all the TLObjects from scheme.tl to
|
"""
|
||||||
tl/functions and tl/types
|
Generates all the TLObjects from the ``scheme_file`` to
|
||||||
|
``tl/functions`` and ``tl/types``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# First ensure that the required parent directories exist
|
# First ensure that the required parent directories exist
|
||||||
|
@ -85,42 +89,33 @@ class TLGenerator:
|
||||||
# Step 4: Once all the objects have been generated,
|
# Step 4: Once all the objects have been generated,
|
||||||
# we can now group them in a single file
|
# we can now group them in a single file
|
||||||
filename = os.path.join(self._get_file('all_tlobjects.py'))
|
filename = os.path.join(self._get_file('all_tlobjects.py'))
|
||||||
with open(filename, 'w', encoding='utf-8') as file:
|
with open(filename, 'w', encoding='utf-8') as file,\
|
||||||
with SourceBuilder(file) as builder:
|
SourceBuilder(file) as builder:
|
||||||
builder.writeln(AUTO_GEN_NOTICE)
|
builder.writeln(AUTO_GEN_NOTICE)
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
|
|
||||||
builder.writeln('from . import types, functions')
|
builder.writeln('from . import types, functions')
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
|
|
||||||
# Create a constant variable to indicate which layer this is
|
# Create a constant variable to indicate which layer this is
|
||||||
builder.writeln('LAYER = {}'.format(
|
builder.writeln('LAYER = {}', TLParser.find_layer(scheme_file))
|
||||||
TLParser.find_layer(scheme_file))
|
builder.writeln()
|
||||||
)
|
|
||||||
builder.writeln()
|
|
||||||
|
|
||||||
# Then create the dictionary containing constructor_id: class
|
# Then create the dictionary containing constructor_id: class
|
||||||
builder.writeln('tlobjects = {')
|
builder.writeln('tlobjects = {')
|
||||||
builder.current_indent += 1
|
builder.current_indent += 1
|
||||||
|
|
||||||
# Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
|
# Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
|
||||||
for tlobject in tlobjects:
|
for tlobject in tlobjects:
|
||||||
constructor = hex(tlobject.id)
|
builder.write('{:#010x}: ', tlobject.id)
|
||||||
if len(constructor) != 10:
|
builder.write('functions' if tlobject.is_function else 'types')
|
||||||
# Make it a nice length 10 so it fits well
|
if tlobject.namespace:
|
||||||
constructor = '0x' + constructor[2:].zfill(8)
|
builder.write('.' + tlobject.namespace)
|
||||||
|
|
||||||
builder.write('{}: '.format(constructor))
|
builder.writeln('.{},', tlobject.class_name())
|
||||||
builder.write(
|
|
||||||
'functions' if tlobject.is_function else 'types')
|
|
||||||
|
|
||||||
if tlobject.namespace:
|
builder.current_indent -= 1
|
||||||
builder.write('.' + tlobject.namespace)
|
builder.writeln('}')
|
||||||
|
|
||||||
builder.writeln('.{},'.format(tlobject.class_name()))
|
|
||||||
|
|
||||||
builder.current_indent -= 1
|
|
||||||
builder.writeln('}')
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _write_init_py(out_dir, depth, namespace_tlobjects, type_constructors):
|
def _write_init_py(out_dir, depth, namespace_tlobjects, type_constructors):
|
||||||
|
@ -136,16 +131,17 @@ class TLGenerator:
|
||||||
# so they all can be serialized and sent, however, only the
|
# so they all can be serialized and sent, however, only the
|
||||||
# functions are "content_related".
|
# functions are "content_related".
|
||||||
builder.writeln(
|
builder.writeln(
|
||||||
'from {}.tl.tlobject import TLObject'.format('.' * depth)
|
'from {}.tl.tlobject import TLObject', '.' * depth
|
||||||
)
|
)
|
||||||
builder.writeln('from typing import Optional, List, Union, TYPE_CHECKING')
|
builder.writeln('from typing import Optional, List, '
|
||||||
|
'Union, TYPE_CHECKING')
|
||||||
|
|
||||||
# Add the relative imports to the namespaces,
|
# Add the relative imports to the namespaces,
|
||||||
# unless we already are in a namespace.
|
# unless we already are in a namespace.
|
||||||
if not ns:
|
if not ns:
|
||||||
builder.writeln('from . import {}'.format(', '.join(
|
builder.writeln('from . import {}', ', '.join(
|
||||||
x for x in namespace_tlobjects.keys() if x
|
x for x in namespace_tlobjects.keys() if x
|
||||||
)))
|
))
|
||||||
|
|
||||||
# Import 'os' for those needing access to 'os.urandom()'
|
# Import 'os' for those needing access to 'os.urandom()'
|
||||||
# Currently only 'random_id' needs 'os' to be imported,
|
# Currently only 'random_id' needs 'os' to be imported,
|
||||||
|
@ -204,18 +200,18 @@ class TLGenerator:
|
||||||
if name == 'date':
|
if name == 'date':
|
||||||
imports['datetime'] = ['datetime']
|
imports['datetime'] = ['datetime']
|
||||||
continue
|
continue
|
||||||
elif not import_space in imports:
|
elif import_space not in imports:
|
||||||
imports[import_space] = set()
|
imports[import_space] = set()
|
||||||
imports[import_space].add('Type{}'.format(name))
|
imports[import_space].add('Type{}'.format(name))
|
||||||
|
|
||||||
# Add imports required for type checking.
|
# Add imports required for type checking
|
||||||
builder.writeln('if TYPE_CHECKING:')
|
if imports:
|
||||||
for namespace, names in imports.items():
|
builder.writeln('if TYPE_CHECKING:')
|
||||||
builder.writeln('from {} import {}'.format(
|
for namespace, names in imports.items():
|
||||||
namespace, ', '.join(names)))
|
builder.writeln('from {} import {}',
|
||||||
else:
|
namespace, ', '.join(names))
|
||||||
builder.writeln('pass')
|
|
||||||
builder.end_block()
|
builder.end_block()
|
||||||
|
|
||||||
# Generate the class for every TLObject
|
# Generate the class for every TLObject
|
||||||
for t in tlobjects:
|
for t in tlobjects:
|
||||||
|
@ -229,25 +225,24 @@ class TLGenerator:
|
||||||
for line in type_defs:
|
for line in type_defs:
|
||||||
builder.writeln(line)
|
builder.writeln(line)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _write_source_code(tlobject, builder, depth, type_constructors):
|
def _write_source_code(tlobject, builder, depth, type_constructors):
|
||||||
"""Writes the source code corresponding to the given TLObject
|
"""
|
||||||
by making use of the 'builder' SourceBuilder.
|
Writes the source code corresponding to the given TLObject
|
||||||
|
by making use of the ``builder`` `SourceBuilder`.
|
||||||
|
|
||||||
Additional information such as file path depth and
|
Additional information such as file path depth and
|
||||||
the Type: [Constructors] must be given for proper
|
the ``Type: [Constructors]`` must be given for proper
|
||||||
importing and documentation strings.
|
importing and documentation strings.
|
||||||
"""
|
"""
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
builder.writeln('class {}(TLObject):'.format(tlobject.class_name()))
|
builder.writeln('class {}(TLObject):', tlobject.class_name())
|
||||||
|
|
||||||
# Class-level variable to store its Telegram's constructor ID
|
# Class-level variable to store its Telegram's constructor ID
|
||||||
builder.writeln('CONSTRUCTOR_ID = {}'.format(hex(tlobject.id)))
|
builder.writeln('CONSTRUCTOR_ID = {:#x}', tlobject.id)
|
||||||
builder.writeln('SUBCLASS_OF_ID = {}'.format(
|
builder.writeln('SUBCLASS_OF_ID = {:#x}',
|
||||||
hex(crc32(tlobject.result.encode('ascii'))))
|
crc32(tlobject.result.encode('ascii')))
|
||||||
)
|
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
|
|
||||||
# Flag arguments must go last
|
# Flag arguments must go last
|
||||||
|
@ -265,9 +260,7 @@ class TLGenerator:
|
||||||
|
|
||||||
# Write the __init__ function
|
# Write the __init__ function
|
||||||
if args:
|
if args:
|
||||||
builder.writeln(
|
builder.writeln('def __init__(self, {}):', ', '.join(args))
|
||||||
'def __init__(self, {}):'.format(', '.join(args))
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
builder.writeln('def __init__(self):')
|
builder.writeln('def __init__(self):')
|
||||||
|
|
||||||
|
@ -286,30 +279,27 @@ class TLGenerator:
|
||||||
builder.writeln('"""')
|
builder.writeln('"""')
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if not arg.flag_indicator:
|
if not arg.flag_indicator:
|
||||||
builder.writeln(':param {} {}:'.format(
|
builder.writeln(':param {} {}:',
|
||||||
arg.doc_type_hint(), arg.name
|
arg.doc_type_hint(), arg.name)
|
||||||
))
|
|
||||||
builder.current_indent -= 1 # It will auto-indent (':')
|
builder.current_indent -= 1 # It will auto-indent (':')
|
||||||
|
|
||||||
# We also want to know what type this request returns
|
# We also want to know what type this request returns
|
||||||
# or to which type this constructor belongs to
|
# or to which type this constructor belongs to
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
if tlobject.is_function:
|
if tlobject.is_function:
|
||||||
builder.write(':returns {}: '.format(tlobject.result))
|
builder.write(':returns {}: ', tlobject.result)
|
||||||
else:
|
else:
|
||||||
builder.write('Constructor for {}: '.format(tlobject.result))
|
builder.write('Constructor for {}: ', tlobject.result)
|
||||||
|
|
||||||
constructors = type_constructors[tlobject.result]
|
constructors = type_constructors[tlobject.result]
|
||||||
if not constructors:
|
if not constructors:
|
||||||
builder.writeln('This type has no constructors.')
|
builder.writeln('This type has no constructors.')
|
||||||
elif len(constructors) == 1:
|
elif len(constructors) == 1:
|
||||||
builder.writeln('Instance of {}.'.format(
|
builder.writeln('Instance of {}.',
|
||||||
constructors[0].class_name()
|
constructors[0].class_name())
|
||||||
))
|
|
||||||
else:
|
else:
|
||||||
builder.writeln('Instance of either {}.'.format(
|
builder.writeln('Instance of either {}.', ', '.join(
|
||||||
', '.join(c.class_name() for c in constructors)
|
c.class_name() for c in constructors))
|
||||||
))
|
|
||||||
|
|
||||||
builder.writeln('"""')
|
builder.writeln('"""')
|
||||||
|
|
||||||
|
@ -327,8 +317,8 @@ class TLGenerator:
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if not arg.can_be_inferred:
|
if not arg.can_be_inferred:
|
||||||
builder.writeln('self.{0} = {0} # type: {1}'.format(
|
builder.writeln('self.{0} = {0} # type: {1}',
|
||||||
arg.name, arg.python_type_hint()))
|
arg.name, arg.python_type_hint())
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Currently the only argument that can be
|
# Currently the only argument that can be
|
||||||
|
@ -350,7 +340,7 @@ class TLGenerator:
|
||||||
|
|
||||||
builder.writeln(
|
builder.writeln(
|
||||||
"self.random_id = random_id if random_id "
|
"self.random_id = random_id if random_id "
|
||||||
"is not None else {}".format(code)
|
"is not None else {}", code
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Cannot infer a value for ', arg)
|
raise ValueError('Cannot infer a value for ', arg)
|
||||||
|
@ -374,27 +364,27 @@ class TLGenerator:
|
||||||
base_types = ('string', 'bytes', 'int', 'long', 'int128',
|
base_types = ('string', 'bytes', 'int', 'long', 'int128',
|
||||||
'int256', 'double', 'Bool', 'true', 'date')
|
'int256', 'double', 'Bool', 'true', 'date')
|
||||||
|
|
||||||
builder.write("'_': '{}'".format(tlobject.class_name()))
|
builder.write("'_': '{}'", tlobject.class_name())
|
||||||
for arg in args:
|
for arg in args:
|
||||||
builder.writeln(',')
|
builder.writeln(',')
|
||||||
builder.write("'{}': ".format(arg.name))
|
builder.write("'{}': ", arg.name)
|
||||||
if arg.type in base_types:
|
if arg.type in base_types:
|
||||||
if arg.is_vector:
|
if arg.is_vector:
|
||||||
builder.write('[] if self.{0} is None else self.{0}[:]'
|
builder.write('[] if self.{0} is None else self.{0}[:]',
|
||||||
.format(arg.name))
|
arg.name)
|
||||||
else:
|
else:
|
||||||
builder.write('self.{}'.format(arg.name))
|
builder.write('self.{}', arg.name)
|
||||||
else:
|
else:
|
||||||
if arg.is_vector:
|
if arg.is_vector:
|
||||||
builder.write(
|
builder.write(
|
||||||
'[] if self.{0} is None else [None '
|
'[] if self.{0} is None else [None '
|
||||||
'if x is None else x.to_dict() for x in self.{0}]'
|
'if x is None else x.to_dict() for x in self.{0}]',
|
||||||
.format(arg.name)
|
arg.name
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
builder.write(
|
builder.write(
|
||||||
'None if self.{0} is None else self.{0}.to_dict()'
|
'None if self.{0} is None else self.{0}.to_dict()',
|
||||||
.format(arg.name)
|
arg.name
|
||||||
)
|
)
|
||||||
|
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
|
@ -421,17 +411,16 @@ class TLGenerator:
|
||||||
.format(a.name) for a in ra)
|
.format(a.name) for a in ra)
|
||||||
builder.writeln(
|
builder.writeln(
|
||||||
"assert ({}) or ({}), '{} parameters must all "
|
"assert ({}) or ({}), '{} parameters must all "
|
||||||
"be False-y (like None) or all me True-y'".format(
|
"be False-y (like None) or all me True-y'",
|
||||||
' and '.join(cnd1), ' and '.join(cnd2),
|
' and '.join(cnd1), ' and '.join(cnd2),
|
||||||
', '.join(a.name for a in ra)
|
', '.join(a.name for a in ra)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
builder.writeln("return b''.join((")
|
builder.writeln("return b''.join((")
|
||||||
builder.current_indent += 1
|
builder.current_indent += 1
|
||||||
|
|
||||||
# First constructor code, we already know its bytes
|
# First constructor code, we already know its bytes
|
||||||
builder.writeln('{},'.format(repr(struct.pack('<I', tlobject.id))))
|
builder.writeln('{},', repr(struct.pack('<I', tlobject.id)))
|
||||||
|
|
||||||
for arg in tlobject.args:
|
for arg in tlobject.args:
|
||||||
if TLGenerator.write_to_bytes(builder, arg, tlobject.args):
|
if TLGenerator.write_to_bytes(builder, arg, tlobject.args):
|
||||||
|
@ -449,12 +438,14 @@ class TLGenerator:
|
||||||
builder, arg, tlobject.args, name='_' + arg.name
|
builder, arg, tlobject.args, name='_' + arg.name
|
||||||
)
|
)
|
||||||
|
|
||||||
builder.writeln('return {}({})'.format(
|
builder.writeln(
|
||||||
tlobject.class_name(), ', '.join(
|
'return {}({})',
|
||||||
|
tlobject.class_name(),
|
||||||
|
', '.join(
|
||||||
'{0}=_{0}'.format(a.name) for a in tlobject.sorted_args()
|
'{0}=_{0}'.format(a.name) for a in tlobject.sorted_args()
|
||||||
if not a.flag_indicator and not a.generic_definition
|
if not a.flag_indicator and not a.generic_definition
|
||||||
)
|
)
|
||||||
))
|
)
|
||||||
|
|
||||||
# Only requests can have a different response that's not their
|
# Only requests can have a different response that's not their
|
||||||
# serialized body, that is, we'll be setting their .result.
|
# serialized body, that is, we'll be setting their .result.
|
||||||
|
@ -482,13 +473,13 @@ class TLGenerator:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _write_self_assign(builder, arg, get_input_code):
|
def _write_self_assign(builder, arg, get_input_code):
|
||||||
"""Writes self.arg = input.format(self.arg), considering vectors"""
|
"""Writes self.arg = input.format(self.arg), considering vectors."""
|
||||||
if arg.is_vector:
|
if arg.is_vector:
|
||||||
builder.write('self.{0} = [{1} for _x in self.{0}]'
|
builder.write('self.{0} = [{1} for _x in self.{0}]',
|
||||||
.format(arg.name, get_input_code.format('_x')))
|
arg.name, get_input_code.format('_x'))
|
||||||
else:
|
else:
|
||||||
builder.write('self.{} = {}'.format(
|
builder.write('self.{} = {}',
|
||||||
arg.name, get_input_code.format('self.' + arg.name)))
|
arg.name, get_input_code.format('self.' + arg.name))
|
||||||
|
|
||||||
builder.writeln(
|
builder.writeln(
|
||||||
' if self.{} else None'.format(arg.name) if arg.is_flag else ''
|
' if self.{} else None'.format(arg.name) if arg.is_flag else ''
|
||||||
|
@ -536,17 +527,17 @@ class TLGenerator:
|
||||||
# so we need an extra join here. Note that empty vector flags
|
# so we need an extra join here. Note that empty vector flags
|
||||||
# should NOT be sent either!
|
# should NOT be sent either!
|
||||||
builder.write("b'' if {0} is None or {0} is False "
|
builder.write("b'' if {0} is None or {0} is False "
|
||||||
"else b''.join((".format(name))
|
"else b''.join((", name)
|
||||||
else:
|
else:
|
||||||
builder.write("b'' if {0} is None or {0} is False "
|
builder.write("b'' if {0} is None or {0} is False "
|
||||||
"else (".format(name))
|
"else (", name)
|
||||||
|
|
||||||
if arg.is_vector:
|
if arg.is_vector:
|
||||||
if arg.use_vector_id:
|
if arg.use_vector_id:
|
||||||
# vector code, unsigned 0x1cb5c415 as little endian
|
# vector code, unsigned 0x1cb5c415 as little endian
|
||||||
builder.write(r"b'\x15\xc4\xb5\x1c',")
|
builder.write(r"b'\x15\xc4\xb5\x1c',")
|
||||||
|
|
||||||
builder.write("struct.pack('<i', len({})),".format(name))
|
builder.write("struct.pack('<i', len({})),", name)
|
||||||
|
|
||||||
# Cannot unpack the values for the outer tuple through *[(
|
# Cannot unpack the values for the outer tuple through *[(
|
||||||
# since that's a Python >3.5 feature, so add another join.
|
# since that's a Python >3.5 feature, so add another join.
|
||||||
|
@ -560,7 +551,7 @@ class TLGenerator:
|
||||||
arg.is_vector = True
|
arg.is_vector = True
|
||||||
arg.is_flag = old_flag
|
arg.is_flag = old_flag
|
||||||
|
|
||||||
builder.write(' for x in {})'.format(name))
|
builder.write(' for x in {})', name)
|
||||||
|
|
||||||
elif arg.flag_indicator:
|
elif arg.flag_indicator:
|
||||||
# Calculate the flags with those items which are not None
|
# Calculate the flags with those items which are not None
|
||||||
|
@ -579,41 +570,39 @@ class TLGenerator:
|
||||||
|
|
||||||
elif 'int' == arg.type:
|
elif 'int' == arg.type:
|
||||||
# struct.pack is around 4 times faster than int.to_bytes
|
# struct.pack is around 4 times faster than int.to_bytes
|
||||||
builder.write("struct.pack('<i', {})".format(name))
|
builder.write("struct.pack('<i', {})", name)
|
||||||
|
|
||||||
elif 'long' == arg.type:
|
elif 'long' == arg.type:
|
||||||
builder.write("struct.pack('<q', {})".format(name))
|
builder.write("struct.pack('<q', {})", name)
|
||||||
|
|
||||||
elif 'int128' == arg.type:
|
elif 'int128' == arg.type:
|
||||||
builder.write("{}.to_bytes(16, 'little', signed=True)".format(name))
|
builder.write("{}.to_bytes(16, 'little', signed=True)", name)
|
||||||
|
|
||||||
elif 'int256' == arg.type:
|
elif 'int256' == arg.type:
|
||||||
builder.write("{}.to_bytes(32, 'little', signed=True)".format(name))
|
builder.write("{}.to_bytes(32, 'little', signed=True)", name)
|
||||||
|
|
||||||
elif 'double' == arg.type:
|
elif 'double' == arg.type:
|
||||||
builder.write("struct.pack('<d', {})".format(name))
|
builder.write("struct.pack('<d', {})", name)
|
||||||
|
|
||||||
elif 'string' == arg.type:
|
elif 'string' == arg.type:
|
||||||
builder.write('TLObject.serialize_bytes({})'.format(name))
|
builder.write('TLObject.serialize_bytes({})', name)
|
||||||
|
|
||||||
elif 'Bool' == arg.type:
|
elif 'Bool' == arg.type:
|
||||||
# 0x997275b5 if boolean else 0xbc799737
|
# 0x997275b5 if boolean else 0xbc799737
|
||||||
builder.write(
|
builder.write(r"b'\xb5ur\x99' if {} else b'7\x97y\xbc'", name)
|
||||||
r"b'\xb5ur\x99' if {} else b'7\x97y\xbc'".format(name)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif 'true' == arg.type:
|
elif 'true' == arg.type:
|
||||||
pass # These are actually NOT written! Only used for flags
|
pass # These are actually NOT written! Only used for flags
|
||||||
|
|
||||||
elif 'bytes' == arg.type:
|
elif 'bytes' == arg.type:
|
||||||
builder.write('TLObject.serialize_bytes({})'.format(name))
|
builder.write('TLObject.serialize_bytes({})', name)
|
||||||
|
|
||||||
elif 'date' == arg.type: # Custom format
|
elif 'date' == arg.type: # Custom format
|
||||||
builder.write('TLObject.serialize_datetime({})'.format(name))
|
builder.write('TLObject.serialize_datetime({})', name)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Else it may be a custom type
|
# Else it may be a custom type
|
||||||
builder.write('bytes({})'.format(name))
|
builder.write('bytes({})', name)
|
||||||
|
|
||||||
if arg.is_flag:
|
if arg.is_flag:
|
||||||
builder.write(')')
|
builder.write(')')
|
||||||
|
@ -646,15 +635,12 @@ class TLGenerator:
|
||||||
# Treat 'true' flags as a special case, since they're true if
|
# Treat 'true' flags as a special case, since they're true if
|
||||||
# they're set, and nothing else needs to actually be read.
|
# they're set, and nothing else needs to actually be read.
|
||||||
if 'true' == arg.type:
|
if 'true' == arg.type:
|
||||||
builder.writeln(
|
builder.writeln('{} = bool(flags & {})',
|
||||||
'{} = bool(flags & {})'.format(name, 1 << arg.flag_index)
|
name, 1 << arg.flag_index)
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
was_flag = True
|
was_flag = True
|
||||||
builder.writeln('if flags & {}:'.format(
|
builder.writeln('if flags & {}:', 1 << arg.flag_index)
|
||||||
1 << arg.flag_index
|
|
||||||
))
|
|
||||||
# Temporary disable .is_flag not to enter this if
|
# Temporary disable .is_flag not to enter this if
|
||||||
# again when calling the method recursively
|
# again when calling the method recursively
|
||||||
arg.is_flag = False
|
arg.is_flag = False
|
||||||
|
@ -664,12 +650,12 @@ class TLGenerator:
|
||||||
# We have to read the vector's constructor ID
|
# We have to read the vector's constructor ID
|
||||||
builder.writeln("reader.read_int()")
|
builder.writeln("reader.read_int()")
|
||||||
|
|
||||||
builder.writeln('{} = []'.format(name))
|
builder.writeln('{} = []', name)
|
||||||
builder.writeln('for _ in range(reader.read_int()):')
|
builder.writeln('for _ in range(reader.read_int()):')
|
||||||
# Temporary disable .is_vector, not to enter this if again
|
# Temporary disable .is_vector, not to enter this if again
|
||||||
arg.is_vector = False
|
arg.is_vector = False
|
||||||
TLGenerator.write_read_code(builder, arg, args, name='_x')
|
TLGenerator.write_read_code(builder, arg, args, name='_x')
|
||||||
builder.writeln('{}.append(_x)'.format(name))
|
builder.writeln('{}.append(_x)', name)
|
||||||
arg.is_vector = True
|
arg.is_vector = True
|
||||||
|
|
||||||
elif arg.flag_indicator:
|
elif arg.flag_indicator:
|
||||||
|
@ -678,44 +664,40 @@ class TLGenerator:
|
||||||
builder.writeln()
|
builder.writeln()
|
||||||
|
|
||||||
elif 'int' == arg.type:
|
elif 'int' == arg.type:
|
||||||
builder.writeln('{} = reader.read_int()'.format(name))
|
builder.writeln('{} = reader.read_int()', name)
|
||||||
|
|
||||||
elif 'long' == arg.type:
|
elif 'long' == arg.type:
|
||||||
builder.writeln('{} = reader.read_long()'.format(name))
|
builder.writeln('{} = reader.read_long()', name)
|
||||||
|
|
||||||
elif 'int128' == arg.type:
|
elif 'int128' == arg.type:
|
||||||
builder.writeln(
|
builder.writeln('{} = reader.read_large_int(bits=128)', name)
|
||||||
'{} = reader.read_large_int(bits=128)'.format(name)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif 'int256' == arg.type:
|
elif 'int256' == arg.type:
|
||||||
builder.writeln(
|
builder.writeln('{} = reader.read_large_int(bits=256)', name)
|
||||||
'{} = reader.read_large_int(bits=256)'.format(name)
|
|
||||||
)
|
|
||||||
|
|
||||||
elif 'double' == arg.type:
|
elif 'double' == arg.type:
|
||||||
builder.writeln('{} = reader.read_double()'.format(name))
|
builder.writeln('{} = reader.read_double()', name)
|
||||||
|
|
||||||
elif 'string' == arg.type:
|
elif 'string' == arg.type:
|
||||||
builder.writeln('{} = reader.tgread_string()'.format(name))
|
builder.writeln('{} = reader.tgread_string()', name)
|
||||||
|
|
||||||
elif 'Bool' == arg.type:
|
elif 'Bool' == arg.type:
|
||||||
builder.writeln('{} = reader.tgread_bool()'.format(name))
|
builder.writeln('{} = reader.tgread_bool()', name)
|
||||||
|
|
||||||
elif 'true' == arg.type:
|
elif 'true' == arg.type:
|
||||||
# Arbitrary not-None value, don't actually read "true" flags
|
# Arbitrary not-None value, don't actually read "true" flags
|
||||||
builder.writeln('{} = True'.format(name))
|
builder.writeln('{} = True', name)
|
||||||
|
|
||||||
elif 'bytes' == arg.type:
|
elif 'bytes' == arg.type:
|
||||||
builder.writeln('{} = reader.tgread_bytes()'.format(name))
|
builder.writeln('{} = reader.tgread_bytes()', name)
|
||||||
|
|
||||||
elif 'date' == arg.type: # Custom format
|
elif 'date' == arg.type: # Custom format
|
||||||
builder.writeln('{} = reader.tgread_date()'.format(name))
|
builder.writeln('{} = reader.tgread_date()', name)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Else it may be a custom type
|
# Else it may be a custom type
|
||||||
if not arg.skip_constructor_id:
|
if not arg.skip_constructor_id:
|
||||||
builder.writeln('{} = reader.tgread_object()'.format(name))
|
builder.writeln('{} = reader.tgread_object()', name)
|
||||||
else:
|
else:
|
||||||
# Import the correct type inline to avoid cyclic imports.
|
# Import the correct type inline to avoid cyclic imports.
|
||||||
# There may be better solutions so that we can just access
|
# There may be better solutions so that we can just access
|
||||||
|
@ -732,10 +714,9 @@ class TLGenerator:
|
||||||
# file with the same namespace, but since it does no harm
|
# file with the same namespace, but since it does no harm
|
||||||
# and we don't have information about such thing in the
|
# and we don't have information about such thing in the
|
||||||
# method we just ignore that case.
|
# method we just ignore that case.
|
||||||
builder.writeln('from {} import {}'.format(ns, class_name))
|
builder.writeln('from {} import {}', ns, class_name)
|
||||||
builder.writeln('{} = {}.from_reader(reader)'.format(
|
builder.writeln('{} = {}.from_reader(reader)',
|
||||||
name, class_name
|
name, class_name)
|
||||||
))
|
|
||||||
|
|
||||||
# End vector and flag blocks if required (if we opened them before)
|
# End vector and flag blocks if required (if we opened them before)
|
||||||
if arg.is_vector:
|
if arg.is_vector:
|
||||||
|
@ -744,7 +725,7 @@ class TLGenerator:
|
||||||
if was_flag:
|
if was_flag:
|
||||||
builder.current_indent -= 1
|
builder.current_indent -= 1
|
||||||
builder.writeln('else:')
|
builder.writeln('else:')
|
||||||
builder.writeln('{} = None'.format(name))
|
builder.writeln('{} = None', name)
|
||||||
builder.current_indent -= 1
|
builder.current_indent -= 1
|
||||||
# Restore .is_flag
|
# Restore .is_flag
|
||||||
arg.is_flag = True
|
arg.is_flag = True
|
||||||
|
|
Loading…
Reference in New Issue
Block a user