From 584a6a046a1db0142f32581ed0ee3044d432eaed Mon Sep 17 00:00:00 2001 From: Mendel E Date: Mon, 29 Jul 2019 07:01:51 -0400 Subject: [PATCH 1/8] Use shlex.split() for message.command Enables easier and standard parsing, for quote wrapped args, etc. Filters.command now has a posix argument, and the separator argument was removed. shlex.split() works similar to having before separator=None. --- pyrogram/client/filters/filters.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index f80127c2..c785d7d1 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -18,6 +18,7 @@ import re from typing import Callable +from shlex import split from .filter import Filter from ..types.bots_and_keyboards import InlineKeyboardMarkup, ReplyKeyboardMarkup @@ -212,8 +213,8 @@ class Filters: def command( commands: str or list, prefix: str or list = "/", - separator: str = " ", - case_sensitive: bool = False + case_sensitive: bool = False, + posix: bool = True ): """Filter commands, i.e.: text messages starting with "/" or any other custom prefix. @@ -229,13 +230,13 @@ class Filters: Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."]. Can be None or "" (empty string) to allow commands with no prefix at all. - separator (``str``, *optional*): - The command arguments separator. Defaults to " " (white space). - Examples: /start first second, /start-first-second, /start.first.second. - case_sensitive (``bool``, *optional*): Pass True if you want your command(s) to be case sensitive. Defaults to False. Examples: when True, command="Start" would trigger /Start but not /start. + + posix (``bool``, *optional*): + Pass False if you don't want to use shlex posix mode, Defaults to True. + It will strip quotes, and has some other behaviors, read more https://docs.python.org/3/library/shlex.html#parsing-rules """ def func(flt, message): @@ -245,7 +246,7 @@ class Filters: if text: for p in flt.p: if text.startswith(p): - s = text.split(flt.s) + s = split(text, posix=flt.psx) c, a = s[0][len(p):], s[1:] c = c if flt.cs else c.lower() message.command = ([c] + a) if c in flt.c else None @@ -257,7 +258,7 @@ class Filters: commands = {c if case_sensitive else c.lower() for c in commands} prefixes = set(prefix) if prefix else {""} - return create(func, "CommandFilter", c=commands, p=prefixes, s=separator, cs=case_sensitive) + return create(func, "CommandFilter", c=commands, p=prefixes, cs=case_sensitive, psx=posix) @staticmethod def regex(pattern, flags: int = 0): From b4cdf1900c310520029e6deb06422424a1c63fc1 Mon Sep 17 00:00:00 2001 From: Mendel E Date: Mon, 29 Jul 2019 20:41:37 -0400 Subject: [PATCH 2/8] Call shlex.split() only after validating cmd, try/except it. --- pyrogram/client/filters/filters.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index c785d7d1..0c0bc82c 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -246,10 +246,15 @@ class Filters: if text: for p in flt.p: if text.startswith(p): - s = split(text, posix=flt.psx) - c, a = s[0][len(p):], s[1:] + c = text[len(p):].split(None, 1)[0] c = c if flt.cs else c.lower() - message.command = ([c] + a) if c in flt.c else None + if c not in flt.c: + return False + try: + a = split(text, posix=flt.psx)[1:] + message.command = ([c] + a) + except ValueError as e: + message.command = {"text": text[len(p):], "error": e} break return bool(message.command) From d8765080d376d83e70f3ff2e1a76669cb786bf62 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Wed, 31 Jul 2019 23:57:16 +0200 Subject: [PATCH 3/8] Update Filters.command - Removed "posix" parameter because we only want posix=True and the filter becomes simpler. - Figured out how to deal with single backslashes ("\") errors. - Refactor the whole filter: use better names for identifiers. - Rename parameter "prefix" to "prefixes". --- pyrogram/client/filters/filters.py | 50 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index 0c0bc82c..372782cb 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -212,9 +212,8 @@ class Filters: @staticmethod def command( commands: str or list, - prefix: str or list = "/", - case_sensitive: bool = False, - posix: bool = True + prefixes: str or list = "/", + case_sensitive: bool = False ): """Filter commands, i.e.: text messages starting with "/" or any other custom prefix. @@ -225,18 +224,14 @@ class Filters: a command arrives, the command itself and its arguments will be stored in the *command* field of the :obj:`Message`. - prefix (``str`` | ``list``, *optional*): + prefixes (``str`` | ``list``, *optional*): A prefix or a list of prefixes as string the filter should look for. - Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."]. - Can be None or "" (empty string) to allow commands with no prefix at all. + Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."], list(".:!"). + Pass None or "" (empty string) to allow commands with no prefix at all. case_sensitive (``bool``, *optional*): Pass True if you want your command(s) to be case sensitive. Defaults to False. Examples: when True, command="Start" would trigger /Start but not /start. - - posix (``bool``, *optional*): - Pass False if you don't want to use shlex posix mode, Defaults to True. - It will strip quotes, and has some other behaviors, read more https://docs.python.org/3/library/shlex.html#parsing-rules """ def func(flt, message): @@ -244,26 +239,37 @@ class Filters: message.command = None if text: - for p in flt.p: - if text.startswith(p): - c = text[len(p):].split(None, 1)[0] - c = c if flt.cs else c.lower() - if c not in flt.c: + for prefix in flt.prefixes: + if text.startswith(prefix): + command = text[len(prefix):].split()[0] + command = command if flt.case_sensitive else command.lower() + + if command not in flt.commands: return False - try: - a = split(text, posix=flt.psx)[1:] - message.command = ([c] + a) - except ValueError as e: - message.command = {"text": text[len(p):], "error": e} + + text = text.replace("\\", "\\\\") + + args = shlex.split(text)[1:] + message.command = [command] + args + break return bool(message.command) commands = commands if type(commands) is list else [commands] commands = {c if case_sensitive else c.lower() for c in commands} - prefixes = set(prefix) if prefix else {""} - return create(func, "CommandFilter", c=commands, p=prefixes, cs=case_sensitive, psx=posix) + prefixes = [] if prefixes is None else prefixes + prefixes = prefixes if type(prefixes) is list else [prefixes] + prefixes = set(prefixes) if prefixes else {""} + + return create( + func, + "CommandFilter", + commands=commands, + prefixes=prefixes, + case_sensitive=case_sensitive + ) @staticmethod def regex(pattern, flags: int = 0): From c85f991443d1cd83c16d73a4ae6abb497a321de3 Mon Sep 17 00:00:00 2001 From: Mendel E Date: Wed, 7 Aug 2019 11:38:34 -0400 Subject: [PATCH 4/8] Use regex for message.command --- pyrogram/client/filters/filters.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index 372782cb..f74b1b8e 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -18,7 +18,6 @@ import re from typing import Callable -from shlex import split from .filter import Filter from ..types.bots_and_keyboards import InlineKeyboardMarkup, ReplyKeyboardMarkup @@ -233,6 +232,7 @@ class Filters: Pass True if you want your command(s) to be case sensitive. Defaults to False. Examples: when True, command="Start" would trigger /Start but not /start. """ + command_re = re.compile(r"([\"'])(?!\\)(.*?)(? Date: Wed, 7 Aug 2019 22:31:37 -0400 Subject: [PATCH 5/8] Filters.command improvements - Use regex for case sensitivity - Less indentation - Ensure that the command returned is the correct case - Ensure that if the command has more text, it is split by whitespace --- pyrogram/client/filters/filters.py | 34 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index f74b1b8e..a095ed89 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -238,21 +238,31 @@ class Filters: text = message.text or message.caption message.command = None - if text: - for prefix in flt.prefixes: - if text.startswith(prefix): - # groups are 1-indexed, group(1) is the quote, group(2) is the text - # between the quotes, group(3) is unquoted, whitespace-split text - args = [m.group(2) or m.group(3) or "" - for m in re.finditer(command_re, text[len(prefix):])] - command = args[0] if flt.case_sensitive else args[0].lower() + if not text: + return False - if command not in flt.commands: - return False + pattern = r"^{}(?:\s|$)" if flt.case_sensitive else r"(?i)^{}(?:\s|$)" - message.command = args + for prefix in flt.prefixes: + if not text.startswith(prefix): + continue - break + without_prefix = text[len(prefix):] + + for cmd in flt.commands: + + if not re.match(pattern.format(cmd), without_prefix): + continue + + # match.groups are 1-indexed, group(1) is the quote, group(2) is the text + # between the quotes, group(3) is unquoted, whitespace-split text + without_command = without_prefix[len(cmd):] + message.command = [cmd] + [ + m.group(2) or m.group(3) or '' + for m in command_re.finditer(without_command) + ] + + break return bool(message.command) From 5164ea78c207d85e40675801f15adbb963f8af8b Mon Sep 17 00:00:00 2001 From: trenoduro Date: Thu, 8 Aug 2019 15:07:46 +0200 Subject: [PATCH 6/8] Added support for bot_token inside config.ini file (#296) --- pyrogram/client/client.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index 7ac155c2..0e1f9bef 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -110,6 +110,7 @@ class Client(Methods, BaseClient): bot_token (``str``, *optional*): Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" Only applicable for new sessions. + This is an alternative way to set it if you don't want to use the *config.ini* file. phone_number (``str`` | ``callable``, *optional*): Pass your phone number as string (with your Country Code prefix included) to avoid entering it manually. @@ -1228,6 +1229,11 @@ class Client(Methods, BaseClient): def load_config(self): parser = ConfigParser() parser.read(str(self.config_file)) + + if self.bot_token: + pass + else: + self.bot_token = parser.get("pyrogram", "bot_token", fallback=None) if self.api_id and self.api_hash: pass From b55440ab86464f6c4d45bffdc53343ec3434025d Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Thu, 8 Aug 2019 16:04:10 +0200 Subject: [PATCH 7/8] Update Filters.command - Remove negative lookahead to fix "\"" reporting commas - Escape cmd when interpolating the pattern - Remove the escape character from the arguments - Return True when a valid command is found, return False at the end --- pyrogram/client/filters/filters.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index a095ed89..5d892bbe 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -232,7 +232,7 @@ class Filters: Pass True if you want your command(s) to be case sensitive. Defaults to False. Examples: when True, command="Start" would trigger /Start but not /start. """ - command_re = re.compile(r"([\"'])(?!\\)(.*?)(? Date: Sat, 10 Aug 2019 00:54:22 +0200 Subject: [PATCH 8/8] Add export_invite_link bound method (#300) --- pyrogram/client/types/user_and_chats/chat.py | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py index 546485f6..b32dc3e7 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/client/types/user_and_chats/chat.py @@ -714,3 +714,27 @@ class Chat(Object): """ return self._client.leave_chat(self.id) + + + def export_invite_link(self): + """Bound method *export_invite_link* of :obj:`Chat`. + + Use as a shortcut for: + + .. code-block:: python + + client.export_chat_invite_link(123456789) + + Example: + .. code-block:: python + + chat.export_invite_link() + + Returns: + ``str``: On success, the exported invite link is returned. + + Raises: + ValueError: In case the chat_id belongs to a user. + """ + + return self._client.export_invite_link(self.id)