Get rid of the patched/ module

This may fix #1669.
This commit is contained in:
Lonami Exo 2021-01-14 22:56:01 +01:00
parent c0738a7ae1
commit cd51c9e47c
3 changed files with 22 additions and 57 deletions

1
.gitignore vendored
View File

@ -1,7 +1,6 @@
# Generated code # Generated code
/telethon/tl/functions/ /telethon/tl/functions/
/telethon/tl/types/ /telethon/tl/types/
/telethon/tl/patched/
/telethon/tl/alltlobjects.py /telethon/tl/alltlobjects.py
/telethon/errors/rpcerrorlist.py /telethon/errors/rpcerrorlist.py

View File

@ -1,16 +1,15 @@
import abc
from .chatgetter import ChatGetter from .chatgetter import ChatGetter
from .sendergetter import SenderGetter from .sendergetter import SenderGetter
from .messagebutton import MessageButton from .messagebutton import MessageButton
from .forward import Forward from .forward import Forward
from .file import File from .file import File
from .. import TLObject, types, functions from .. import TLObject, types, functions, alltlobjects
from ... import utils, errors from ... import utils, errors
# TODO Figure out a way to have the code generator error on missing fields # TODO Figure out a way to have the code generator error on missing fields
# Maybe parsing the init function alone if that's possible. # 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 This custom class aggregates both :tl:`Message` and
:tl:`MessageService` to ease accessing their members. :tl:`MessageService` to ease accessing their members.
@ -1105,3 +1104,18 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
return None return None
# endregion Private Methods # 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)

View File

@ -50,13 +50,6 @@ NAMED_BLACKLIST = {
BASE_TYPES = ('string', 'bytes', 'int', 'long', 'int128', BASE_TYPES = ('string', 'bytes', 'int', 'long', 'int128',
'int256', 'double', 'Bool', 'true', 'date') '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( def _write_modules(
out_dir, depth, kind, namespace_tlobjects, type_constructors): out_dir, depth, kind, namespace_tlobjects, type_constructors):
@ -157,11 +150,8 @@ def _write_modules(
# Generate the class for every TLObject # Generate the class for every TLObject
for t in tlobjects: for t in tlobjects:
if t.fullname in PATCHED_TYPES: _write_source_code(t, kind, builder, type_constructors)
builder.writeln('{} = None # Patched', t.class_name) builder.current_indent = 0
else:
_write_source_code(t, kind, builder, type_constructors)
builder.current_indent = 0
# Write the type definitions generated earlier. # Write the type definitions generated earlier.
builder.writeln() builder.writeln()
@ -645,41 +635,11 @@ def _write_arg_read_code(builder, arg, args, name):
arg.is_flag = True 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): def _write_all_tlobjects(tlobjects, layer, builder):
builder.writeln(AUTO_GEN_NOTICE) builder.writeln(AUTO_GEN_NOTICE)
builder.writeln() builder.writeln()
builder.writeln('from . import types, functions, patched') builder.writeln('from . import types, functions')
builder.writeln() builder.writeln()
# Create a constant variable to indicate which layer this is # 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) # Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
for tlobject in tlobjects: for tlobject in tlobjects:
builder.write('{:#010x}: ', tlobject.id) builder.write('{:#010x}: ', tlobject.id)
# TODO Probably circular dependency builder.write('functions' if tlobject.is_function else 'types')
if tlobject.fullname in PATCHED_TYPES:
builder.write('patched')
else:
builder.write('functions' if tlobject.is_function else 'types')
if tlobject.namespace: if tlobject.namespace:
builder.write('.{}', 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 # Group everything by {namespace: [tlobjects]} to generate __init__.py
namespace_functions = defaultdict(list) namespace_functions = defaultdict(list)
namespace_types = defaultdict(list) namespace_types = defaultdict(list)
namespace_patched = defaultdict(list)
# Group {type: [constructors]} to generate the documentation # Group {type: [constructors]} to generate the documentation
type_constructors = defaultdict(list) type_constructors = defaultdict(list)
@ -722,14 +677,11 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir):
else: else:
namespace_types[tlobject.namespace].append(tlobject) namespace_types[tlobject.namespace].append(tlobject)
type_constructors[tlobject.result].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', _write_modules(output_dir / 'functions', import_depth, 'TLRequest',
namespace_functions, type_constructors) namespace_functions, type_constructors)
_write_modules(output_dir / 'types', import_depth, 'TLObject', _write_modules(output_dir / 'types', import_depth, 'TLObject',
namespace_types, type_constructors) namespace_types, type_constructors)
_write_patched(output_dir / 'patched', namespace_patched)
filename = output_dir / 'alltlobjects.py' filename = output_dir / 'alltlobjects.py'
with filename.open('w') as file: with filename.open('w') as file:
@ -738,7 +690,7 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir):
def clean_tlobjects(output_dir): def clean_tlobjects(output_dir):
for d in ('functions', 'types', 'patched'): for d in ('functions', 'types'):
d = output_dir / d d = output_dir / d
if d.is_dir(): if d.is_dir():
shutil.rmtree(str(d)) shutil.rmtree(str(d))