mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-28 06:31:13 +03:00 
			
		
		
		
	Subclass TLRequest for content-related objects
This commit is contained in:
		
							parent
							
								
									d1afc70963
								
							
						
					
					
						commit
						3f16c92eb3
					
				|  | @ -3,17 +3,17 @@ import itertools | |||
| 
 | ||||
| from .telegrambaseclient import TelegramBaseClient | ||||
| from .. import errors, utils | ||||
| from ..tl import TLObject, types, functions | ||||
| from ..tl import TLObject, TLRequest, types, functions | ||||
| 
 | ||||
| 
 | ||||
| _NOT_A_REQUEST = TypeError('You can only invoke requests, not types!') | ||||
| 
 | ||||
| 
 | ||||
| class UserMethods(TelegramBaseClient): | ||||
|     async def __call__(self, request, retries=5, ordered=False): | ||||
|         requests = (request,) if not utils.is_list_like(request) else request | ||||
|         if not all(isinstance(x, TLObject) and | ||||
|                    x.content_related for x in requests): | ||||
|             raise TypeError('You can only invoke requests, not types!') | ||||
| 
 | ||||
|         for r in requests: | ||||
|         for r in (request if utils.is_list_like(request) else (request,)): | ||||
|             if not isinstance(r, TLRequest): | ||||
|                 raise _NOT_A_REQUEST | ||||
|             await r.resolve(self, utils) | ||||
| 
 | ||||
|         for _ in range(retries): | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ from ..crypto import AES | |||
| from ..errors import SecurityError, BrokenAuthKeyError | ||||
| from ..extensions import BinaryReader | ||||
| from ..tl.core import TLMessage | ||||
| from ..tl.tlobject import TLRequest | ||||
| 
 | ||||
| __log__ = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -43,7 +44,7 @@ class MTProtoState: | |||
|         """ | ||||
|         return TLMessage( | ||||
|             msg_id=self._get_new_msg_id(), | ||||
|             seq_no=self._get_seq_no(obj.content_related), | ||||
|             seq_no=self._get_seq_no(isinstance(obj, TLRequest)), | ||||
|             obj=obj, | ||||
|             after_id=after.msg_id if after else None | ||||
|         ) | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| from .tlobject import TLObject | ||||
| from .tlobject import TLObject, TLRequest | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import gzip | ||||
| import struct | ||||
| 
 | ||||
| from .. import TLObject | ||||
| from .. import TLObject, TLRequest | ||||
| 
 | ||||
| 
 | ||||
| class GzipPacked(TLObject): | ||||
|  | @ -21,7 +21,7 @@ class GzipPacked(TLObject): | |||
|         """ | ||||
|         data = bytes(request) | ||||
|         # TODO This threshold could be configurable | ||||
|         if request.content_related and len(data) > 512: | ||||
|         if isinstance(request, TLRequest) and len(data) > 512: | ||||
|             gzipped = bytes(GzipPacked(data)) | ||||
|             return gzipped if len(gzipped) < len(data) else data | ||||
|         else: | ||||
|  |  | |||
|  | @ -11,13 +11,10 @@ class MessageContainer(TLObject): | |||
|     CONSTRUCTOR_ID = 0x73f1f8dc | ||||
| 
 | ||||
|     def __init__(self, messages): | ||||
|         super().__init__() | ||||
|         self.content_related = False | ||||
|         self.messages = messages | ||||
| 
 | ||||
