mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-31 16:07:44 +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 .telegrambaseclient import TelegramBaseClient | ||||||
| from .. import errors, utils | 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): | class UserMethods(TelegramBaseClient): | ||||||
|     async def __call__(self, request, retries=5, ordered=False): |     async def __call__(self, request, retries=5, ordered=False): | ||||||
|         requests = (request,) if not utils.is_list_like(request) else request |         for r in (request if utils.is_list_like(request) else (request,)): | ||||||
|         if not all(isinstance(x, TLObject) and |             if not isinstance(r, TLRequest): | ||||||
|                    x.content_related for x in requests): |                 raise _NOT_A_REQUEST | ||||||
|             raise TypeError('You can only invoke requests, not types!') |  | ||||||
| 
 |  | ||||||
|         for r in requests: |  | ||||||
|             await r.resolve(self, utils) |             await r.resolve(self, utils) | ||||||
| 
 | 
 | ||||||
|         for _ in range(retries): |         for _ in range(retries): | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ from ..crypto import AES | ||||||
| from ..errors import SecurityError, BrokenAuthKeyError | from ..errors import SecurityError, BrokenAuthKeyError | ||||||
| from ..extensions import BinaryReader | from ..extensions import BinaryReader | ||||||
| from ..tl.core import TLMessage | from ..tl.core import TLMessage | ||||||
|  | from ..tl.tlobject import TLRequest | ||||||
| 
 | 
 | ||||||
