Merge branch 'develop' into asyncio

# Conflicts:
#	pyrogram/client/methods/chats/set_chat_description.py
This commit is contained in:
Dan 2019-04-13 16:26:50 +02:00
commit 9100a43f7b
13 changed files with 127 additions and 79 deletions

View file

@ -95,4 +95,5 @@ PHOTO_EXT_INVALID The photo extension is invalid
EXTERNAL_URL_INVALID The external media URL is invalid EXTERNAL_URL_INVALID The external media URL is invalid
CHAT_NOT_MODIFIED The chat settings were not modified CHAT_NOT_MODIFIED The chat settings were not modified
RESULTS_TOO_MUCH The result contains too many items RESULTS_TOO_MUCH The result contains too many items
RESULT_ID_DUPLICATE The result contains items with duplicated identifiers RESULT_ID_DUPLICATE The result contains items with duplicated identifiers
ACCESS_TOKEN_INVALID The bot access token is invalid
1 id message
95 EXTERNAL_URL_INVALID The external media URL is invalid
96 CHAT_NOT_MODIFIED The chat settings were not modified
97 RESULTS_TOO_MUCH The result contains too many items
98 RESULT_ID_DUPLICATE The result contains items with duplicated identifiers
99 ACCESS_TOKEN_INVALID The bot access token is invalid

View file

@ -10,13 +10,14 @@ can be freely used as basic building blocks for your own applications without wo
Example | Description Example | Description
---: | :--- ---: | :---
[**hello**](hello.py) | Demonstration of basic API usage [**hello_world**](hello_world.py) | Demonstration of basic API usage
[**echo**](echo.py) | Reply to every private text message [**echobot**](echobot.py) | Echo every private text message
[**welcome**](welcome.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat) [**welcome**](welcome.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat)
[**history**](history.py) | Get the full message history of a chat [**history**](history.py) | Get the full message history of a chat
[**chat_members**](chat_members.py) | Get all the members of a chat [**chat_members**](chat_members.py) | Get all the members of a chat
[**dialogs**](dialogs.py) | Get all of your dialog chats [**dialogs**](dialogs.py) | Get all of your dialog chats
[**inline_bots**](inline_bots.py) | Query an inline bot and send a result to a chat [**using_inline_bots**](using_inline_bots.py) | Query an inline bot (as user) and send a result to a chat
[**keyboards**](keyboards.py) | Send normal and inline keyboards using regular bots [**keyboards**](keyboards.py) | Send normal and inline keyboards using regular bots
[**callback_queries**](callback_queries.py) | Handle queries coming from inline button presses [**callback_queries**](callback_queries.py) | Handle queries coming from inline button presses
[**inline_queries**](inline_queries.py) | Handle inline queries
[**raw_updates**](raw_updates.py) | Handle raw updates (old, should be avoided) [**raw_updates**](raw_updates.py) | Handle raw updates (old, should be avoided)

View file

@ -5,12 +5,12 @@ It uses the @on_callback_query decorator to register a CallbackQueryHandler.
from pyrogram import Client from pyrogram import Client
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
@app.on_callback_query() @app.on_callback_query()
def answer(client, callback_query): def answer(client, callback_query):
callback_query.answer('Button contains: "{}"'.format(callback_query.data), show_alert=True) callback_query.answer("Button contains: '{}'".format(callback_query.data), show_alert=True)
app.run() # Automatically start() and idle() app.run() # Automatically start() and idle()

View file

@ -2,7 +2,7 @@
from pyrogram import Client from pyrogram import Client
app = Client("my_count") app = Client("my_account")
target = "pyrogramchat" # Target channel/supergroup target = "pyrogramchat" # Target channel/supergroup
with app: with app:

View file

@ -0,0 +1,54 @@
"""This example shows how to handle inline queries.
Two results are generated when users invoke the bot inline mode, e.g.: @pyrogrambot hi.
It uses the @on_inline_query decorator to register an InlineQueryHandler.
"""
from uuid import uuid4
from pyrogram import (
Client, InlineQueryResultArticle, InputTextMessageContent, InlineKeyboardMarkup, InlineKeyboardButton
)
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
@app.on_inline_query()
def answer(client, inline_query):
inline_query.answer(
results=[
InlineQueryResultArticle(
id=uuid4(),
title="Installation",
input_message_content=InputTextMessageContent(
"Here's how to install **Pyrogram**"
),
url="https://docs.pyrogram.ml/start/Installation",
description="How to install Pyrogram",
thumb_url="https://i.imgur.com/JyxrStE.png",
reply_markup=InlineKeyboardMarkup(
[
[InlineKeyboardButton("Open website", url="https://docs.pyrogram.ml/start/Installation")]
]
)
),
InlineQueryResultArticle(
id=uuid4(),
title="Usage",
input_message_content=InputTextMessageContent(
"Here's how to use **Pyrogram**"
),
url="https://docs.pyrogram.ml/start/Usage",
description="How to use Pyrogram",
thumb_url="https://i.imgur.com/JyxrStE.png",
reply_markup=InlineKeyboardMarkup(
[
[InlineKeyboardButton("Open website", url="https://docs.pyrogram.ml/start/Usage")]
]
)
)
],
cache_time=1
)
app.run() # Automatically start() and idle()

