From 477fbd8dc7ead4fb46479b0a4289bab3d8e021fe Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Tue, 16 Oct 2018 09:29:48 +0200 Subject: [PATCH] Generate simple examples for the docs --- telethon_generator/data/html/core.html | 23 +++-- telethon_generator/docswriter.py | 9 +- telethon_generator/generators/docs.py | 25 +++++- telethon_generator/parsers/tlobject/tlarg.py | 84 +++++++++++++++++++ .../parsers/tlobject/tlobject.py | 39 +++++++++ 5 files changed, 168 insertions(+), 12 deletions(-) diff --git a/telethon_generator/data/html/core.html b/telethon_generator/data/html/core.html index b55bb7de..95d600ee 100644 --- a/telethon_generator/data/html/core.html +++ b/telethon_generator/data/html/core.html @@ -59,8 +59,8 @@ users.getUsers#0d91a548 id:Vector<InputUser> = Vector<User>

This is not Python code. It's the "TL definition". It's an easy-to-read line that gives a quick overview on the parameters and its result. You don't need to worry about this. See - here - for more details on it.

+ Understanding + the Type Language for more details on it.

Index

Full example

-

Documentation for this is now - here. +

All methods shown here have dummy examples on how to write them, + so you don't get confused with their TL definition. However, this may + not always run. They are just there to show the right syntax.

+ +

You should check out + how + to access the full API in ReadTheDocs.