|     def to_dict(self, recursive=True): | ||||
|         return { | ||||
|             'content_related': self.content_related, | ||||
|             'messages': | ||||
|                 ([] if self.messages is None else [ | ||||
|                     None if x is None else x.to_dict() for x in self.messages | ||||
|  |  | |||
|  | @ -3,16 +3,11 @@ from datetime import datetime, date | |||
| 
 | ||||
| 
 | ||||
| class TLObject: | ||||
|     def __init__(self): | ||||
|         # TODO Perhaps content_related makes more sense as another type? | ||||
|         # Something like class TLRequest(TLObject), request inherit this | ||||
|         self.content_related = False  # Only requests/functions/queries are | ||||
| 
 | ||||
|     # These should not be overrode | ||||
|     @staticmethod | ||||
|     def pretty_format(obj, indent=None): | ||||
|         """Pretty formats the given object as a string which is returned. | ||||
|            If indent is None, a single line will be returned. | ||||
|         """ | ||||
|         Pretty formats the given object as a string which is returned. | ||||
|         If indent is None, a single line will be returned. | ||||
|         """ | ||||
|         if indent is None: | ||||
|             if isinstance(obj, TLObject): | ||||
|  | @ -136,11 +131,6 @@ class TLObject: | |||
| 
 | ||||
|         raise TypeError('Cannot interpret "{}" as a date.'.format(dt)) | ||||
| 
 | ||||
|     # These are nearly always the same for all subclasses | ||||
|     @staticmethod | ||||
|     def read_result(reader): | ||||
|         return reader.tgread_object() | ||||
| 
 | ||||
|     def __eq__(self, o): | ||||
|         return isinstance(o, type(self)) and self.to_dict() == o.to_dict() | ||||
| 
 | ||||
|  | @ -153,16 +143,24 @@ class TLObject: | |||
|     def stringify(self): | ||||
|         return TLObject.pretty_format(self, indent=0) | ||||
| 
 | ||||
|     # These should be overrode | ||||
|     async def resolve(self, client, utils): | ||||
|         pass | ||||
| 
 | ||||
|     def to_dict(self): | ||||
|         return {} | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     def __bytes__(self): | ||||
|         return b'' | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
|     @classmethod | ||||
|     def from_reader(cls, reader): | ||||
|         return TLObject() | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| 
 | ||||
| class TLRequest(TLObject): | ||||
|     """ | ||||
|     Represents a content-related `TLObject` (a request that can be sent). | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def read_result(reader): | ||||
|         return reader.tgread_object() | ||||
| 
 | ||||
|     async def resolve(self, client, utils): | ||||
|         pass | ||||
|  |  | |||
|  | @ -32,7 +32,8 @@ BASE_TYPES = ('string', 'bytes', 'int', 'long', 'int128', | |||
|               'int256', 'double', 'Bool', 'true', 'date') | ||||
| 
 | ||||
| 
 | ||||
| def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | ||||
| def _write_modules( | ||||
|         out_dir, depth, kind, namespace_tlobjects, type_constructors): | ||||
|     # namespace_tlobjects: {'namespace', [TLObject]} | ||||
|     os.makedirs(out_dir, exist_ok=True) | ||||
|     for ns, tlobjects in namespace_tlobjects.items(): | ||||
|  | @ -41,7 +42,7 @@ def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | |||
|                 SourceBuilder(f) as builder: | ||||
|             builder.writeln(AUTO_GEN_NOTICE) | ||||
| 
 | ||||
|             builder.writeln('from {}.tl.tlobject import TLObject', '.' * depth) | ||||
|             builder.writeln('from {}.tl.tlobject import {}', '.' * depth, kind) | ||||
|             builder.writeln('from typing import Optional, List, ' | ||||
|                             'Union, TYPE_CHECKING') | ||||
| 
 | ||||
|  | @ -124,7 +125,7 @@ def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | |||
| 
 | ||||
|             # Generate the class for every TLObject | ||||
|             for t in tlobjects: | ||||
|                 _write_source_code(t, builder, type_constructors) | ||||
|                 _write_source_code(t, kind, builder, type_constructors) | ||||
|                 builder.current_indent = 0 | ||||
| 
 | ||||
|             # Write the type definitions generated earlier. | ||||
|  | @ -133,7 +134,7 @@ def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | |||
|                 builder.writeln(line) | ||||
| 
 | ||||
| 
 | ||||
| def _write_source_code(tlobject, builder, type_constructors): | ||||
| def _write_source_code(tlobject, kind, builder, type_constructors): | ||||
|     """ | ||||
|     Writes the source code corresponding to the given TLObject | ||||
|     by making use of the ``builder`` `SourceBuilder`. | ||||
|  | @ -142,7 +143,7 @@ def _write_source_code(tlobject, builder, type_constructors): | |||
|     the ``Type: [Constructors]`` must be given for proper | ||||
|     importing and documentation strings. | ||||
|     """ | ||||
|     _write_class_init(tlobject, type_constructors, builder) | ||||
|     _write_class_init(tlobject, kind, type_constructors, builder) | ||||
|     _write_resolve(tlobject, builder) | ||||
|     _write_to_dict(tlobject, builder) | ||||
|     _write_to_bytes(tlobject, builder) | ||||
|  | @ -150,10 +151,10 @@ def _write_source_code(tlobject, builder, type_constructors): | |||
|     _write_read_result(tlobject, builder) | ||||
| 
 | ||||
| 
 | ||||
| def _write_class_init(tlobject, type_constructors, builder): | ||||
| def _write_class_init(tlobject, kind, type_constructors, builder): | ||||
|     builder.writeln() | ||||
|     builder.writeln() | ||||
|     builder.writeln('class {}(TLObject):', tlobject.class_name) | ||||
|     builder.writeln('class {}({}):', tlobject.class_name, kind) | ||||
| 
 | ||||
|     # Class-level variable to store its Telegram's constructor ID | ||||
|     builder.writeln('CONSTRUCTOR_ID = {:#x}', tlobject.id) | ||||
|  | @ -165,46 +166,39 @@ def _write_class_init(tlobject, type_constructors, builder): | |||
|     args = [(a.name if not a.is_flag and not a.can_be_inferred | ||||
|              else '{}=None'.format(a.name)) for a in tlobject.real_args] | ||||
| 
 | ||||
|     # Write the __init__ function | ||||
|     # Write the __init__ function if it has any argument | ||||
|     if not tlobject.real_args: | ||||
|         return | ||||
| 
 | ||||
|     builder.writeln('def __init__({}):', ', '.join(['self'] + args)) | ||||
|     if tlobject.real_args: | ||||
|         # Write the docstring, to know the type of the args | ||||
|         builder.writeln('"""') | ||||
|         for arg in tlobject.real_args: | ||||
|             if not arg.flag_indicator: | ||||
|                 builder.writeln(':param {} {}:', arg.type_hint(), arg.name) | ||||
|                 builder.current_indent -= 1  # It will auto-indent (':') | ||||
|     # Write the docstring, to know the type of the args | ||||
|     builder.writeln('"""') | ||||
|     for arg in tlobject.real_args: | ||||
|         if not arg.flag_indicator: | ||||
|             builder.writeln(':param {} {}:', arg.type_hint(), arg.name) | ||||
|             builder.current_indent -= 1  # It will auto-indent (':') | ||||
| 
 | ||||
|         # We also want to know what type this request returns | ||||
|         # or to which type this constructor belongs to | ||||
|         builder.writeln() | ||||
|         if tlobject.is_function: | ||||
|             builder.write(':returns {}: ', tlobject.result) | ||||
|         else: | ||||
|             builder.write('Constructor for {}: ', tlobject.result) | ||||
| 
 | ||||
|         constructors = type_constructors[tlobject.result] | ||||
|         if not constructors: | ||||
|             builder.writeln('This type has no constructors.') | ||||
|         elif len(constructors) == 1: | ||||
|             builder.writeln('Instance of {}.', | ||||
|                             constructors[0].class_name) | ||||
|         else: | ||||
|             builder.writeln('Instance of either {}.', ', '.join( | ||||
|                 c.class_name for c in constructors)) | ||||
| 
 | ||||
|         builder.writeln('"""') | ||||
| 
 | ||||
|     builder.writeln('super().__init__()') | ||||
|     # Functions have a result object and are confirmed by default | ||||
|     # We also want to know what type this request returns | ||||
|     # or to which type this constructor belongs to | ||||
|     builder.writeln() | ||||
|     if tlobject.is_function: | ||||
|         builder.writeln('self.result = None') | ||||
|         builder.writeln('self.content_related = True') | ||||
|         builder.write(':returns {}: ', tlobject.result) | ||||
|     else: | ||||
|         builder.write('Constructor for {}: ', tlobject.result) | ||||
| 
 | ||||
|     constructors = type_constructors[tlobject.result] | ||||
|     if not constructors: | ||||
|         builder.writeln('This type has no constructors.') | ||||
|     elif len(constructors) == 1: | ||||
|         builder.writeln('Instance of {}.', | ||||
|                         constructors[0].class_name) | ||||
|     else: | ||||
|         builder.writeln('Instance of either {}.', ', '.join( | ||||
|             c.class_name for c in constructors)) | ||||
| 
 | ||||
|     builder.writeln('"""') | ||||
| 
 | ||||
|     # Set the arguments | ||||
|     if tlobject.real_args: | ||||
|         builder.writeln() | ||||
| 
 | ||||
|     for arg in tlobject.real_args: | ||||
|         if not arg.can_be_inferred: | ||||
|             builder.writeln('self.{0} = {0}  # type: {1}', | ||||
|  | @ -453,7 +447,7 @@ def _write_arg_to_bytes(builder, arg, args, name=None): | |||
|         builder.write("struct.pack('<d', {})", name) | ||||
| 
 | ||||
|     elif 'string' == arg.type: | ||||
|         builder.write('TLObject.serialize_bytes({})', name) | ||||
|         builder.write('self.serialize_bytes({})', name) | ||||
| 
 | ||||
|     elif 'Bool' == arg.type: | ||||
|         # 0x997275b5 if boolean else 0xbc799737 | ||||
|  | @ -463,10 +457,10 @@ def _write_arg_to_bytes(builder, arg, args, name=None): | |||
|         pass  # These are actually NOT written! Only used for flags | ||||
| 
 | ||||
|     elif 'bytes' == arg.type: | ||||
|         builder.write('TLObject.serialize_bytes({})', name) | ||||
|         builder.write('self.serialize_bytes({})', name) | ||||
| 
 | ||||
|     elif 'date' == arg.type:  # Custom format | ||||
|         builder.write('TLObject.serialize_datetime({})', name) | ||||
|         builder.write('self.serialize_datetime({})', name) | ||||
| 
 | ||||
|     else: | ||||
|         # Else it may be a custom type | ||||
|  | @ -651,9 +645,9 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir): | |||
|             namespace_types[tlobject.namespace].append(tlobject) | ||||
|             type_constructors[tlobject.result].append(tlobject) | ||||
| 
 | ||||
|     _write_modules(get_file('functions'), import_depth, | ||||
|     _write_modules(get_file('functions'), import_depth, 'TLRequest', | ||||
|                    namespace_functions, type_constructors) | ||||
|     _write_modules(get_file('types'), import_depth, | ||||
|     _write_modules(get_file('types'), import_depth, 'TLObject', | ||||
|                    namespace_types, type_constructors) | ||||
| 
 | ||||
|     filename = os.path.join(get_file('all_tlobjects.py')) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user