mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 09:26:37 +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