diff --git a/hydrogram/client.py b/hydrogram/client.py index c8ee13505..80542b5dd 100644 --- a/hydrogram/client.py +++ b/hydrogram/client.py @@ -309,7 +309,7 @@ def __init__( self.parser = Parser(self) - self.session = None + self.session: Session | None = None self.media_sessions = {} self.media_sessions_lock = asyncio.Lock() @@ -318,8 +318,8 @@ def __init__( self.save_file_semaphore = asyncio.Semaphore(self.max_concurrent_transmissions) self.get_file_semaphore = asyncio.Semaphore(self.max_concurrent_transmissions) - self.is_connected = None - self.is_initialized = None + self.is_connected: bool | None = None + self.is_initialized: bool | None = None self.takeout_id = None diff --git a/hydrogram/methods/auth/disconnect.py b/hydrogram/methods/auth/disconnect.py index b52217174..63887014d 100644 --- a/hydrogram/methods/auth/disconnect.py +++ b/hydrogram/methods/auth/disconnect.py @@ -28,17 +28,11 @@ async def disconnect( self: "hydrogram.Client", ): """Disconnect the client from Telegram servers. - - Raises: - ConnectionError: In case you try to disconnect an already disconnected client or in case you try to - disconnect a client that needs to be terminated first. """ - if not self.is_connected: - raise ConnectionError("Client is already disconnected") + if self.session: + await self.session.stop() - if self.is_initialized: - raise ConnectionError("Can't disconnect an initialized client") + if self.storage: + await self.storage.close() - await self.session.stop() - await self.storage.close() self.is_connected = False diff --git a/hydrogram/methods/auth/terminate.py b/hydrogram/methods/auth/terminate.py index aa0b34d4d..2fc4b1304 100644 --- a/hydrogram/methods/auth/terminate.py +++ b/hydrogram/methods/auth/terminate.py @@ -16,7 +16,8 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Hydrogram. If not, see . - +import asyncio +import contextlib import logging import hydrogram @@ -33,29 +34,28 @@ async def terminate( This method does the opposite of :meth:`~hydrogram.Client.initialize`. It will stop the dispatcher and shut down updates and download workers. - - Raises: - ConnectionError: In case you try to terminate a client that is already terminated. """ - if not self.is_initialized: - raise ConnectionError("Client is already terminated") - if self.takeout_id: - await self.invoke(raw.functions.account.FinishTakeoutSession()) - log.info("Takeout session %s finished", self.takeout_id) + with contextlib.suppress(Exception): + await self.invoke(raw.functions.account.FinishTakeoutSession()) + log.info("Takeout session %s finished", self.takeout_id) - await self.storage.save() - await self.dispatcher.stop() + if self.storage: + await self.storage.save() - for media_session in self.media_sessions.values(): - await media_session.stop() + if self.dispatcher: + await self.dispatcher.stop() - self.media_sessions.clear() + if self.media_sessions: + for media_session in self.media_sessions.values(): + await media_session.stop() + self.media_sessions.clear() self.updates_watchdog_event.set() if self.updates_watchdog_task is not None: - await self.updates_watchdog_task + with contextlib.suppress(asyncio.TimeoutError, asyncio.CancelledError): + await asyncio.wait_for(self.updates_watchdog_task, timeout=1.0) self.updates_watchdog_event.clear() diff --git a/hydrogram/session/session.py b/hydrogram/session/session.py index a041970ee..416d9f011 100644 --- a/hydrogram/session/session.py +++ b/hydrogram/session/session.py @@ -176,6 +176,14 @@ async def stop(self): self.stored_msg_ids.clear() + if self.recv_task and not self.recv_task.done(): + self.recv_task.cancel() + + with contextlib.suppress(asyncio.CancelledError, asyncio.TimeoutError, RuntimeError): + await asyncio.wait_for(self.recv_task, timeout=1.0) + + self.recv_task = None + self.ping_task_event.set() if self.ping_task is not None: @@ -186,14 +194,6 @@ async def stop(self): if self.connection: await self.connection.close() - if self.recv_task and not self.recv_task.done(): - self.recv_task.cancel() - - with contextlib.suppress(asyncio.CancelledError, asyncio.TimeoutError, RuntimeError): - await asyncio.wait_for(self.recv_task, timeout=1.0) - - self.recv_task = None - if not self.is_media and callable(self.client.disconnect_handler): try: await self.client.disconnect_handler(self.client)