diff --git a/telethon_generator/docswriter.py b/telethon_generator/docswriter.py index 4b0929bd..87783d83 100644 --- a/telethon_generator/docswriter.py +++ b/telethon_generator/docswriter.py @@ -95,11 +95,16 @@ class DocsWriter: raise RuntimeError('No menu had been started in the first place.') self.write('') - def write_title(self, title, level=1): + def write_title(self, title, level=1, id=None): """Writes a title header in the document body, with an optional depth level """ - self.write('{title}', title=title, level=level) + if id: + self.write('{title}', + title=title, lv=level, id=id) + else: + self.write('{title}', + title=title, lv=level) def write_code(self, tlobject): """Writes the code for the given 'tlobject' properly diff --git a/telethon_generator/generators/docs.py b/telethon_generator/generators/docs.py index ea42ddaf..836ae89f 100755 --- a/telethon_generator/generators/docs.py +++ b/telethon_generator/generators/docs.py @@ -297,7 +297,8 @@ def _write_html_pages(tlobjects, errors, layer, input_res, output_dir): docs.write_title(tlobject.class_name) if tlobject.is_function: - docs.write_text('Bots can{} use this method.' + docs.write_text('Bots can{} use this method. ' + 'See code examples.' .format("" if tlobject.bot_usable else "'t")) if tlobject.is_function and tlobject.bot_usable: bot_docs_paths.append(filename) @@ -410,6 +411,28 @@ def _write_html_pages(tlobjects, errors, layer, input_res, output_dir): docs.write_text('You can import these from ' 'telethon.errors.') + docs.write_title('Example', id='examples') + docs.write( + '
from telethon.sync import TelegramClient\n'
+                    'from telethon import functions, types\n'
+                    '\n'
+                    'with TelegramClient(name, api_id, api_hash) as client:\n'
+                    '    result = client(')
+                tlobject.as_example(docs, indent=1)
+                docs.write(')\n')
+                if tlobject.result.startswith('Vector'):
+                    docs.write(
+                        '    for x in result:\n'
+                        '        print(x'
+                    )
+                else:
+                    docs.write('    print(result')
+                    if tlobject.result != 'Bool' \
+                            and not tlobject.result.startswith('Vector'):
+                        docs.write('.stringify()')
+
+                docs.write(')
') + depth = '../' * (2 if tlobject.namespace else 1) docs.add_script(src='prependPath = "{}";'.format(depth)) docs.add_script(relative_src=paths['search.js']) diff --git a/telethon_generator/parsers/tlobject/tlarg.py b/telethon_generator/parsers/tlobject/tlarg.py index f3808ad4..ff7decbb 100644 --- a/telethon_generator/parsers/tlobject/tlarg.py +++ b/telethon_generator/parsers/tlobject/tlarg.py @@ -1,6 +1,64 @@ import re +KNOWN_NAMED_EXAMPLES = { + ('peer', 'InputPeer'): "'TelethonOffTopic'", + ('channel', 'InputChannel'): "'TelethonOffTopic'", + ('user_id', 'InputUser'): "'Lonami'", + ('users', 'InputUser'): "'Lonami'", + ('message', 'string'): "'Hello there!'", + ('expires_at', 'date'): 'datetime.timedelta(minutes=5)', + ('until_date', 'date'): 'datetime.timedelta(days=14)', + ('view_messages', 'true'): 'None', + ('send_messages', 'true'): 'None', + ('limit', 'int'): '100', + ('hash', 'int'): '0', + ('hash', 'string'): "'A4LmkR23G0IGxBE71zZfo1'", + ('min_id', 'int'): '0', + ('max_id', 'int'): '0', + ('add_offset', 'int'): '0', + ('title', 'string'): "'My awesome title'", + ('device_model', 'string'): "'ASUS Laptop'", + ('system_version', 'string'): "'Arch Linux'", + ('app_version', 'string'): "'1.0'", + ('system_lang_code', 'string'): "'en'", + ('lang_pack', 'string'): "''", + ('lang_code', 'string'): "'en'", + ('chat_id', 'int'): '478614198' +} + +KNOWN_TYPED_EXAMPLES = { + 'int128': "int.from_bytes(os.urandom(16), 'big')", + 'bytes': "b'arbitrary\\x7f data \\xfa here'", + 'long': "-12398745604826", + 'string': "'some string here'", + 'int': '42', + 'date': 'datetime.datetime(2018, 6, 25)', + 'double': '7.13', + 'Bool': 'False', + 'true': 'True', + 'InputChatPhoto': "client.upload_file('/path/to/photo.jpg')" +} + +# These are flags that are cleaner to leave off +OMITTED_EXAMPLES = { + 'silent', + 'background', + 'clear_draft', + 'reply_to_msg_id', + 'random_id', + 'reply_markup', + 'entities', + 'embed_links', + 'hash', + 'min_id', + 'max_id', + 'add_offset', + 'grouped', + 'broadcast' +} + + class TLArg: def __init__(self, name, arg_type, generic_definition): """ @@ -131,3 +189,29 @@ class TLArg: 'name': self.name.replace('is_self', 'self'), 'type': re.sub(r'\bdate$', 'int', self.real_type()) } + + def as_example(self, f, indent=0): + if self.is_generic: + f.write('other_request') + return + + known = (KNOWN_NAMED_EXAMPLES.get((self.name, self.type)) + or KNOWN_TYPED_EXAMPLES.get(self.type)) + if known: + f.write(known) + return + + assert self.omit_example() or self.cls, 'TODO handle ' + str(self) + + # Pick an interesting example if any + for cls in self.cls: + if cls.is_good_example(): + cls.as_example(f, indent) + break + else: + # If no example is good, just pick the first + self.cls[0].as_example(f, indent) + + def omit_example(self): + return (self.is_flag or self.can_be_inferred) \ + and self.name in OMITTED_EXAMPLES diff --git a/telethon_generator/parsers/tlobject/tlobject.py b/telethon_generator/parsers/tlobject/tlobject.py index 76f46fa3..2dd45a2e 100644 --- a/telethon_generator/parsers/tlobject/tlobject.py +++ b/telethon_generator/parsers/tlobject/tlobject.py @@ -102,3 +102,42 @@ class TLObject: 'type': self.result } + + def is_good_example(self): + return not self.class_name.endswith('Empty') + + def as_example(self, f, indent=0): + f.write('functions' if self.is_function else 'types') + if self.namespace: + f.write('.') + f.write(self.namespace) + + f.write('.') + f.write(self.class_name) + f.write('(') + + args = [arg for arg in self.real_args if not arg.omit_example()] + if not args: + f.write(')') + return + + f.write('\n') + indent += 1 + remaining = len(args) + for arg in args: + remaining -= 1 + f.write(' ' * indent) + f.write(arg.name) + f.write('=') + if arg.is_vector: + f.write('[') + arg.as_example(f, indent) + if arg.is_vector: + f.write(']') + if remaining: + f.write(',') + f.write('\n') + + indent -= 1 + f.write(' ' * indent) + f.write(')')