View file

@ -10,7 +10,7 @@ like send_audio(), send_document(), send_location(), etc...
from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
# Create a client using your bot token # Create a client using your bot token
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
with app: with app:
app.send_message( app.send_message(
@ -33,19 +33,17 @@ with app:
reply_markup=InlineKeyboardMarkup( reply_markup=InlineKeyboardMarkup(
[ [
[ # First row [ # First row
InlineKeyboardButton( # Generates a callback query when pressed InlineKeyboardButton( # Generates a callback query when pressed
"Button", "Button",
callback_data=b"data" callback_data=b"data" # Note how callback_data must be bytes
), # Note how callback_data must be bytes ),
InlineKeyboardButton( # Opens a web URL InlineKeyboardButton( # Opens a web URL
"URL", "URL",
url="https://docs.pyrogram.ml" url="https://docs.pyrogram.ml"
), ),
], ],
[ # Second row [ # Second row
# Opens the inline interface InlineKeyboardButton( # Opens the inline interface
InlineKeyboardButton(
"Choose chat", "Choose chat",
switch_inline_query="pyrogram" switch_inline_query="pyrogram"
), ),

View file

@ -30,7 +30,6 @@ import shutil
import struct import struct
import tempfile import tempfile
import time import time
import warnings
from configparser import ConfigParser from configparser import ConfigParser
from datetime import datetime from datetime import datetime
from hashlib import sha256, md5 from hashlib import sha256, md5
@ -41,6 +40,10 @@ from typing import Union, List
from pyrogram.api import functions, types from pyrogram.api import functions, types
from pyrogram.api.core import Object from pyrogram.api.core import Object
from pyrogram.client.handlers import DisconnectHandler
from pyrogram.client.handlers.handler import Handler
from pyrogram.client.methods.password.utils import compute_check
from pyrogram.crypto import AES
from pyrogram.errors import ( from pyrogram.errors import (
PhoneMigrate, NetworkMigrate, PhoneNumberInvalid, PhoneMigrate, NetworkMigrate, PhoneNumberInvalid,
PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty, PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty,
@ -49,10 +52,6 @@ from pyrogram.errors import (
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied, VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied,
PasswordRecoveryNa, PasswordEmpty PasswordRecoveryNa, PasswordEmpty
) )
from pyrogram.client.handlers import DisconnectHandler
from pyrogram.client.handlers.handler import Handler
from pyrogram.client.methods.password.utils import compute_check
from pyrogram.crypto import AES
from pyrogram.session import Auth, Session from pyrogram.session import Auth, Session
from .ext.utils import ainput from .ext.utils import ainput
from .ext import utils, Syncer, BaseClient, Dispatcher from .ext import utils, Syncer, BaseClient, Dispatcher
@ -283,10 +282,10 @@ class Client(Methods, BaseClient):
self.is_bot = True self.is_bot = True
self.bot_token = self.session_name self.bot_token = self.session_name
self.session_name = self.session_name.split(":")[0] self.session_name = self.session_name.split(":")[0]
warnings.warn('\nYou are using a bot token as session name.\n' log.warning('\nWARNING: You are using a bot token as session name!\n'
'It will be deprecated in next update, please use session file name to load ' 'This usage will be deprecated soon. Please use a session file name to load '
'existing sessions and bot_token argument to create new sessions.', 'an existing session and the bot_token argument to create new sessions.\n'
DeprecationWarning, stacklevel=2) 'More info: https://docs.pyrogram.ml/start/Setup#bot-authorization\n')
self.load_config() self.load_config()
await self.load_session() await self.load_session()

View file

@ -222,14 +222,16 @@ class Filters:
- poll""" - poll"""
@staticmethod @staticmethod
def command(command: str or list, def command(
prefix: str or list = "/", commands: str or list,
separator: str = " ", prefix: str or list = "/",
case_sensitive: bool = False): separator: str = " ",
case_sensitive: bool = False
):
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix. """Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
Args: Args:
command (``str`` | ``list``): commands (``str`` | ``list``):
The command or list of commands as string the filter should look for. The command or list of commands as string the filter should look for.
Examples: "start", ["start", "help", "settings"]. When a message text containing Examples: "start", ["start", "help", "settings"]. When a message text containing
a command arrives, the command itself and its arguments will be stored in the *command* a command arrives, the command itself and its arguments will be stored in the *command*
@ -249,31 +251,25 @@ class Filters:
Examples: when True, command="Start" would trigger /Start but not /start. Examples: when True, command="Start" would trigger /Start but not /start.
""" """
def f(_, m): def func(flt, message):
if m.text: text = message.text or message.caption
for i in _.p:
if m.text.startswith(i): if text:
t = m.text.split(_.s) for p in flt.p:
c, a = t[0][len(i):], t[1:] if text.startswith(p):
c = c if _.cs else c.lower() s = text.split(flt.s)
m.command = ([c] + a) if c in _.c else None 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
break break
return bool(m.command) return bool(message.command)
return create( commands = commands if type(commands) is list else [commands]
"Command", commands = {c if case_sensitive else c.lower() for c in commands}
f, prefixes = set(prefix) if prefix else {""}
c={command if case_sensitive
else command.lower()} return create("Command", func=func, c=commands, p=prefixes, s=separator, cs=case_sensitive)
if not isinstance(command, list)
else {c if case_sensitive
else c.lower()
for c in command},
p=set(prefix) if prefix else {""},
s=separator,
cs=case_sensitive
)
@staticmethod @staticmethod
def regex(pattern, flags: int = 0): def regex(pattern, flags: int = 0):
@ -311,21 +307,20 @@ class Filters:
def __init__(self, users: int or str or list = None): def __init__(self, users: int or str or list = None):
users = [] if users is None else users if type(users) is list else [users] users = [] if users is None else users if type(users) is list else [users]
super().__init__( super().__init__(
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in users} "me" if u in ["me", "self"]
if type(users) is list else else u.lower().strip("@") if type(u) is str
{"me" if users in ["me", "self"] else users.lower().strip("@") if type(users) is str else users} else u for u in users
) )
def __call__(self, message): def __call__(self, message):
return bool( return (message.from_user
message.from_user and (message.from_user.id in self
and (message.from_user.id in self or (message.from_user.username
or (message.from_user.username and message.from_user.username.lower() in self)
and message.from_user.username.lower() in self) or ("me" in self
or ("me" in self and message.from_user.is_self)))
and message.from_user.is_self))
)
# noinspection PyPep8Naming # noinspection PyPep8Naming
class chat(Filter, set): class chat(Filter, set):
@ -343,21 +338,21 @@ class Filters:
def __init__(self, chats: int or str or list = None): def __init__(self, chats: int or str or list = None):
chats = [] if chats is None else chats if type(chats) is list else [chats] chats = [] if chats is None else chats if type(chats) is list else [chats]
super().__init__( super().__init__(
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in chats} "me" if c in ["me", "self"]
if type(chats) is list else else c.lower().strip("@") if type(c) is str
{"me" if chats in ["me", "self"] else chats.lower().strip("@") if type(chats) is str else chats} else c for c in chats
) )
def __call__(self, message): def __call__(self, message):
return bool( return (message.chat
message.chat and (message.chat.id in self
and (message.chat.id in self or (message.chat.username
or (message.chat.username and message.chat.username.lower() in self)
and message.chat.username.lower() in self) or ("me" in self
or ("me" in self and message.from_user and message.from_user
and message.from_user.is_self and message.from_user.is_self
and not message.outgoing)) and not message.outgoing)))
)
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162)) dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))

View file

@ -47,15 +47,13 @@ class SetChatDescription(BaseClient):
""" """
peer = await self.resolve_peer(chat_id) peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChannel): if isinstance(peer, (types.InputPeerChannel, types.InputPeerChat)):
await self.send( await self.send(
functions.channels.EditAbout( functions.messages.EditChatAbout(
channel=peer, peer=peer,
about=description about=description
) )
) )
elif isinstance(peer, types.InputPeerChat):
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
else: else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))

View file

@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
from pyrogram.api import types from pyrogram.api import types
from .inline_query_result import InlineQueryResult from .inline_query_result import InlineQueryResult
@ -61,7 +63,7 @@ class InlineQueryResultArticle(InlineQueryResult):
def __init__( def __init__(
self, self,
id: str, id: Any,
title: str, title: str,
input_message_content, input_message_content,
reply_markup=None, reply_markup=None,
@ -84,7 +86,7 @@ class InlineQueryResultArticle(InlineQueryResult):
def write(self): def write(self):
return types.InputBotInlineResult( return types.InputBotInlineResult(
id=self.id, id=str(self.id),
type=self.type, type=self.type,
send_message=self.input_message_content.write(self.reply_markup), send_message=self.input_message_content.write(self.reply_markup),
title=self.title, title=self.title,