From 8c7f654ec7ad1ecc5b097f45a528210d9c4427d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sun, 13 Nov 2022 20:30:10 +0300 Subject: [PATCH 01/10] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d9d7366..1576a95 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) # Example ```Python -from convopyro import listen_message +from convopyro import listen_message,cancel_listen @app.on_message(filters.command('start')) async def start(client, message): @@ -38,6 +38,11 @@ async def start(client, message): answer = await listen_message(client, messsage.chat.id, timeout=None) await answer.reply(f'hello {answer.text}') +@app.on_message(filters.command('cancel_listen')) +async def start(client, message): + answer = await cancel_listen(client, messsage.chat.id) + print("Canceled Listen Message") + ``` # Advanced Usage From b48a4fa5aa3398f5bb6196b42e9b015d640ae137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sun, 13 Nov 2022 20:30:54 +0300 Subject: [PATCH 02/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1576a95..81ddb75 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ async def start(client, message): await answer.reply(f'hello {answer.text}') @app.on_message(filters.command('cancel_listen')) -async def start(client, message): +async def cancel_listen(client, message): answer = await cancel_listen(client, messsage.chat.id) print("Canceled Listen Message") From 47cbe74e5e033afead84ae46483460b7aa6fe816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:28:23 +0300 Subject: [PATCH 03/10] Update README.md --- README.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 81ddb75..6bcaffd 100644 --- a/README.md +++ b/README.md @@ -31,17 +31,27 @@ answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) from convopyro import listen_message,cancel_listen -@app.on_message(filters.command('start')) +@app.on_message(filters.command("start")) async def start(client, message): - await client.send_mesage(messsage.chat.id, "What's your name?") - - answer = await listen_message(client, messsage.chat.id, timeout=None) - await answer.reply(f'hello {answer.text}') - -@app.on_message(filters.command('cancel_listen')) -async def cancel_listen(client, message): - answer = await cancel_listen(client, messsage.chat.id) - print("Canceled Listen Message") + send = await client.send_message( + message.chat.id, + "What's your name?", + reply_markup=InlineKeyboardMarkup( + [[InlineKeyboardButton("Cancel listen", callback_data="cancel_listen")]] + ), + ) + + answer = await listen_message(client, message.chat.id, timeout=None) + if answer: + await answer.reply(f"hello {answer.text}") + else: + await message.reply("Canceled Answer") + + +@app.on_callback_query(filters.regex(pattern=r"^cancel_listen$")) +async def listen_closed(client: Client, callback_query: CallbackQuery): + await cancel_listen(client, callback_query.from_user.id) + await callback_query.message.delete() ``` From aa986b2dd531e4868611e6e293b1b9ed1942a82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sun, 13 Nov 2022 21:30:54 +0300 Subject: [PATCH 04/10] Update __init__.py --- src/convopyro/__init__.py | 299 ++++++++++++++++++++------------------ 1 file changed, 157 insertions(+), 142 deletions(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index cdaf045..d1fd1c4 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -3,150 +3,165 @@ from typing import Union import pyrogram, asyncio -class Conversation(): - """ - A conversation plugin class for pyrogram using inbuild Update Handlers. - Complete list of handlers to be used without `Handlers` postfix :- - https://docs.pyrogram.org/api/handlers#index - - - Usage: - In main.py where `Client` is initialized: - - app = Client('MyBot') - Conversation(app) # That's it! - - Then just use inside any handler `client.listen`: - - @app.on_message() - def button_click(client, update): - answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) - - Method client.listen.Message(or any other types) - Parameters: - filters: - Single or combined filters like https://docs.pyrogram.org/topics/use-filters. - Default is `None` but either filter or id is required. - - id: - An id for uniquely identify each listen only required if you want to Cancel() manually. - You can pass any of the three types here: - -> pyrogram.filters.user - -> pyrogram.filters.chat - -> str - if pyrogram filter's `user` or `chat` is passed as `id` then it gets combined with rest `filters`. - - Default is `None` but either filter or id is required. - - timeout: - In seconds (int) for waiting time of getting a response. - - Returns: - `update` (like pyrogram.types.Message ...etc) if user reponded within given conditions. - `None` if listen cancelled using `listen.Cancel` - `Exception` An asyncio.TimeoutError is raise if waiting timeout occurs. - Example: - @app.on_message(filters.command('start')) - async def start(client, message): - await client.send_mesage(messsage.chat.id, "What's your name?") - reply_msg = await client.listen.Message(filters.chat(messsage.chat.id), timeout = None) - if reply_msg: - reply_msg.reply(f'hello {reply_msg.text}') - - - Method client.listen.Cancel - Parameters: - id: - An id for uniquely identify the listen you want to Cancel() manually. - You can pass any of the three types here: - -> pyrogram.filters.user - -> pyrogram.filters.chat - -> str - Returns: - `Boolean` True if `id` was present and listen was Cancelped or False if `id` was invalid. - - Example: - @app.on_message(filters.command('stop')) - async def stop(client, message): - await client.listen.Cancel(message.from_user.id) - """ - def __init__(self, client : pyrogram.Client): - client.listen = self - self.client = client - self.handlers = {} - self.hdlr_lock = asyncio.Lock() - - async def __add(self, hdlr, filters = None, id = None, timeout = None): - _id = id - - if type(_id) in [pyrogram.filters.InvertFilter, pyrogram.filters.OrFilter, pyrogram.filters.AndFilter]: - raise ValueError('Combined filters are not allowed as unique id .') - - if _id and type(_id) not in [pyrogram.filters.user, pyrogram.filters.chat, str]: - raise TypeError('Unique (id) has to be one of pyrogram\'s filters user/chat or a string.') - - if not (_id or filters): - raise ValueError('Atleast either filters or _id as parameter is required.') - - if str(_id) in self.handlers: - await self.__remove(str(_id)) - #raise ValueError('Dupicate id provided.') - - # callback handler - async def dump(_, update): - await self.__remove(dump._id, update) - - dump._id = str(_id) if _id else hash(dump) - group = -0x3e7 - event = asyncio.Event() - filters = (_id & filters) if _id and filters and not isinstance(_id, str) else filters or (filters if isinstance(_id, str) else _id) - handler = hdlr(dump, filters) - - - if group not in self.client.dispatcher.groups: - self.client.dispatcher.groups[group] = [] - self.client.dispatcher.groups = OrderedDict(sorted(self.client.dispatcher.groups.items())) - - async with self.hdlr_lock: - self.client.dispatcher.groups[group].append(handler) - self.handlers[dump._id] = (handler, group, event) - - try: - await asyncio.wait_for(event.wait(), timeout) - except asyncio.exceptions.TimeoutError: - await self.__remove(dump._id) - raise asyncio.exceptions.TimeoutError - finally: - result = self.handlers.pop(dump._id, None) - self.hdlr_lock.release() - return result - - async def __remove(self, _id, update = None): - handler, group, event = self.handlers[_id] - self.client.dispatcher.groups[group].remove(handler) - await self.hdlr_lock.acquire() - self.handlers[_id] = update - event.set() - - async def Cancel(self, _id): - if str(_id) in self.handlers: - await self.__remove(str(_id)) - return True - else: - return False - - def __getattr__(self, name): - async def wrapper(*args, **kwargs): - return await self.__add(getattr(pyrogram.handlers, f'{name}Handler'), *args, **kwargs) - return wrapper - - -from pyrogram import Client, filters -from pyrogram.types import Message + +class Conversation: + """ + A conversation plugin class for pyrogram using inbuild Update Handlers. + Complete list of handlers to be used without `Handlers` postfix :- + https://docs.pyrogram.org/api/handlers#index + Usage: + In main.py where `Client` is initialized: + app = Client('MyBot') + Conversation(app) # That's it! + + Then just use inside any handler `client.listen`: + @app.on_message() + def button_click(client, update): + answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) + Method client.listen.Message(or any other types) + Parameters: + filters: + Single or combined filters like https://docs.pyrogram.org/topics/use-filters. + Default is `None` but either filter or id is required. + + id: + An id for uniquely identify each listen only required if you want to Cancel() manually. + You can pass any of the three types here: + -> pyrogram.filters.user + -> pyrogram.filters.chat + -> str + if pyrogram filter's `user` or `chat` is passed as `id` then it gets combined with rest `filters`. + Default is `None` but either filter or id is required. + + timeout: + In seconds (int) for waiting time of getting a response. + Returns: + `update` (like pyrogram.types.Message ...etc) if user reponded within given conditions. + `None` if listen cancelled using `listen.Cancel` + `Exception` An asyncio.TimeoutError is raise if waiting timeout occurs. + Example: + @app.on_message(filters.command('start')) + async def start(client, message): + await client.send_mesage(messsage.chat.id, "What's your name?") + reply_msg = await client.listen.Message(filters.chat(messsage.chat.id), timeout = None) + if reply_msg: + reply_msg.reply(f'hello {reply_msg.text}') + + Method client.listen.Cancel + Parameters: + id: + An id for uniquely identify the listen you want to Cancel() manually. + You can pass any of the three types here: + -> pyrogram.filters.user + -> pyrogram.filters.chat + -> str + Returns: + `Boolean` True if `id` was present and listen was Cancelped or False if `id` was invalid. + + Example: + @app.on_message(filters.command('stop')) + async def stop(client, message): + await client.listen.Cancel(message.from_user.id) + """ + + def __init__(self, client: pyrogram.Client): + client.listen = self + self.client = client + self.handlers = {} + self.hdlr_lock = asyncio.Lock() + + async def __add(self, hdlr, filters=None, id=None, timeout=None): + _id = id + + if type(_id) in [ + pyrogram.filters.InvertFilter, + pyrogram.filters.OrFilter, + pyrogram.filters.AndFilter, + ]: + raise ValueError("Combined filters are not allowed as unique id .") + + if _id and type(_id) not in [pyrogram.filters.user, pyrogram.filters.chat, str]: + raise TypeError( + "Unique (id) has to be one of pyrogram's filters user/chat or a string." + ) + + if not (_id or filters): + raise ValueError("Atleast either filters or _id as parameter is required.") + + if str(_id) in self.handlers: + await self.__remove(str(_id)) + # raise ValueError('Dupicate id provided.') + + # callback handler + async def dump(_, update): + await self.__remove(dump._id, update) + + dump._id = str(_id) if _id else hash(dump) + group = -0x3E7 + event = asyncio.Event() + filters = ( + (_id & filters) + if _id and filters and not isinstance(_id, str) + else filters or (filters if isinstance(_id, str) else _id) + ) + handler = hdlr(dump, filters) + + if group not in self.client.dispatcher.groups: + self.client.dispatcher.groups[group] = [] + self.client.dispatcher.groups = OrderedDict( + sorted(self.client.dispatcher.groups.items()) + ) + + async with self.hdlr_lock: + self.client.dispatcher.groups[group].append(handler) + self.handlers[dump._id] = (handler, group, event) + + try: + await asyncio.wait_for(event.wait(), timeout) + except asyncio.exceptions.TimeoutError: + await self.__remove(dump._id) + raise asyncio.exceptions.TimeoutError + finally: + result = self.handlers.pop(dump._id, None) + self.hdlr_lock.release() + return result + + async def __remove(self, _id, update=None): + handler, group, event = self.handlers[_id] + self.client.dispatcher.groups[group].remove(handler) + await self.hdlr_lock.acquire() + self.handlers[_id] = update + event.set() + + async def Cancel(self, _id): + if str(_id) in self.handlers: + await self.__remove(str(_id)) + return True + else: + return False + + def __getattr__(self, name): + async def wrapper(*args, **kwargs): + return await self.__add( + getattr(pyrogram.handlers, f"{name}Handler"), *args, **kwargs + ) + + return wrapper + + +from pyrogram import Client, filters +from pyrogram.types import Message from asyncio.exceptions import TimeoutError -async def listen_message(client:Client, chat_id:int, timeout=None) -> Union[Message, None]: + +async def listen_message( + client: Client, chat_id: int, timeout=None +) -> Union[Message, None]: try: - return await client.listen.Message(filters.chat(chat_id), timeout=timeout) + return await client.listen.Message(id=filters.chat(chat_id), timeout=timeout) except TimeoutError: return None + + +async def cancel_listen(client: Client, chat_id: int) -> bool: + return await client.listen.Cancel(filters.chat(chat_id)) From 58a36d8b227dcbcbd1aff751ba7ac9e6725a7a41 Mon Sep 17 00:00:00 2001 From: Sourcery AI <> Date: Thu, 15 Dec 2022 09:34:38 +0000 Subject: [PATCH 05/10] 'Refactored by Sourcery' --- src/convopyro/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index d1fd1c4..cef81a3 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -134,11 +134,10 @@ async def __remove(self, _id, update=None): event.set() async def Cancel(self, _id): - if str(_id) in self.handlers: - await self.__remove(str(_id)) - return True - else: + if str(_id) not in self.handlers: return False + await self.__remove(str(_id)) + return True def __getattr__(self, name): async def wrapper(*args, **kwargs): From 8d78be8ff22b507b38c3a6eefa2dafa84c429a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sat, 21 Jan 2023 12:15:04 +0300 Subject: [PATCH 06/10] =?UTF-8?q?Typing=20G=C3=BCncellemesi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/convopyro/__init__.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index cef81a3..84929ff 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -148,19 +148,15 @@ async def wrapper(*args, **kwargs): return wrapper -from pyrogram import Client, filters -from pyrogram.types import Message +from pyrogram import Client, filters +from pyrogram.types import Message from asyncio.exceptions import TimeoutError - -async def listen_message( - client: Client, chat_id: int, timeout=None -) -> Union[Message, None]: +async def listen_message(client:Client, chat_id:Union[int, str, List[Union[int, str]]], timeout:Union[int, None]=None) -> Union[Message, None]: try: - return await client.listen.Message(id=filters.chat(chat_id), timeout=timeout) + return await client.listen.Message(filters.chat(chat_id), timeout=timeout) except TimeoutError: return None - -async def cancel_listen(client: Client, chat_id: int) -> bool: +async def stop_listen(client:Client, chat_id:Union[int, str, List[Union[int, str]]]) -> bool: return await client.listen.Cancel(filters.chat(chat_id)) From 09e06c26869b383001b86f2da3e4fb4ccabc53ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sat, 21 Jan 2023 12:16:54 +0300 Subject: [PATCH 07/10] Update __init__.py --- src/convopyro/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index 84929ff..7bf85c5 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -158,5 +158,5 @@ async def listen_message(client:Client, chat_id:Union[int, str, List[Union[int, except TimeoutError: return None -async def stop_listen(client:Client, chat_id:Union[int, str, List[Union[int, str]]]) -> bool: +async def cancel_listen(client:Client, chat_id:Union[int, str, List[Union[int, str]]]) -> bool: return await client.listen.Cancel(filters.chat(chat_id)) From 57bab5e8f0145f695787a6f3382e8ba80b2f97c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Sat, 21 Jan 2023 12:18:02 +0300 Subject: [PATCH 08/10] Update __init__.py --- src/convopyro/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index 7bf85c5..1ee658a 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -1,9 +1,10 @@ #!/usr/bin/python3 from collections import OrderedDict -from typing import Union +from typing import Union, List import pyrogram, asyncio + class Conversation: """ A conversation plugin class for pyrogram using inbuild Update Handlers. From f0f7aac976943f37530aa41c81f5fc5f48d91729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:03:59 +0300 Subject: [PATCH 09/10] Update __init__.py --- src/convopyro/__init__.py | 275 ++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 146 deletions(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index 1ee658a..8886a06 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -3,152 +3,135 @@ from typing import Union, List import pyrogram, asyncio - - -class Conversation: - """ - A conversation plugin class for pyrogram using inbuild Update Handlers. - Complete list of handlers to be used without `Handlers` postfix :- - https://docs.pyrogram.org/api/handlers#index - Usage: - In main.py where `Client` is initialized: - app = Client('MyBot') - Conversation(app) # That's it! - - Then just use inside any handler `client.listen`: - @app.on_message() - def button_click(client, update): - answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) - Method client.listen.Message(or any other types) - Parameters: - filters: - Single or combined filters like https://docs.pyrogram.org/topics/use-filters. - Default is `None` but either filter or id is required. - - id: - An id for uniquely identify each listen only required if you want to Cancel() manually. - You can pass any of the three types here: - -> pyrogram.filters.user - -> pyrogram.filters.chat - -> str - if pyrogram filter's `user` or `chat` is passed as `id` then it gets combined with rest `filters`. - Default is `None` but either filter or id is required. - - timeout: - In seconds (int) for waiting time of getting a response. - Returns: - `update` (like pyrogram.types.Message ...etc) if user reponded within given conditions. - `None` if listen cancelled using `listen.Cancel` - `Exception` An asyncio.TimeoutError is raise if waiting timeout occurs. - Example: - @app.on_message(filters.command('start')) - async def start(client, message): - await client.send_mesage(messsage.chat.id, "What's your name?") - reply_msg = await client.listen.Message(filters.chat(messsage.chat.id), timeout = None) - if reply_msg: - reply_msg.reply(f'hello {reply_msg.text}') - - Method client.listen.Cancel - Parameters: - id: - An id for uniquely identify the listen you want to Cancel() manually. - You can pass any of the three types here: - -> pyrogram.filters.user - -> pyrogram.filters.chat - -> str - Returns: - `Boolean` True if `id` was present and listen was Cancelped or False if `id` was invalid. - - Example: - @app.on_message(filters.command('stop')) - async def stop(client, message): - await client.listen.Cancel(message.from_user.id) - """ - - def __init__(self, client: pyrogram.Client): - client.listen = self - self.client = client - self.handlers = {} - self.hdlr_lock = asyncio.Lock() - - async def __add(self, hdlr, filters=None, id=None, timeout=None): - _id = id - - if type(_id) in [ - pyrogram.filters.InvertFilter, - pyrogram.filters.OrFilter, - pyrogram.filters.AndFilter, - ]: - raise ValueError("Combined filters are not allowed as unique id .") - - if _id and type(_id) not in [pyrogram.filters.user, pyrogram.filters.chat, str]: - raise TypeError( - "Unique (id) has to be one of pyrogram's filters user/chat or a string." - ) - - if not (_id or filters): - raise ValueError("Atleast either filters or _id as parameter is required.") - - if str(_id) in self.handlers: - await self.__remove(str(_id)) - # raise ValueError('Dupicate id provided.') - - # callback handler - async def dump(_, update): - await self.__remove(dump._id, update) - - dump._id = str(_id) if _id else hash(dump) - group = -0x3E7 - event = asyncio.Event() - filters = ( - (_id & filters) - if _id and filters and not isinstance(_id, str) - else filters or (filters if isinstance(_id, str) else _id) - ) - handler = hdlr(dump, filters) - - if group not in self.client.dispatcher.groups: - self.client.dispatcher.groups[group] = [] - self.client.dispatcher.groups = OrderedDict( - sorted(self.client.dispatcher.groups.items()) - ) - - async with self.hdlr_lock: - self.client.dispatcher.groups[group].append(handler) - self.handlers[dump._id] = (handler, group, event) - - try: - await asyncio.wait_for(event.wait(), timeout) - except asyncio.exceptions.TimeoutError: - await self.__remove(dump._id) - raise asyncio.exceptions.TimeoutError - finally: - result = self.handlers.pop(dump._id, None) - self.hdlr_lock.release() - return result - - async def __remove(self, _id, update=None): - handler, group, event = self.handlers[_id] - self.client.dispatcher.groups[group].remove(handler) - await self.hdlr_lock.acquire() - self.handlers[_id] = update - event.set() - - async def Cancel(self, _id): - if str(_id) not in self.handlers: - return False - await self.__remove(str(_id)) - return True - - def __getattr__(self, name): - async def wrapper(*args, **kwargs): - return await self.__add( - getattr(pyrogram.handlers, f"{name}Handler"), *args, **kwargs - ) - - return wrapper - - +class Conversation(): + """ + A conversation plugin class for pyrogram using inbuild Update Handlers. + Complete list of handlers to be used without `Handlers` postfix :- + https://docs.pyrogram.org/api/handlers#index + Usage: + In main.py where `Client` is initialized: + app = Client('MyBot') + Conversation(app) # That's it! + + Then just use inside any handler `client.listen`: + @app.on_message() + def button_click(client, update): + answer = client.listen.CallbackQuery(filters.user(update.from_user.id)) + Method client.listen.Message(or any other types) + Parameters: + filters: + Single or combined filters like https://docs.pyrogram.org/topics/use-filters. + Default is `None` but either filter or id is required. + + id: + An id for uniquely identify each listen only required if you want to Cancel() manually. + You can pass any of the three types here: + -> pyrogram.filters.user + -> pyrogram.filters.chat + -> str + if pyrogram filter's `user` or `chat` is passed as `id` then it gets combined with rest `filters`. + Default is `None` but either filter or id is required. + + timeout: + In seconds (int) for waiting time of getting a response. + Returns: + `update` (like pyrogram.types.Message ...etc) if user reponded within given conditions. + `None` if listen cancelled using `listen.Cancel` + `Exception` An asyncio.TimeoutError is raise if waiting timeout occurs. + Example: + @app.on_message(filters.command('start')) + async def start(client, message): + await client.send_mesage(messsage.chat.id, "What's your name?") + reply_msg = await client.listen.Message(filters.chat(messsage.chat.id), timeout = None) + if reply_msg: + reply_msg.reply(f'hello {reply_msg.text}') + + Method client.listen.Cancel + Parameters: + id: + An id for uniquely identify the listen you want to Cancel() manually. + You can pass any of the three types here: + -> pyrogram.filters.user + -> pyrogram.filters.chat + -> str + Returns: + `Boolean` True if `id` was present and listen was Cancelped or False if `id` was invalid. + + Example: + @app.on_message(filters.command('stop')) + async def stop(client, message): + await client.listen.Cancel(message.from_user.id) + """ + def __init__(self, client : pyrogram.Client): + client.listen = self + self.client = client + self.handlers = {} + self.hdlr_lock = asyncio.Lock() + + async def __add(self, hdlr, filters = None, id = None, timeout = None): + _id = id + + if type(_id) in [pyrogram.filters.InvertFilter, pyrogram.filters.OrFilter, pyrogram.filters.AndFilter]: + raise ValueError('Combined filters are not allowed as unique id .') + + if _id and type(_id) not in [pyrogram.filters.user, pyrogram.filters.chat, str]: + raise TypeError('Unique (id) has to be one of pyrogram\'s filters user/chat or a string.') + + if not (_id or filters): + raise ValueError('Atleast either filters or _id as parameter is required.') + + if str(_id) in self.handlers: + await self.__remove(str(_id)) + #raise ValueError('Dupicate id provided.') + + # callback handler + async def dump(_, update): + await self.__remove(dump._id, update) + + dump._id = str(_id) if _id else hash(dump) + group = -0x3e7 + event = asyncio.Event() + filters = (_id & filters) if _id and filters and not isinstance(_id, str) else filters or (filters if isinstance(_id, str) else _id) + handler = hdlr(dump, filters) + + + if group not in self.client.dispatcher.groups: + self.client.dispatcher.groups[group] = [] + self.client.dispatcher.groups = OrderedDict(sorted(self.client.dispatcher.groups.items())) + + async with self.hdlr_lock: + self.client.dispatcher.groups[group].append(handler) + self.handlers[dump._id] = (handler, group, event) + + try: + await asyncio.wait_for(event.wait(), timeout) + except asyncio.exceptions.TimeoutError: + await self.__remove(dump._id) + raise asyncio.exceptions.TimeoutError + finally: + result = self.handlers.pop(dump._id, None) + self.hdlr_lock.release() + return result + + async def __remove(self, _id, update = None): + handler, group, event = self.handlers[_id] + self.client.dispatcher.groups[group].remove(handler) + await self.hdlr_lock.acquire() + self.handlers[_id] = update + event.set() + + async def Cancel(self, _id) -> bool: + if str(_id) not in self.handlers: + return False + await self.__remove(str(_id)) + return True + + def __getattr__(self, name): + async def wrapper(*args, **kwargs): + return await self.__add(getattr(pyrogram.handlers, f'{name}Handler'), *args, **kwargs) + return wrapper + + from pyrogram import Client, filters from pyrogram.types import Message from asyncio.exceptions import TimeoutError From 6798f72cb37ba3009faf5e61918a4c25dd04195e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadir=20Tar=C4=B1k=20=C4=B0lgin?= <84983622+kadirilgin1453@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:38:56 +0300 Subject: [PATCH 10/10] Update __init__.py --- src/convopyro/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/convopyro/__init__.py b/src/convopyro/__init__.py index 8886a06..67e2492 100644 --- a/src/convopyro/__init__.py +++ b/src/convopyro/__init__.py @@ -138,7 +138,7 @@ async def wrapper(*args, **kwargs): async def listen_message(client:Client, chat_id:Union[int, str, List[Union[int, str]]], timeout:Union[int, None]=None) -> Union[Message, None]: try: - return await client.listen.Message(filters.chat(chat_id), timeout=timeout) + return await client.listen.Message(filters.chat(chat_id), timeout=timeout,id=filters.chat(chat_id)) except TimeoutError: return None