mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-05 12:40:22 +03:00
stuff
This commit is contained in:
parent
1d4bd39307
commit
34fc07b1fe
|
@ -202,6 +202,12 @@ is decided by Telegram.
|
||||||
The ``telethon.errors`` module continues to provide custom errors used by the library such as
|
The ``telethon.errors`` module continues to provide custom errors used by the library such as
|
||||||
``TypeNotFoundError``.
|
``TypeNotFoundError``.
|
||||||
|
|
||||||
|
Errors are all now immutable - you can't modify them. This means the library will not correct
|
||||||
|
weird errors such as FLOOD_WAIT_0 (which was previously modified to FLOOD_WAIT_1). When the
|
||||||
|
library does automatic flood sleeping, it will still make this correction, but if the
|
||||||
|
``flood_sleep_threshold`` is in the range [0,1) then you may get FLOOD_WAIT_0 raised to your
|
||||||
|
application code. This must be handled manually.
|
||||||
|
|
||||||
// TODO keep RPCError around? eh idk how much it's used
|
// TODO keep RPCError around? eh idk how much it's used
|
||||||
// TODO should RpcError subclass ValueError? technically the values used in the request somehow were wrong…
|
// TODO should RpcError subclass ValueError? technically the values used in the request somehow were wrong…
|
||||||
// TODO provide a way to see which errors are known in the docs or at tl.telethon.dev
|
// TODO provide a way to see which errors are known in the docs or at tl.telethon.dev
|
||||||
|
|
|
@ -82,7 +82,8 @@ class _DialogsIter(requestiter.RequestIter):
|
||||||
|
|
||||||
cd = _custom.Dialog(self.client, d, entities, message)
|
cd = _custom.Dialog(self.client, d, entities, message)
|
||||||
if cd.dialog.pts:
|
if cd.dialog.pts:
|
||||||
self.client._channel_pts[cd.id] = cd.dialog.pts
|
# TODO probably a bad idea to change pts around as a side effect - add a .discard_pending_updates() method?
|
||||||
|
self.client._channel_pts[cd.entity.id] = cd.dialog.pts
|
||||||
|
|
||||||
if not self.ignore_migrated or getattr(
|
if not self.ignore_migrated or getattr(
|
||||||
cd.entity, 'migrated_to', None) is None:
|
cd.entity, 'migrated_to', None) is None:
|
||||||
|
|
|
@ -508,7 +508,7 @@ async def send_message(
|
||||||
date=result.date,
|
date=result.date,
|
||||||
out=result.out,
|
out=result.out,
|
||||||
media=result.media,
|
media=result.media,
|
||||||
entities=result._fmt_entities,
|
entities=result.entities,
|
||||||
reply_markup=request.reply_markup,
|
reply_markup=request.reply_markup,
|
||||||
ttl_period=result.ttl_period
|
ttl_period=result.ttl_period
|
||||||
), {}, entity)
|
), {}, entity)
|
||||||
|
|
|
@ -74,6 +74,10 @@ def init(
|
||||||
use_ipv6: bool = False,
|
use_ipv6: bool = False,
|
||||||
proxy: typing.Union[tuple, dict] = None,
|
proxy: typing.Union[tuple, dict] = None,
|
||||||
local_addr: typing.Union[str, tuple] = None,
|
local_addr: typing.Union[str, tuple] = None,
|
||||||
|
default_dc_id: int = None,
|
||||||
|
default_ipv4_ip: str = None,
|
||||||
|
default_ipv6_ip: str = None,
|
||||||
|
default_port: int = None,
|
||||||
timeout: int = 10,
|
timeout: int = 10,
|
||||||
request_retries: int = 5,
|
request_retries: int = 5,
|
||||||
connection_retries: int = 5,
|
connection_retries: int = 5,
|
||||||
|
@ -180,6 +184,15 @@ def init(
|
||||||
'`use_ipv6=True` must only be used with a local IPv6 address.'
|
'`use_ipv6=True` must only be used with a local IPv6 address.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._default_dc_id = default_dc_id or DEFAULT_DC_ID
|
||||||
|
if not isinstance(self._default_dc_id, int):
|
||||||
|
raise TypeError('`default_dc_id` must be an int or None.')
|
||||||
|
self._default_ipv4_ip = int(ipaddress.ip_address(default_ipv4_ip or DEFAULT_IPV4_IP))
|
||||||
|
self._default_ipv6_ip = int(ipaddress.ip_address(default_ipv6_ip or DEFAULT_IPV6_IP))
|
||||||
|
self._default_port = default_port or DEFAULT_PORT
|
||||||
|
if not isinstance(self._default_port, int):
|
||||||
|
raise TypeError('`default_port` must be an int or None')
|
||||||
|
|
||||||
self._raise_last_call_error = raise_last_call_error
|
self._raise_last_call_error = raise_last_call_error
|
||||||
|
|
||||||
self._request_retries = request_retries
|
self._request_retries = request_retries
|
||||||
|
@ -305,7 +318,7 @@ async def connect(self: 'TelegramClient') -> None:
|
||||||
try_fetch_user = False
|
try_fetch_user = False
|
||||||
self._session_state = SessionState(
|
self._session_state = SessionState(
|
||||||
user_id=0,
|
user_id=0,
|
||||||
dc_id=DEFAULT_DC_ID,
|
dc_id=self._default_dc_id,
|
||||||
bot=False,
|
bot=False,
|
||||||
pts=0,
|
pts=0,
|
||||||
qts=0,
|
qts=0,
|
||||||
|
@ -319,10 +332,10 @@ async def connect(self: 'TelegramClient') -> None:
|
||||||
dc = self._all_dcs.get(self._session_state.dc_id)
|
dc = self._all_dcs.get(self._session_state.dc_id)
|
||||||
if dc is None:
|
if dc is None:
|
||||||
dc = DataCenter(
|
dc = DataCenter(
|
||||||
id=DEFAULT_DC_ID,
|
id=self._default_dc_id,
|
||||||
ipv4=None if self._use_ipv6 else int(ipaddress.ip_address(DEFAULT_IPV4_IP)),
|
ipv4=None if self._use_ipv6 else self._default_ipv4_ip,
|
||||||
ipv6=int(ipaddress.ip_address(DEFAULT_IPV6_IP)) if self._use_ipv6 else None,
|
ipv6=self._default_ipv6_ip if self._use_ipv6 else None,
|
||||||
port=DEFAULT_PORT,
|
port=self._default_port,
|
||||||
auth=b'',
|
auth=b'',
|
||||||
)
|
)
|
||||||
self._all_dcs[dc.id] = dc
|
self._all_dcs[dc.id] = dc
|
||||||
|
|
|
@ -73,6 +73,21 @@ class TelegramClient:
|
||||||
You only need to use this if you have multiple network cards and
|
You only need to use this if you have multiple network cards and
|
||||||
want to use a specific one.
|
want to use a specific one.
|
||||||
|
|
||||||
|
default_dc_id (`int`, optional):
|
||||||
|
The DC ID to connect to, if not already provided by the session.
|
||||||
|
|
||||||
|
default_ipv4_ip (`str`, optional):
|
||||||
|
The default IPv4 address to connect to, if not already provided by
|
||||||
|
the session.
|
||||||
|
|
||||||
|
default_ipv6_ip (`str`, optional):
|
||||||
|
The default IPv6 address to connect to, if not already provided by
|
||||||
|
the session.
|
||||||
|
|
||||||
|
default_port (`int`, optional):
|
||||||
|
The default port to connect to, if not already provided by
|
||||||
|
the session. This is used whether the connection is IPv4 or IPv6.
|
||||||
|
|
||||||
timeout (`int` | `float`, optional):
|
timeout (`int` | `float`, optional):
|
||||||
The timeout in seconds to be used when connecting.
|
The timeout in seconds to be used when connecting.
|
||||||
This is **not** the timeout to be used when ``await``'ing for
|
This is **not** the timeout to be used when ``await``'ing for
|
||||||
|
@ -2681,6 +2696,10 @@ class TelegramClient:
|
||||||
use_ipv6: bool = False,
|
use_ipv6: bool = False,
|
||||||
proxy: typing.Union[tuple, dict] = None,
|
proxy: typing.Union[tuple, dict] = None,
|
||||||
local_addr: typing.Union[str, tuple] = None,
|
local_addr: typing.Union[str, tuple] = None,
|
||||||
|
default_dc_id: int = None,
|
||||||
|
default_ipv4_ip: str = None,
|
||||||
|
default_ipv6_ip: str = None,
|
||||||
|
default_port: int = None,
|
||||||
timeout: int = 10,
|
timeout: int = 10,
|
||||||
request_retries: int = 5,
|
request_retries: int = 5,
|
||||||
connection_retries: int = 5,
|
connection_retries: int = 5,
|
||||||
|
|
|
@ -102,17 +102,17 @@ async def _call(self: 'TelegramClient', sender, request, ordered=False, flood_sl
|
||||||
|
|
||||||
# SLOWMODE_WAIT is chat-specific, not request-specific
|
# SLOWMODE_WAIT is chat-specific, not request-specific
|
||||||
if not isinstance(e, errors.SLOWMODE_WAIT):
|
if not isinstance(e, errors.SLOWMODE_WAIT):
|
||||||
|
# TODO reconsider use of time.time() - maybe monotonic or server time is better.
|
||||||
self._flood_waited_requests \
|
self._flood_waited_requests \
|
||||||
[request.CONSTRUCTOR_ID] = time.time() + e.seconds
|
[request.CONSTRUCTOR_ID] = time.time() + e.seconds
|
||||||
|
|
||||||
# In test servers, FLOOD_WAIT_0 has been observed, and sleeping for
|
# In test servers, FLOOD_WAIT_0 has been observed, and sleeping for
|
||||||
# such a short amount will cause retries very fast leading to issues.
|
# such a short amount will cause retries very fast leading to issues.
|
||||||
if e.seconds == 0:
|
seconds = e.seconds or 1
|
||||||
e.seconds = 1
|
|
||||||
|
|
||||||
if e.seconds <= self.flood_sleep_threshold:
|
if seconds <= self.flood_sleep_threshold:
|
||||||
self._log[__name__].info(*_fmt_flood(e.seconds, request))
|
self._log[__name__].info(*_fmt_flood(seconds, request))
|
||||||
await asyncio.sleep(e.seconds)
|
await asyncio.sleep(seconds)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except InvalidDcError as e:
|
except InvalidDcError as e:
|
||||||
|
|
|
@ -74,7 +74,7 @@ class Session(ABC):
|
||||||
For example, if a ``ty`` representing a bot is stored but the asking ``ty`` is a user,
|
For example, if a ``ty`` representing a bot is stored but the asking ``ty`` is a user,
|
||||||
the corresponding ``access_hash`` should still be returned.
|
the corresponding ``access_hash`` should still be returned.
|
||||||
|
|
||||||
You may use `types.canonical_entity_type` to find out the canonical type.
|
You may use `types.get_canonical_entity_type` to find out the canonical type.
|
||||||
|
|
||||||
A ``ty`` with the value of ``None`` should be treated as "any entity with matching ID".
|
A ``ty`` with the value of ``None`` should be treated as "any entity with matching ID".
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from .types import DataCenter, ChannelState, SessionState, Entity, get_entity_type_group
|
from .types import DataCenter, ChannelState, SessionState, Entity, get_entity_type_group, get_canonical_entity_type
|
||||||
from .abstract import Session
|
from .abstract import Session
|
||||||
from .._misc import utils, tlobject
|
from .._misc import utils, tlobject
|
||||||
from .. import _tl
|
from .. import _tl
|
||||||
|
@ -34,11 +34,11 @@ class MemorySession(Session):
|
||||||
return list(self.channel_states.values())
|
return list(self.channel_states.values())
|
||||||
|
|
||||||
async def insert_entities(self, entities: List[Entity]):
|
async def insert_entities(self, entities: List[Entity]):
|
||||||
self.entities.update(((get_peer_canonical_entity_type(e.ty), e.id), e.access_hash) for e in entities)
|
self.entities.update(((get_canonical_entity_type(e.ty), e.id), e.access_hash) for e in entities)
|
||||||
|
|
||||||
async def get_entity(self, ty: int, id: int) -> Optional[Entity]:
|
async def get_entity(self, ty: int, id: int) -> Optional[Entity]:
|
||||||
try:
|
try:
|
||||||
access_hash = self.entities[get_peer_canonical_entity_type(ty), id]
|
access_hash = self.entities[get_canonical_entity_type(ty), id]
|
||||||
return Entity(ty, id, access_hash)
|
return Entity(ty, id, access_hash)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -123,7 +123,7 @@ class Entity:
|
||||||
self.access_hash = access_hash
|
self.access_hash = access_hash
|
||||||
|
|
||||||
|
|
||||||
def canonical_entity_type(ty: int, *, _mapping={
|
def get_canonical_entity_type(ty: int, *, _mapping={
|
||||||
Entity.USER: Entity.USER,
|
Entity.USER: Entity.USER,
|
||||||
Entity.BOT: Entity.USER,
|
Entity.BOT: Entity.USER,
|
||||||
Entity.GROUP: Entity.GROUP,
|
Entity.GROUP: Entity.GROUP,
|
||||||
|
|
|
@ -37,9 +37,6 @@ class Dialog:
|
||||||
input_entity (:tl:`InputPeer`):
|
input_entity (:tl:`InputPeer`):
|
||||||
Input version of the entity.
|
Input version of the entity.
|
||||||
|
|
||||||
id (`int`):
|
|
||||||
The marked ID of the entity, which is guaranteed to be unique.
|
|
||||||
|
|
||||||
name (`str`):
|
name (`str`):
|
||||||
Display name for this dialog. For chats and channels this is
|
Display name for this dialog. For chats and channels this is
|
||||||
their title, and for users it's "First-Name Last-Name".
|
their title, and for users it's "First-Name Last-Name".
|
||||||
|
@ -81,7 +78,6 @@ class Dialog:
|
||||||
|
|
||||||
self.entity = entities[utils.get_peer_id(dialog.peer)]
|
self.entity = entities[utils.get_peer_id(dialog.peer)]
|
||||||
self.input_entity = utils.get_input_peer(self.entity)
|
self.input_entity = utils.get_input_peer(self.entity)
|
||||||
self.id = utils.get_peer_id(self.entity) # ^ May be InputPeerSelf()
|
|
||||||
self.name = self.title = utils.get_display_name(self.entity)
|
self.name = self.title = utils.get_display_name(self.entity)
|
||||||
|
|
||||||
self.unread_count = dialog.unread_count
|
self.unread_count = dialog.unread_count
|
||||||
|
|
|
@ -409,14 +409,23 @@ class Message(ChatGetter, SenderGetter):
|
||||||
sender_id = None
|
sender_id = None
|
||||||
if isinstance(message, _tl.Message):
|
if isinstance(message, _tl.Message):
|
||||||
if message.from_id is not None:
|
if message.from_id is not None:
|
||||||
sender_id = utils.get_peer_id(message.from_id)
|
sender_id = message.from_id
|
||||||
if sender_id is None and message.peer_id and not isinstance(message, _tl.MessageEmpty):
|
if sender_id is None and message.peer_id and not isinstance(message, _tl.MessageEmpty):
|
||||||
# If the message comes from a Channel, let the sender be it
|
# If the message comes from a Channel, let the sender be it
|
||||||
# ...or...
|
# ...or...
|
||||||
# incoming messages in private conversations no longer have from_id
|
# incoming messages in private conversations no longer have from_id
|
||||||
# (layer 119+), but the sender can only be the chat we're in.
|
# (layer 119+), but the sender can only be the chat we're in.
|
||||||
|
print("a", message.peer_id, message.out, isinstance(message.peer_id, _tl.PeerUser))
|
||||||
if message.post or (not message.out and isinstance(message.peer_id, _tl.PeerUser)):
|
if message.post or (not message.out and isinstance(message.peer_id, _tl.PeerUser)):
|
||||||
sender_id = utils.get_peer_id(message.peer_id)
|
sender_id = message.peer_id
|
||||||
|
if message.post:
|
||||||
|
sender_id = message.peer_id
|
||||||
|
if isinstance(message.peer_id, _tl.PeerUser):
|
||||||
|
if message.out:
|
||||||
|
sender_id = _tl.PeerUser(client._session_state.user_id)
|
||||||
|
else:
|
||||||
|
sender_id = message.peer_id
|
||||||
|
print("b", sender_id)
|
||||||
|
|
||||||
# Note that these calls would reset the client
|
# Note that these calls would reset the client
|
||||||
ChatGetter.__init__(self, message.peer_id, broadcast=message.post)
|
ChatGetter.__init__(self, message.peer_id, broadcast=message.post)
|
||||||
|
@ -444,8 +453,8 @@ class Message(ChatGetter, SenderGetter):
|
||||||
|
|
||||||
cache = client._entity_cache
|
cache = client._entity_cache
|
||||||
|
|
||||||
self._sender, self._input_sender = utils._get_entity_pair(
|
# self._sender, self._input_sender = utils._get_entity_pair(
|
||||||
self.sender_id, entities, cache)
|
# self.sender_id, entities, cache)
|
||||||
|
|
||||||
self._chat, self._input_chat = utils._get_entity_pair(
|
self._chat, self._input_chat = utils._get_entity_pair(
|
||||||
self.chat_id, entities, cache)
|
self.chat_id, entities, cache)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import abc
|
import abc
|
||||||
|
from ..._misc import utils
|
||||||
|
|
||||||
|
|
||||||
class SenderGetter(abc.ABC):
|
class SenderGetter(abc.ABC):
|
||||||
|
@ -8,7 +9,7 @@ class SenderGetter(abc.ABC):
|
||||||
methods.
|
methods.
|
||||||
"""
|
"""
|
||||||
def __init__(self, sender_id=None, *, sender=None, input_sender=None):
|
def __init__(self, sender_id=None, *, sender=None, input_sender=None):
|
||||||
self._sender_id = sender_id
|
self._sender_id = utils.get_peer(sender_id)
|
||||||
self._sender = sender
|
self._sender = sender
|
||||||
self._input_sender = input_sender
|
self._input_sender = input_sender
|
||||||
self._client = None
|
self._client = None
|
||||||
|
@ -84,7 +85,7 @@ class SenderGetter(abc.ABC):
|
||||||
@property
|
@property
|
||||||
def sender_id(self):
|
def sender_id(self):
|
||||||
"""
|
"""
|
||||||
Returns the marked sender integer ID, if present.
|
Returns the sender peer, if present.
|
||||||
|
|
||||||
If there is a sender in the object, `sender_id` will *always* be set,
|
If there is a sender in the object, `sender_id` will *always* be set,
|
||||||
which is why you should use it instead of `sender.id <sender>`.
|
which is why you should use it instead of `sender.id <sender>`.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user