diff --git a/.gitignore b/.gitignore index dbfd60b5..6f2cf6f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # Generated code /telethon/tl/functions/ /telethon/tl/types/ -/telethon/tl/patched/ /telethon/tl/alltlobjects.py /telethon/errors/rpcerrorlist.py diff --git a/telethon/tl/custom/message.py b/telethon/tl/custom/message.py index d7203a03..f93c6b0d 100644 --- a/telethon/tl/custom/message.py +++ b/telethon/tl/custom/message.py @@ -1,16 +1,15 @@ -import abc from .chatgetter import ChatGetter from .sendergetter import SenderGetter from .messagebutton import MessageButton from .forward import Forward from .file import File -from .. import TLObject, types, functions +from .. import TLObject, types, functions, alltlobjects from ... import utils, errors # TODO Figure out a way to have the code generator error on missing fields # Maybe parsing the init function alone if that's possible. -class Message(ChatGetter, SenderGetter, TLObject, abc.ABC): +class _Message(ChatGetter, SenderGetter): """ This custom class aggregates both :tl:`Message` and :tl:`MessageService` to ease accessing their members. @@ -1105,3 +1104,18 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC): return None # endregion Private Methods + +def _patch(cls): + # Create new types (classes) for all messages to combine `_Message` in them. + # `_Message` comes first so we get its `__init__`. + newtype = type(cls.__name__, (_Message, cls), {}) + setattr(types, cls.__name__, newtype) + # `BinaryReader` directly imports this dictionary, but we're mutating it + # in-place, not replacing it, so it works out to deserialize `newtype`. + alltlobjects.tlobjects[cls.CONSTRUCTOR_ID] = newtype + return newtype + + +_patch(types.MessageEmpty) +Message = _patch(types.Message) +_patch(types.MessageService) diff --git a/telethon_generator/generators/tlobject.py b/telethon_generator/generators/tlobject.py index e18be176..c37ce603 100644 --- a/telethon_generator/generators/tlobject.py +++ b/telethon_generator/generators/tlobject.py @@ -50,13 +50,6 @@ NAMED_BLACKLIST = { BASE_TYPES = ('string', 'bytes', 'int', 'long', 'int128', 'int256', 'double', 'Bool', 'true', 'date') -# Patched types {fullname: custom.ns.Name} -PATCHED_TYPES = { - 'messageEmpty': 'message.Message', - 'message': 'message.Message', - 'messageService': 'message.Message' -} - def _write_modules( out_dir, depth, kind, namespace_tlobjects, type_constructors): @@ -157,11 +150,8 @@ def _write_modules( # Generate the class for every TLObject for t in tlobjects: - if t.fullname in PATCHED_TYPES: - builder.writeln('{} = None # Patched', t.class_name) - else: - _write_source_code(t, kind, builder, type_constructors) - builder.current_indent = 0 + _write_source_code(t, kind, builder, type_constructors) + builder.current_indent = 0 # Write the type definitions generated earlier. builder.writeln() @@ -645,41 +635,11 @@ def _write_arg_read_code(builder, arg, args, name): arg.is_flag = True -def _write_patched(out_dir, namespace_tlobjects): - out_dir.mkdir(parents=True, exist_ok=True) - for ns, tlobjects in namespace_tlobjects.items(): - file = out_dir / '{}.py'.format(ns or '__init__') - with file.open('w') as f, SourceBuilder(f) as builder: - builder.writeln(AUTO_GEN_NOTICE) - - builder.writeln('import struct') - builder.writeln('from .. import TLObject, types, custom') - builder.writeln() - for t in tlobjects: - builder.writeln('class {}(custom.{}):', t.class_name, - PATCHED_TYPES[t.fullname]) - - builder.writeln('CONSTRUCTOR_ID = {:#x}', t.id) - builder.writeln('SUBCLASS_OF_ID = {:#x}', - crc32(t.result.encode('ascii'))) - - _write_to_dict(t, builder) - _write_to_bytes(t, builder) - _write_from_reader(t, builder) - builder.current_indent = 0 - builder.writeln() - builder.writeln( - 'types.{1}{0} = {0}', t.class_name, - '{}.'.format(t.namespace) if t.namespace else '' - ) - builder.writeln() - - def _write_all_tlobjects(tlobjects, layer, builder): builder.writeln(AUTO_GEN_NOTICE) builder.writeln() - builder.writeln('from . import types, functions, patched') + builder.writeln('from . import types, functions') builder.writeln() # Create a constant variable to indicate which layer this is @@ -693,11 +653,7 @@ def _write_all_tlobjects(tlobjects, layer, builder): # Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class) for tlobject in tlobjects: builder.write('{:#010x}: ', tlobject.id) - # TODO Probably circular dependency - if tlobject.fullname in PATCHED_TYPES: - builder.write('patched') - else: - builder.write('functions' if tlobject.is_function else 'types') + builder.write('functions' if tlobject.is_function else 'types') if tlobject.namespace: builder.write('.{}', tlobject.namespace) @@ -712,7 +668,6 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir): # Group everything by {namespace: [tlobjects]} to generate __init__.py namespace_functions = defaultdict(list) namespace_types = defaultdict(list) - namespace_patched = defaultdict(list) # Group {type: [constructors]} to generate the documentation type_constructors = defaultdict(list) @@ -722,14 +677,11 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir): else: namespace_types[tlobject.namespace].append(tlobject) type_constructors[tlobject.result].append(tlobject) - if tlobject.fullname in PATCHED_TYPES: - namespace_patched[tlobject.namespace].append(tlobject) _write_modules(output_dir / 'functions', import_depth, 'TLRequest', namespace_functions, type_constructors) _write_modules(output_dir / 'types', import_depth, 'TLObject', namespace_types, type_constructors) - _write_patched(output_dir / 'patched', namespace_patched) filename = output_dir / 'alltlobjects.py' with filename.open('w') as file: @@ -738,7 +690,7 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir): def clean_tlobjects(output_dir): - for d in ('functions', 'types', 'patched'): + for d in ('functions', 'types'): d = output_dir / d if d.is_dir(): shutil.rmtree(str(d))