Support converting .tl -> .json

This commit is contained in:
Lonami Exo 2018-06-13 10:48:35 +02:00
parent d4dc147459
commit f3f0c28505
2 changed files with 56 additions and 12 deletions

View File

@ -61,13 +61,13 @@ def generate(which):
generate_errors, generate_tlobjects, generate_docs, clean_tlobjects generate_errors, generate_tlobjects, generate_docs, clean_tlobjects
with open(INVALID_BM_IN) as f: with open(INVALID_BM_IN) as f:
ib = set(json.load(f)) invalid_bot_methods = set(json.load(f))
layer = find_layer(TLOBJECT_IN_TL) layer = find_layer(TLOBJECT_IN_TL)
errors = list(parse_errors(ERRORS_IN_JSON, ERRORS_IN_DESC)) errors = list(parse_errors(ERRORS_IN_JSON, ERRORS_IN_DESC))
tlobjects = list(itertools.chain( tlobjects = list(itertools.chain(
parse_tl(TLOBJECT_IN_CORE_TL, layer=layer, invalid_bot_methods=ib), parse_tl(TLOBJECT_IN_CORE_TL, layer, invalid_bot_methods),
parse_tl(TLOBJECT_IN_TL, layer=layer, invalid_bot_methods=ib))) parse_tl(TLOBJECT_IN_TL, layer, invalid_bot_methods)))
if not which: if not which:
which.extend(('tl', 'errors')) which.extend(('tl', 'errors'))
@ -110,6 +110,31 @@ def generate(which):
else: else:
generate_docs(tlobjects, errors, layer, DOCS_IN_RES, DOCS_OUT) generate_docs(tlobjects, errors, layer, DOCS_IN_RES, DOCS_OUT)
if 'json' in which:
which.remove('json')
print(action, 'JSON schema...')
mtproto = 'mtproto_api.json'
telegram = 'telegram_api.json'
if clean:
for x in (mtproto, telegram):
if os.path.isfile(x):
os.remove(x)
else:
def gen_json(fin, fout):
methods = []
constructors = []
for tl in parse_tl(fin, layer):
if tl.is_function:
methods.append(tl.to_dict())
else:
constructors.append(tl.to_dict())
what = {'constructors': constructors, 'methods': methods}
with open(fout, 'w') as f:
json.dump(what, f, indent=2)
gen_json(TLOBJECT_IN_CORE_TL, mtproto)
gen_json(TLOBJECT_IN_TL, telegram)
if which: if which:
print('The following items were not understood:', which) print('The following items were not understood:', which)
print(' Consider using only "tl", "errors" and/or "docs".') print(' Consider using only "tl", "errors" and/or "docs".')

View File

@ -1,4 +1,5 @@
import re import re
import struct
from zlib import crc32 from zlib import crc32
from ..utils import snake_to_camel_case from ..utils import snake_to_camel_case
@ -99,6 +100,18 @@ class TLObject:
) )
return crc32(representation.encode('ascii')) return crc32(representation.encode('ascii'))
def to_dict(self):
return {
'id':
str(struct.unpack('i', struct.pack('I', self.id))[0]),
'method' if self.is_function else 'predicate':
self.fullname,
'params':
[x.to_dict() for x in self.args if not x.generic_definition],
'type':
self.result
}
class TLArg: class TLArg:
def __init__(self, name, arg_type, generic_definition): def __init__(self, name, arg_type, generic_definition):
@ -194,7 +207,7 @@ class TLArg:
return result return result
def __str__(self): def real_type(self):
# Find the real type representation by updating it as required # Find the real type representation by updating it as required
real_type = self.type real_type = self.type
if self.flag_indicator: if self.flag_indicator:
@ -212,14 +225,23 @@ class TLArg:
if self.is_flag: if self.is_flag:
real_type = 'flags.{}?{}'.format(self.flag_index, real_type) real_type = 'flags.{}?{}'.format(self.flag_index, real_type)
return real_type
def __str__(self):
if self.generic_definition: if self.generic_definition:
return '{{{}:{}}}'.format(self.name, real_type) return '{{{}:{}}}'.format(self.name, self.real_type())
else: else:
return '{}:{}'.format(self.name, real_type) return '{}:{}'.format(self.name, self.real_type())
def __repr__(self): def __repr__(self):
return str(self).replace(':date', ':int').replace('?date', '?int') return str(self).replace(':date', ':int').replace('?date', '?int')
def to_dict(self):
return {
'name': self.name.replace('is_self', 'self'),
'type': re.sub(r'\bdate$', 'int', self.real_type())
}
def _from_line(line, is_function, layer): def _from_line(line, is_function, layer):
match = re.match( match = re.match(
@ -253,7 +275,7 @@ def _from_line(line, is_function, layer):
) )
def parse_tl(file_path, layer, ignore_core=False, invalid_bot_methods=None): def parse_tl(file_path, layer, invalid_bot_methods=None):
"""This method yields TLObjects from a given .tl file.""" """This method yields TLObjects from a given .tl file."""
if invalid_bot_methods is None: if invalid_bot_methods is None:
invalid_bot_methods = set() invalid_bot_methods = set()
@ -277,11 +299,8 @@ def parse_tl(file_path, layer, ignore_core=False, invalid_bot_methods=None):
try: try:
result = _from_line(line, is_function, layer=layer) result = _from_line(line, is_function, layer=layer)
if not ignore_core or result.id not in CORE_TYPES: result.bot_usable = result.fullname not in invalid_bot_methods
result.bot_usable =\ yield result
result.fullname not in invalid_bot_methods
yield result
except ValueError as e: except ValueError as e:
if 'vector#1cb5c415' not in str(e): if 'vector#1cb5c415' not in str(e):
raise raise