diff --git a/setup.py b/setup.py index 2112dd6e..a4ffd497 100755 --- a/setup.py +++ b/setup.py @@ -61,13 +61,13 @@ def generate(which): generate_errors, generate_tlobjects, generate_docs, clean_tlobjects 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) errors = list(parse_errors(ERRORS_IN_JSON, ERRORS_IN_DESC)) tlobjects = list(itertools.chain( - parse_tl(TLOBJECT_IN_CORE_TL, layer=layer, invalid_bot_methods=ib), - parse_tl(TLOBJECT_IN_TL, layer=layer, invalid_bot_methods=ib))) + parse_tl(TLOBJECT_IN_CORE_TL, layer, invalid_bot_methods), + parse_tl(TLOBJECT_IN_TL, layer, invalid_bot_methods))) if not which: which.extend(('tl', 'errors')) @@ -110,6 +110,31 @@ def generate(which): else: 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: print('The following items were not understood:', which) print(' Consider using only "tl", "errors" and/or "docs".') diff --git a/telethon_generator/parsers/tlobject.py b/telethon_generator/parsers/tlobject.py index d3e60f88..4c26f893 100644 --- a/telethon_generator/parsers/tlobject.py +++ b/telethon_generator/parsers/tlobject.py @@ -1,4 +1,5 @@ import re +import struct from zlib import crc32 from ..utils import snake_to_camel_case @@ -99,6 +100,18 @@ class TLObject: ) 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: def __init__(self, name, arg_type, generic_definition): @@ -194,7 +207,7 @@ class TLArg: return result - def __str__(self): + def real_type(self): # Find the real type representation by updating it as required real_type = self.type if self.flag_indicator: @@ -212,14 +225,23 @@ class TLArg: if self.is_flag: real_type = 'flags.{}?{}'.format(self.flag_index, real_type) + return real_type + + def __str__(self): if self.generic_definition: - return '{{{}:{}}}'.format(self.name, real_type) + return '{{{}:{}}}'.format(self.name, self.real_type()) else: - return '{}:{}'.format(self.name, real_type) + return '{}:{}'.format(self.name, self.real_type()) def __repr__(self): 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): 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.""" if invalid_bot_methods is None: invalid_bot_methods = set() @@ -277,11 +299,8 @@ def parse_tl(file_path, layer, ignore_core=False, invalid_bot_methods=None): try: 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 - - yield result + result.bot_usable = result.fullname not in invalid_bot_methods + yield result except ValueError as e: if 'vector#1cb5c415' not in str(e): raise