| __log__ = logging.getLogger(__name__) | __log__ = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -43,7 +44,7 @@ class MTProtoState: | ||||||
|         """ |         """ | ||||||
|         return TLMessage( |         return TLMessage( | ||||||
|             msg_id=self._get_new_msg_id(), |             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, |             obj=obj, | ||||||
|             after_id=after.msg_id if after else None |             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 gzip | ||||||
| import struct | import struct | ||||||
| 
 | 
 | ||||||
| from .. import TLObject | from .. import TLObject, TLRequest | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class GzipPacked(TLObject): | class GzipPacked(TLObject): | ||||||
|  | @ -21,7 +21,7 @@ class GzipPacked(TLObject): | ||||||
|         """ |         """ | ||||||
|         data = bytes(request) |         data = bytes(request) | ||||||
|         # TODO This threshold could be configurable |         # 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)) |             gzipped = bytes(GzipPacked(data)) | ||||||
|             return gzipped if len(gzipped) < len(data) else data |             return gzipped if len(gzipped) < len(data) else data | ||||||
|         else: |         else: | ||||||
|  |  | ||||||
|  | @ -11,13 +11,10 @@ class MessageContainer(TLObject): | ||||||
|     CONSTRUCTOR_ID = 0x73f1f8dc |     CONSTRUCTOR_ID = 0x73f1f8dc | ||||||
| 
 | 
 | ||||||
|     def __init__(self, messages): |     def __init__(self, messages): | ||||||
|         super().__init__() |  | ||||||
|         self.content_related = False |  | ||||||
|         self.messages = messages |         self.messages = messages | ||||||
| 
 | 
 | ||||||
|     def to_dict(self, recursive=True): |     def to_dict(self, recursive=True): | ||||||
|         return { |         return { | ||||||
|             'content_related': self.content_related, |  | ||||||
|             'messages': |             'messages': | ||||||
|                 ([] if self.messages is None else [ |                 ([] if self.messages is None else [ | ||||||
|                     None if x is None else x.to_dict() for x in self.messages |                     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: | 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 |     @staticmethod | ||||||
|     def pretty_format(obj, indent=None): |     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 indent is None: | ||||||
|             if isinstance(obj, TLObject): |             if isinstance(obj, TLObject): | ||||||
|  | @ -136,11 +131,6 @@ class TLObject: | ||||||
| 
 | 
 | ||||||
|         raise TypeError('Cannot interpret "{}" as a date.'.format(dt)) |         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): |     def __eq__(self, o): | ||||||
|         return isinstance(o, type(self)) and self.to_dict() == o.to_dict() |         return isinstance(o, type(self)) and self.to_dict() == o.to_dict() | ||||||
| 
 | 
 | ||||||
|  | @ -153,16 +143,24 @@ class TLObject: | ||||||
|     def stringify(self): |     def stringify(self): | ||||||
|         return TLObject.pretty_format(self, indent=0) |         return TLObject.pretty_format(self, indent=0) | ||||||
| 
 | 
 | ||||||
|     # These should be overrode |  | ||||||
|     async def resolve(self, client, utils): |  | ||||||
|         pass |  | ||||||
| 
 |  | ||||||
|     def to_dict(self): |     def to_dict(self): | ||||||
|         return {} |         raise NotImplementedError | ||||||
| 
 | 
 | ||||||
|     def __bytes__(self): |     def __bytes__(self): | ||||||
|         return b'' |         raise NotImplementedError | ||||||
| 
 | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_reader(cls, reader): |     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') |               '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]} |     # namespace_tlobjects: {'namespace', [TLObject]} | ||||||
|     os.makedirs(out_dir, exist_ok=True) |     os.makedirs(out_dir, exist_ok=True) | ||||||
|     for ns, tlobjects in namespace_tlobjects.items(): |     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: |                 SourceBuilder(f) as builder: | ||||||
|             builder.writeln(AUTO_GEN_NOTICE) |             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, ' |             builder.writeln('from typing import Optional, List, ' | ||||||
|                             'Union, TYPE_CHECKING') |                             'Union, TYPE_CHECKING') | ||||||
| 
 | 
 | ||||||
|  | @ -124,7 +125,7 @@ def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | ||||||
| 
 | 
 | ||||||
|             # Generate the class for every TLObject |             # Generate the class for every TLObject | ||||||
|             for t in tlobjects: |             for t in tlobjects: | ||||||
|                 _write_source_code(t, builder, type_constructors) |                 _write_source_code(t, kind, builder, type_constructors) | ||||||
|                 builder.current_indent = 0 |                 builder.current_indent = 0 | ||||||
| 
 | 
 | ||||||
|             # Write the type definitions generated earlier. |             # Write the type definitions generated earlier. | ||||||
|  | @ -133,7 +134,7 @@ def _write_modules(out_dir, depth, namespace_tlobjects, type_constructors): | ||||||
|                 builder.writeln(line) |                 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 |     Writes the source code corresponding to the given TLObject | ||||||
|     by making use of the ``builder`` `SourceBuilder`. |     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 |     the ``Type: [Constructors]`` must be given for proper | ||||||
|     importing and documentation strings. |     importing and documentation strings. | ||||||
|     """ |     """ | ||||||
|     _write_class_init(tlobject, type_constructors, builder) |     _write_class_init(tlobject, kind, type_constructors, builder) | ||||||
|     _write_resolve(tlobject, builder) |     _write_resolve(tlobject, builder) | ||||||
|     _write_to_dict(tlobject, builder) |     _write_to_dict(tlobject, builder) | ||||||
|     _write_to_bytes(tlobject, builder) |     _write_to_bytes(tlobject, builder) | ||||||
|  | @ -150,10 +151,10 @@ def _write_source_code(tlobject, builder, type_constructors): | ||||||
|     _write_read_result(tlobject, builder) |     _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() |     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 |     # Class-level variable to store its Telegram's constructor ID | ||||||
|     builder.writeln('CONSTRUCTOR_ID = {:#x}', tlobject.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 |     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] |              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)) |     builder.writeln('def __init__({}):', ', '.join(['self'] + args)) | ||||||
|     if tlobject.real_args: |     # Write the docstring, to know the type of the args | ||||||
|         # Write the docstring, to know the type of the args |     builder.writeln('"""') | ||||||
|         builder.writeln('"""') |     for arg in tlobject.real_args: | ||||||
|         for arg in tlobject.real_args: |         if not arg.flag_indicator: | ||||||
|             if not arg.flag_indicator: |             builder.writeln(':param {} {}:', arg.type_hint(), arg.name) | ||||||
|                 builder.writeln(':param {} {}:', arg.type_hint(), arg.name) |             builder.current_indent -= 1  # It will auto-indent (':') | ||||||
|                 builder.current_indent -= 1  # It will auto-indent (':') |  | ||||||
| 
 | 
 | ||||||
|         # We also want to know what type this request returns |     # We also want to know what type this request returns | ||||||
|         # or to which type this constructor belongs to |     # or to which type this constructor belongs to | ||||||
|         builder.writeln() |     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 |  | ||||||
|     if tlobject.is_function: |     if tlobject.is_function: | ||||||
|         builder.writeln('self.result = None') |         builder.write(':returns {}: ', tlobject.result) | ||||||
|         builder.writeln('self.content_related = True') |     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 |     # Set the arguments | ||||||
|     if tlobject.real_args: |  | ||||||
|         builder.writeln() |  | ||||||
| 
 |  | ||||||
|     for arg in tlobject.real_args: |     for arg in tlobject.real_args: | ||||||
|         if not arg.can_be_inferred: |         if not arg.can_be_inferred: | ||||||
|             builder.writeln('self.{0} = {0}  # type: {1}', |             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) |         builder.write("struct.pack('<d', {})", name) | ||||||
| 
 | 
 | ||||||
|     elif 'string' == arg.type: |     elif 'string' == arg.type: | ||||||
|         builder.write('TLObject.serialize_bytes({})', name) |         builder.write('self.serialize_bytes({})', name) | ||||||
| 
 | 
 | ||||||
|     elif 'Bool' == arg.type: |     elif 'Bool' == arg.type: | ||||||
|         # 0x997275b5 if boolean else 0xbc799737 |         # 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 |         pass  # These are actually NOT written! Only used for flags | ||||||
| 
 | 
 | ||||||
|     elif 'bytes' == arg.type: |     elif 'bytes' == arg.type: | ||||||
|         builder.write('TLObject.serialize_bytes({})', name) |         builder.write('self.serialize_bytes({})', name) | ||||||
| 
 | 
 | ||||||
|     elif 'date' == arg.type:  # Custom format |     elif 'date' == arg.type:  # Custom format | ||||||
|         builder.write('TLObject.serialize_datetime({})', name) |         builder.write('self.serialize_datetime({})', name) | ||||||
| 
 | 
 | ||||||
|     else: |     else: | ||||||
|         # Else it may be a custom type |         # 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) |             namespace_types[tlobject.namespace].append(tlobject) | ||||||
|             type_constructors[tlobject.result].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) |                    namespace_functions, type_constructors) | ||||||
|     _write_modules(get_file('types'), import_depth, |     _write_modules(get_file('types'), import_depth, 'TLObject', | ||||||
|                    namespace_types, type_constructors) |                    namespace_types, type_constructors) | ||||||
| 
 | 
 | ||||||
|     filename = os.path.join(get_file('all_tlobjects.py')) |     filename = os.path.join(get_file('all_tlobjects.py')) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user