Added a script to implement missing methods from Telegram website

This commit is contained in:
Davte 2020-04-26 19:14:24 +02:00
parent b0a2770177
commit 45ff81afbc

View File

@ -1,6 +1,7 @@
"""Get and parse Telegram API webpage.""" """Get and parse Telegram API web page."""
# Standard library modules # Standard library modules
import argparse
import asyncio import asyncio
import logging import logging
@ -8,10 +9,20 @@ import logging
import aiohttp import aiohttp
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
# Project modules
from . import api
api_url = "https://core.telegram.org/bots/api" api_url = "https://core.telegram.org/bots/api"
class TelegramApiMethod(object): class TelegramApiMethod(object):
types = {
'Array of String': "List[str]",
'Boolean': "bool",
'Integer': "int",
'Integer or String': "Union[int, str]",
'String': "str",
}
"""Telegram bot API method.""" """Telegram bot API method."""
def __init__(self, name, description, table): def __init__(self, name, description, table):
@ -19,6 +30,7 @@ class TelegramApiMethod(object):
self._name = name self._name = name
self._description = description self._description = description
self._table = table self._table = table
self._parameters = self.get_parameters_from_table()
@property @property
def name(self): def name(self):
@ -35,7 +47,18 @@ class TelegramApiMethod(object):
"""Return method parameters table.""" """Return method parameters table."""
return self._table return self._table
def get_parameters_from_table(self): @property
def parameters(self):
return self._parameters
@property
def parameters_with_types(self):
return [
f"{parameter['name']}: {parameter['type']}"
for parameter in self._parameters
]
def print_parameters_table(self):
"""Extract parameters from API table.""" """Extract parameters from API table."""
result = '' result = ''
if self.table is None: if self.table is None:
@ -54,11 +77,35 @@ class TelegramApiMethod(object):
result += '\n' result += '\n'
return result return result
def get_parameters_from_table(self):
if self.table is None:
return []
parameters = []
rows = self.table.tbody.find_all('tr') or []
for row in rows:
columns = row.find_all('td') or []
name, type_, *_ = map(lambda column: column.text.strip(), columns)
if type_ in self.types:
type_ = self.types[type_]
else:
type_ = f"'{type_}'"
parameters.append(
dict(
name=name,
type=type_
)
)
return parameters
async def main(loop=None, filename=None):
"""Get information from Telegram bot API webpage.""" async def print_api_methods(loop=None,
filename=None,
print_all=False,
output_file=None):
"""Get information from Telegram bot API web page."""
if loop is None: if loop is None:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
implemented_methods = dir(api.TelegramBot)
async with aiohttp.ClientSession( async with aiohttp.ClientSession(
loop=loop, loop=loop,
timeout=aiohttp.ClientTimeout( timeout=aiohttp.ClientTimeout(
@ -68,14 +115,15 @@ async def main(loop=None, filename=None):
async with session.get( async with session.get(
api_url api_url
) as response: ) as response:
webpage = BeautifulSoup( web_page = BeautifulSoup(
await response.text(), await response.text(),
"html.parser" "html.parser"
) )
if filename is not None: if filename is not None:
with open(filename, 'w') as _file: with open(filename, 'w') as _file:
_file.write(webpage.decode()) _file.write(web_page.decode())
for method in webpage.find_all("h4"): methods = []
for method in web_page.find_all("h4"):
method_name = method.text method_name = method.text
description = '' description = ''
parameters_table = None parameters_table = None
@ -89,18 +137,83 @@ async def main(loop=None, filename=None):
break # Stop searching in siblings if <table> is found break # Stop searching in siblings if <table> is found
description += tag.get_text() description += tag.get_text()
if method_name and method_name[0] == method_name[0].lower(): if method_name and method_name[0] == method_name[0].lower():
method = TelegramApiMethod( methods.append(
method_name, description, parameters_table TelegramApiMethod(
method_name,
description,
parameters_table
) )
)
new_line = '\n'
if output_file:
with open(output_file, 'w') as file:
file.write(
"from typing import List, Union\n"
"from davtelepot.api import TelegramBot\n"
"self = TelegramBot('fake_token')\n\n\n"
)
file.writelines(
f"async def {method.name}("
f"{', '.join(method.parameters_with_types)}"
"):\n"
" \"\"\""
f"{method.description.replace(new_line, new_line + ' ' * 4)}\n"
" See https://core.telegram.org/bots/api#"
f"{method.name.lower()} for details.\n"
" \"\"\"\n"
" return await self.api_request(\n"
f" '{method.name}',\n"
" parameters=locals()\n"
" )\n\n\n"
for method in methods
if print_all or method.name not in implemented_methods
)
else:
print( print(
"NAME\n\t{m.name}\n" '\n'.join(
"DESCRIPTION\n\t{m.description}\n" f"NAME\n\t{method.name}\n"
f"TABLE\n\t{method.get_parameters_from_table()}\n\n".format( f"PARAMETERS\n\t{', '.join(method.parameters_with_types)}\n"
m=method f"DESCRIPTION\n\t{method.description}\n"
f"TABLE\n\t{method.print_parameters_table()}\n\n"
for method in methods
if print_all or method.name not in implemented_methods
) )
) )
if __name__ == '__main__':
def main():
cli_parser = argparse.ArgumentParser(
description='Get Telegram API methods information from telegram '
'website.\n'
'Implement missing (or --all) methods in --out file, '
'or print methods information.',
allow_abbrev=False,
)
cli_parser.add_argument('--file', '-f', '--filename', type=str,
default=None,
required=False,
help='File path to store Telegram API web page')
cli_parser.add_argument('--all', '-a',
action='store_true',
help='Print all methods (default: print missing '
'methods only)')
cli_parser.add_argument('--out', '--output', '-o', type=str,
default=None,
required=False,
help='File path to store methods implementation')
cli_arguments = vars(cli_parser.parse_args())
filename = cli_arguments['file']
print_all = cli_arguments['all']
output_file = cli_arguments['out']
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop=loop, filename='prova.txt')) loop.run_until_complete(
print_api_methods(loop=loop,
filename=filename,
print_all=print_all,
output_file=output_file)
)
logging.info("Done!") logging.info("Done!")
if __name__ == '__main__':
main()