Generate simple examples for the docs

This commit is contained in:
Lonami Exo 2018-10-16 09:29:48 +02:00
parent 8f04ec820f
commit 477fbd8dc7
5 changed files with 168 additions and 12 deletions

View File

@ -59,8 +59,8 @@ users.getUsers#0d91a548 id:Vector&lt;InputUser&gt; = Vector&lt;User&gt;</pre>
<p>This is <b>not</b> 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
<a href="http://telethon.readthedocs.io/en/latest/extra/developing/understanding-the-type-language.html">here</a>
for more details on it.</p>
<a href="https://telethon.readthedocs.io/en/latest/extra/developing/understanding-the-type-language.html">Understanding
the Type Language</a> for more details on it.</p>
<h3>Index</h3>
<ul>
@ -82,7 +82,7 @@ users.getUsers#0d91a548 id:Vector&lt;InputUser&gt; = Vector&lt;User&gt;</pre>
<h3 id="methods">Methods</h3>
<p>Currently there are <b>{method_count} methods</b> available for the layer
{layer}. The complete list can be seen <a href="methods/index.html">here</a>.
{layer}. <a href="methods/index.html">See the complete method list</a>.
<br /><br />
Methods, also known as <i>requests</i>, are used to interact with the
Telegram API itself and are invoked through <code>client(Request(...))</code>.
@ -92,8 +92,8 @@ users.getUsers#0d91a548 id:Vector&lt;InputUser&gt; = Vector&lt;User&gt;</pre>
some dialogs, users, etc.</p>
<h3 id="types">Types</h3>
<p>Currently there are <b>{type_count} types</b>. You can see the full
list <a href="types/index.html">here</a>.</p>
<p>Currently there are <b>{type_count} types</b>.
<a href="types/index.html">See the complete list of types</a>.</p>
<p>The Telegram types are the <i>abstract</i> results that you receive
after invoking a request. They are "abstract" because they can have
@ -106,8 +106,8 @@ users.getUsers#0d91a548 id:Vector&lt;InputUser&gt; = Vector&lt;User&gt;</pre>
an instance of it by using one of its, possibly multiple, constructors.</p>
<h3 id="constructors">Constructors</h3>
<p>Currently there are <b>{constructor_count} constructors</b>. You can see
the full list <a href="constructors/index.html">here</a>.</p>
<p>Currently there are <b>{constructor_count} constructors</b>.
<a href="constructors/index.html">See the list of all constructors</a>.</p>
<p>Constructors are the way you can create instances of the abstract types
described above, and also the instances which are actually returned from
@ -170,8 +170,13 @@ users.getUsers#0d91a548 id:Vector&lt;InputUser&gt; = Vector&lt;User&gt;</pre>
</ul>
<h3 id="example">Full example</h3>
<p>Documentation for this is now
<a href="http://telethon.readthedocs.io/en/latest/extra/advanced-usage/accessing-the-full-api.html">here</a>.
<p>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.</p>
<p>You should check out
<a href="http://telethon.readthedocs.io/en/latest/extra/advanced-usage/accessing-the-full-api.html">how
to access the full API</a> in ReadTheDocs.
</p>
</div>
<script src="js/search.js"></script>

View File

@ -95,11 +95,16 @@ class DocsWriter:
raise RuntimeError('No menu had been started in the first place.')
self.write('</ul>')
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('<h{level}>{title}</h{level}>', title=title, level=level)
if id:
self.write('<h{lv} id="{id}">{title}</h{lv}>',
title=title, lv=level, id=id)
else:
self.write('<h{lv}>{title}</h{lv}>',
title=title, lv=level)
def write_code(self, tlobject):
"""Writes the code for the given 'tlobject' properly

View File

@ -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 <strong>can{}</strong> use this method.'
docs.write_text('Bots <strong>can{}</strong> use this method. '
'<a href="#examples">See code examples.</a>'
.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 '
'<code>telethon.errors</code>.')
docs.write_title('Example', id='examples')
docs.write(
'<pre>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(')</pre>')
depth = '../' * (2 if tlobject.namespace else 1)
docs.add_script(src='prependPath = "{}";'.format(depth))
docs.add_script(relative_src=paths['search.js'])

View File

@ -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

View File

@ -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(')')