Automatically infer the value for 'random_id' parameters

This commit is contained in:
Lonami Exo 2017-06-11 19:16:59 +02:00
parent 3ed59d08e5
commit 1ca41b5854
4 changed files with 68 additions and 27 deletions

View File

@ -290,9 +290,11 @@ def generate_documentation(scheme_file):
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 = sorted([a for a in tlobject.args if args = [
not a.flag_indicator and not a.generic_definition], a for a in tlobject.sorted_args()
key=lambda a: a.is_flag) if not a.flag_indicator and not a.generic_definition
]
if args: if args:
# Writing parameters # Writing parameters
docs.begin_table(column_count=3) docs.begin_table(column_count=3)
@ -312,6 +314,8 @@ def generate_documentation(scheme_file):
# Create a description for this argument # Create a description for this argument
description = '' description = ''
if arg.can_be_inferred:
description += 'If left to None, it will be inferred automatically. '
if arg.is_vector: if arg.is_vector:
description += 'A list must be supplied for this argument. ' description += 'A list must be supplied for this argument. '
if arg.is_generic: if arg.is_generic:

View File

@ -408,15 +408,14 @@ class TelegramClient(TelegramBareClient):
no_web_page=False): no_web_page=False):
"""Sends a message to the given entity (or input peer) """Sends a message to the given entity (or input peer)
and returns the sent message ID""" and returns the sent message ID"""
msg_id = utils.generate_random_long() request = SendMessageRequest(
self.invoke(
SendMessageRequest(
peer=get_input_peer(entity), peer=get_input_peer(entity),
message=message, message=message,
random_id=msg_id,
entities=[], entities=[],
no_webpage=no_web_page)) no_webpage=no_web_page
return msg_id )
self.invoke(request)
return request.random_id
def get_message_history(self, def get_message_history(self,
entity, entity,
@ -520,11 +519,10 @@ class TelegramClient(TelegramBareClient):
def send_media_file(self, input_media, entity): def send_media_file(self, input_media, entity):
"""Sends any input_media (contact, document, photo...) to the given entity""" """Sends any input_media (contact, document, photo...) to the given entity"""
self.invoke( self.invoke(SendMediaRequest(
SendMediaRequest(
peer=get_input_peer(entity), peer=get_input_peer(entity),
media=input_media, media=input_media
random_id=utils.generate_random_long())) ))
# endregion # endregion

View File

@ -78,6 +78,14 @@ class TLObject:
result=match.group(3), result=match.group(3),
is_function=is_function) is_function=is_function)
def sorted_args(self):
"""Returns the arguments properly sorted and ready to plug-in
into a Python's method header (i.e., flags and those which
can be inferred will go last so they can default =None)
"""
return sorted(self.args,
key=lambda x: x.is_flag or x.can_be_inferred)
def is_core_type(self): def is_core_type(self):
"""Determines whether the TLObject is a "core type" """Determines whether the TLObject is a "core type"
(and thus should be embedded in the generated code) or not""" (and thus should be embedded in the generated code) or not"""
@ -134,6 +142,12 @@ class TLArg:
self.is_flag = False self.is_flag = False
self.flag_index = -1 self.flag_index = -1
# Special case: some types can be inferred, which makes it
# less annoying to type. Currently the only type that can
# be inferred is if the name is 'random_id', to which a
# random ID will be assigned if left as None (the default)
self.can_be_inferred = name == 'random_id'
# The type can be an indicator that other arguments will be flags # The type can be an indicator that other arguments will be flags
if arg_type == '#': if arg_type == '#':
self.flag_indicator = True self.flag_indicator = True

View File

@ -108,12 +108,18 @@ class TLGenerator:
out_dir, out_dir,
TLGenerator.get_file_name( TLGenerator.get_file_name(
tlobject, add_extension=True)) tlobject, add_extension=True))
with open(filename, 'w', encoding='utf-8') as file: with open(filename, 'w', encoding='utf-8') as file:
# Let's build the source code! # Let's build the source code!
with SourceBuilder(file) as builder: with SourceBuilder(file) as builder:
# Both types and functions inherit from MTProtoRequest so they all can be sent # Both types and functions inherit from MTProtoRequest so they all can be sent
builder.writeln('from {}.tl.mtproto_request import MTProtoRequest' builder.writeln('from {}.tl.mtproto_request import MTProtoRequest'
.format('.' * depth)) .format('.' * depth))
if any(a for a in tlobject.args if a.can_be_inferred):
# Currently only 'random_id' needs 'os' to be imported
builder.writeln('import os')
builder.writeln() builder.writeln()
builder.writeln() builder.writeln()
builder.writeln('class {}(MTProtoRequest):'.format( builder.writeln('class {}(MTProtoRequest):'.format(
@ -134,16 +140,17 @@ class TLGenerator:
builder.writeln() builder.writeln()
# First sort the arguments so that those not being a flag come first # First sort the arguments so that those not being a flag come first
args = sorted( args = [
[arg for arg in tlobject.args a for a in tlobject.sorted_args()
if not arg.flag_indicator], if not a.flag_indicator and not a.generic_definition
key=lambda x: x.is_flag) ]
# Then convert the args to string parameters, the flags having =None # Then convert the args to string parameters, the flags having =None
args = [(arg.name if not arg.is_flag else args = [
'{}=None'.format(arg.name)) for arg in args (a.name if not a.is_flag and not a.can_be_inferred
if not arg.flag_indicator and else '{}=None'.format(a.name))
not arg.generic_definition] for a in args
]
# Write the __init__ function # Write the __init__ function
if args: if args:
@ -209,8 +216,26 @@ class TLGenerator:
if args: if args:
# Leave an empty line if there are any args # Leave an empty line if there are any args
builder.writeln() builder.writeln()
for arg in args: for arg in args:
builder.writeln('self.{0} = {0}'.format(arg.name)) if arg.can_be_inferred:
# Currently the only argument that can be
# inferred are those called 'random_id'
if arg.name == 'random_id':
builder.writeln(
"self.random_id = random_id if random_id "
"is not None else int.from_bytes("
"os.urandom({}), signed=True, "
"byteorder='little')"
.format(8 if arg.type == 'long' else 4)
)
else:
raise ValueError(
'Cannot infer a value for ', arg)
else:
builder.writeln('self.{0} = {0}'
.format(arg.name))
builder.end_block() builder.end_block()
# Write the on_send(self, writer) function # Write the on_send(self, writer) function