diff --git a/docs/generate.py b/docs/generate.py index 834fab10..1b467727 100755 --- a/docs/generate.py +++ b/docs/generate.py @@ -290,9 +290,11 @@ def generate_documentation(scheme_file): 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) - args = sorted([a for a in tlobject.args if - not a.flag_indicator and not a.generic_definition], - key=lambda a: a.is_flag) + args = [ + a for a in tlobject.sorted_args() + if not a.flag_indicator and not a.generic_definition + ] + if args: # Writing parameters docs.begin_table(column_count=3) @@ -312,6 +314,8 @@ def generate_documentation(scheme_file): # 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: diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index 8bd8ad02..4deb98cd 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -408,15 +408,14 @@ class TelegramClient(TelegramBareClient): no_web_page=False): """Sends a message to the given entity (or input peer) and returns the sent message ID""" - msg_id = utils.generate_random_long() - self.invoke( - SendMessageRequest( - peer=get_input_peer(entity), - message=message, - random_id=msg_id, - entities=[], - no_webpage=no_web_page)) - return msg_id + request = SendMessageRequest( + peer=get_input_peer(entity), + message=message, + entities=[], + no_webpage=no_web_page + ) + self.invoke(request) + return request.random_id def get_message_history(self, entity, @@ -520,11 +519,10 @@ class TelegramClient(TelegramBareClient): def send_media_file(self, input_media, entity): """Sends any input_media (contact, document, photo...) to the given entity""" - self.invoke( - SendMediaRequest( - peer=get_input_peer(entity), - media=input_media, - random_id=utils.generate_random_long())) + self.invoke(SendMediaRequest( + peer=get_input_peer(entity), + media=input_media + )) # endregion diff --git a/telethon_generator/parser/tl_object.py b/telethon_generator/parser/tl_object.py index f531c7ff..3d83d192 100644 --- a/telethon_generator/parser/tl_object.py +++ b/telethon_generator/parser/tl_object.py @@ -78,6 +78,14 @@ class TLObject: result=match.group(3), 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): """Determines whether the TLObject is a "core type" (and thus should be embedded in the generated code) or not""" @@ -134,6 +142,12 @@ class TLArg: self.is_flag = False 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 if arg_type == '#': self.flag_indicator = True diff --git a/telethon_generator/tl_generator.py b/telethon_generator/tl_generator.py index 31d36cc9..2e118a10 100755 --- a/telethon_generator/tl_generator.py +++ b/telethon_generator/tl_generator.py @@ -108,12 +108,18 @@ class TLGenerator: 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 {}.tl.mtproto_request import MTProtoRequest' .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('class {}(MTProtoRequest):'.format( @@ -134,16 +140,17 @@ class TLGenerator: 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 = [ + a for a in tlobject.sorted_args() + if not a.flag_indicator and not a.generic_definition + ] # 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 = [ + (a.name if not a.is_flag and not a.can_be_inferred + else '{}=None'.format(a.name)) + for a in args + ] # Write the __init__ function if args: @@ -209,8 +216,26 @@ class TLGenerator: if args: # Leave an empty line if there are any args builder.writeln() - for arg in args: - builder.writeln('self.{0} = {0}'.format(arg.name)) + + for arg in args: + 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() # Write the on_send(self, writer) function