mirror of
https://github.com/pyrogram/pyrogram
synced 2025-08-28 12:57:52 +00:00
Merge branch 'develop' into session_storage
# Conflicts: # pyrogram/client/client.py # pyrogram/client/ext/base_client.py # pyrogram/client/ext/syncer.py # pyrogram/client/style/html.py # pyrogram/client/style/markdown.py
This commit is contained in:
commit
952f0627f1
@ -32,7 +32,7 @@ Features
|
||||
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
||||
- **Documented**: Pyrogram API methods, types and public interfaces are well documented.
|
||||
- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted.
|
||||
- **Updated**, to the latest Telegram API version, currently Layer 91 on top of `MTProto 2.0`_.
|
||||
- **Updated**, to the latest Telegram API version, currently Layer 97 on top of `MTProto 2.0`_.
|
||||
- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code.
|
||||
- **Comprehensive**: Execute any advanced action an official client is able to do, and even more.
|
||||
|
||||
@ -107,7 +107,7 @@ Copyright & License
|
||||
</a>
|
||||
<br>
|
||||
<a href="compiler/api/source/main_api.tl">
|
||||
<img src="https://img.shields.io/badge/schema-layer%2091-eda738.svg?longCache=true&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/schema-layer%2097-eda738.svg?longCache=true&colorA=262b30"
|
||||
alt="Schema Layer">
|
||||
</a>
|
||||
<a href="https://github.com/pyrogram/tgcrypto">
|
||||
@ -122,7 +122,7 @@ Copyright & License
|
||||
|
||||
.. |description| replace:: **Telegram MTProto API Framework for Python**
|
||||
|
||||
.. |schema| image:: https://img.shields.io/badge/schema-layer%2091-eda738.svg?longCache=true&colorA=262b30
|
||||
.. |schema| image:: https://img.shields.io/badge/schema-layer%2097-eda738.svg?longCache=true&colorA=262b30
|
||||
:target: compiler/api/source/main_api.tl
|
||||
:alt: Schema Layer
|
||||
|
||||
|
@ -171,8 +171,8 @@ def start():
|
||||
shutil.rmtree("{}/functions".format(DESTINATION), ignore_errors=True)
|
||||
|
||||
with open("{}/source/auth_key.tl".format(HOME), encoding="utf-8") as auth, \
|
||||
open("{}/source/sys_msgs.tl".format(HOME), encoding="utf-8") as system, \
|
||||
open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api:
|
||||
open("{}/source/sys_msgs.tl".format(HOME), encoding="utf-8") as system, \
|
||||
open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api:
|
||||
schema = (auth.read() + system.read() + api.read()).splitlines()
|
||||
|
||||
with open("{}/template/mtproto.txt".format(HOME), encoding="utf-8") as f:
|
||||
@ -287,9 +287,11 @@ def start():
|
||||
|
||||
sorted_args = sort_args(c.args)
|
||||
|
||||
arguments = ", " + ", ".join(
|
||||
[get_argument_type(i) for i in sorted_args if i != ("flags", "#")]
|
||||
) if c.args else ""
|
||||
arguments = (
|
||||
", "
|
||||
+ ("*, " if c.args else "")
|
||||
+ (", ".join([get_argument_type(i) for i in sorted_args if i != ("flags", "#")]) if c.args else "")
|
||||
)
|
||||
|
||||
fields = "\n ".join(
|
||||
["self.{0} = {0} # {1}".format(i[0], i[1]) for i in c.args if i != ("flags", "#")]
|
||||
@ -333,7 +335,7 @@ def start():
|
||||
docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args
|
||||
|
||||
if c.section == "functions":
|
||||
docstring_args += "\n\n Raises:\n :obj:`Error <pyrogram.Error>`"
|
||||
docstring_args += "\n\n Raises:\n :obj:`RPCError <pyrogram.RPCError>`"
|
||||
docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type)
|
||||
else:
|
||||
references = get_references(".".join(filter(None, [c.namespace, c.name])))
|
||||
@ -456,7 +458,11 @@ def start():
|
||||
fields=fields,
|
||||
read_types=read_types,
|
||||
write_types=write_types,
|
||||
return_arguments=", ".join([i[0] for i in sorted_args if i != ("flags", "#")])
|
||||
return_arguments=", ".join(
|
||||
["{0}={0}".format(i[0]) for i in sorted_args if i != ("flags", "#")]
|
||||
),
|
||||
slots=", ".join(['"{}"'.format(i[0]) for i in sorted_args if i != ("flags", "#")]),
|
||||
qualname="{}{}".format("{}.".format(c.namespace) if c.namespace else "", c.name)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -83,7 +83,7 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
|
||||
fileLocation#91d11eb dc_id:int volume_id:long local_id:int secret:long file_reference:bytes = FileLocation;
|
||||
|
||||
userEmpty#200250ba id:int = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
user#2e13f4c3 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
|
||||
@ -96,12 +96,12 @@ userStatusLastWeek#7bf09fc = UserStatus;
|
||||
userStatusLastMonth#77ebc742 = UserStatus;
|
||||
|
||||
chatEmpty#9ba2d800 id:int = Chat;
|
||||
chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
|
||||
chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
|
||||
chatForbidden#7328bdb id:int title:string = Chat;
|
||||
channel#c88974ac flags:# creator:flags.0?true left:flags.2?true editor:flags.3?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChannelAdminRights banned_rights:flags.15?ChannelBannedRights participants_count:flags.17?int = Chat;
|
||||
channel#4df30834 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat;
|
||||
channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
|
||||
|
||||
chatFull#edd2a791 flags:# id:int participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
|
||||
chatFull#22a235da flags:# can_set_username:flags.7?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int = ChatFull;
|
||||
channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
|
||||
|
||||
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
|
||||
@ -163,6 +163,7 @@ photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_r
|
||||
photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#296f104 long:double lat:double access_hash:long = GeoPoint;
|
||||
@ -186,8 +187,7 @@ peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bo
|
||||
|
||||
peerSettings#818426cd flags:# report_spam:flags.0?true = PeerSettings;
|
||||
|
||||
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
|
||||
wallPaperSolid#63117f24 id:int title:string bg_color:int color:int = WallPaper;
|
||||
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
|
||||
|
||||
inputReportReasonSpam#58dbcab8 = ReportReason;
|
||||
inputReportReasonViolence#1e22c78d = ReportReason;
|
||||
@ -221,7 +221,7 @@ messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<
|
||||
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;
|
||||
|
||||
messages.messages#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesSlice#b446ae3 count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesSlice#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
|
||||
messages.messagesNotModified#74535f21 count:int = messages.Messages;
|
||||
|
||||
@ -281,7 +281,6 @@ updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
|
||||
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
|
||||
updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
|
||||
updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
|
||||
updateChatAdmins#6e947941 chat_id:int enabled:Bool version:int = Update;
|
||||
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
|
||||
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
|
||||
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
|
||||
@ -316,8 +315,9 @@ updateContactsReset#7084a7be = Update;
|
||||
updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
|
||||
updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
|
||||
updateUserPinnedMessage#4c43da18 user_id:int id:int = Update;
|
||||
updateChatPinnedMessage#22893b26 chat_id:int id:int = Update;
|
||||
updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
|
||||
updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update;
|
||||
updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
|
||||
|
||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||
|
||||
@ -382,7 +382,7 @@ inputDocumentEmpty#72f0eaae = InputDocument;
|
||||
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
|
||||
|
||||
documentEmpty#36f8c871 id:long = Document;
|
||||
document#59534e4c id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
|
||||
document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
|
||||
|
||||
help.support#17c6b5f6 phone_number:string user:User = help.Support;
|
||||
|
||||
@ -411,11 +411,15 @@ inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
|
||||
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
|
||||
inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
|
||||
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
|
||||
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
|
||||
|
||||
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
|
||||
privacyKeyChatInvite#500e6dfa = PrivacyKey;
|
||||
privacyKeyPhoneCall#3d662b7b = PrivacyKey;
|
||||
privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
|
||||
privacyKeyForwards#69ec56a3 = PrivacyKey;
|
||||
privacyKeyProfilePhoto#96151fed = PrivacyKey;
|
||||
|
||||
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
|
||||
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
|
||||
@ -487,7 +491,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
|
||||
stickerSet#5585a139 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
|
||||
stickerSet#6a90bcb7 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
@ -544,8 +548,8 @@ channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:
|
||||
channelParticipant#15ebac1d user_id:int date:int = ChannelParticipant;
|
||||
channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
|
||||
channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant;
|
||||
channelParticipantAdmin#a82fa898 flags:# can_edit:flags.0?true user_id:int inviter_id:int promoted_by:int date:int admin_rights:ChannelAdminRights = ChannelParticipant;
|
||||
channelParticipantBanned#222c1886 flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChannelBannedRights = ChannelParticipant;
|
||||
channelParticipantAdmin#5daa6e23 flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights = ChannelParticipant;
|
||||
channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = ChannelParticipant;
|
||||
|
||||
channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
|
||||
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
|
||||
@ -553,6 +557,7 @@ channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
|
||||
channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
|
||||
channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
|
||||
|
||||
channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
|
||||
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
|
||||
@ -594,7 +599,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
|
||||
|
||||
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
|
||||
|
||||
messageFwdHeader#559ebe6d flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
|
||||
messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
|
||||
|
||||
auth.codeTypeSms#72a3158c = auth.CodeType;
|
||||
auth.codeTypeCall#741cd3e3 = auth.CodeType;
|
||||
@ -789,10 +794,6 @@ langPackDifference#f385c1f6 lang_code:string from_version:int version:int string
|
||||
|
||||
langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;
|
||||
|
||||
channelAdminRights#5d7ceba5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true invite_link:flags.6?true pin_messages:flags.7?true add_admins:flags.9?true manage_call:flags.10?true = ChannelAdminRights;
|
||||
|
||||
channelBannedRights#58cf4249 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true until_date:int = ChannelBannedRights;
|
||||
|
||||
channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction;
|
||||
@ -809,6 +810,8 @@ channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:Channel
|
||||
channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
|
||||
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
|
||||
|
||||
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
|
||||
|
||||
@ -972,6 +975,31 @@ chatOnlines#f041e250 onlines:int = ChatOnlines;
|
||||
|
||||
statsURL#47a971e0 url:string = StatsURL;
|
||||
|
||||
chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true = ChatAdminRights;
|
||||
|
||||
chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true until_date:int = ChatBannedRights;
|
||||
|
||||
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
|
||||
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
|
||||
|
||||
account.wallPapersNotModified#1c199183 = account.WallPapers;
|
||||
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
|
||||
|
||||
codeSettings#302f59f3 flags:# allow_flashcall:flags.0?true current_number:flags.1?true app_hash_persistent:flags.2?true app_hash:flags.3?string = CodeSettings;
|
||||
|
||||
wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
|
||||
|
||||
autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int = AutoDownloadSettings;
|
||||
|
||||
account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;
|
||||
|
||||
emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
|
||||
emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword;
|
||||
|
||||
emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference;
|
||||
|
||||
emojiURL#a575739d url:string = EmojiURL;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -982,7 +1010,7 @@ invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
|
||||
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
|
||||
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||
|
||||
auth.sendCode#86aef0ec flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool api_id:int api_hash:string = auth.SentCode;
|
||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||
auth.signUp#1b067634 phone_number:string phone_code_hash:string phone_code:string first_name:string last_name:string = auth.Authorization;
|
||||
auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
|
||||
auth.logOut#5717da40 = Bool;
|
||||
@ -1005,7 +1033,7 @@ account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
|
||||
account.resetNotifySettings#db7e1747 = Bool;
|
||||
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
|
||||
account.updateStatus#6628562c offline:Bool = Bool;
|
||||
account.getWallPapers#c04cfac2 = Vector<WallPaper>;
|
||||
account.getWallPapers#aabb1763 hash:int = account.WallPapers;
|
||||
account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = Bool;
|
||||
account.checkUsername#2714d86c username:string = Bool;
|
||||
account.updateUsername#3e0bdd7c username:string = User;
|
||||
@ -1014,7 +1042,7 @@ account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> =
|
||||
account.deleteAccount#418d4e0b reason:string = Bool;
|
||||
account.getAccountTTL#8fc711d = AccountDaysTTL;
|
||||
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
|
||||
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode;
|
||||
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
|
||||
account.updateDeviceLocked#38df3532 period:int = Bool;
|
||||
account.getAuthorizations#e320c158 = account.Authorizations;
|
||||
@ -1022,7 +1050,7 @@ account.resetAuthorization#df77f3bc hash:long = Bool;
|
||||
account.getPassword#548a30f5 = account.Password;
|
||||
account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
|
||||
account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
|
||||
account.sendConfirmPhoneCode#1516d7bd flags:# allow_flashcall:flags.0?true hash:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode;
|
||||
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
|
||||
account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
|
||||
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
|
||||
@ -1034,7 +1062,7 @@ account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long =
|
||||
account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool;
|
||||
account.getAuthorizationForm#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
|
||||
account.acceptAuthorization#e7027c94 bot_id:int scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool;
|
||||
account.sendVerifyPhoneCode#823380b4 flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;
|
||||
account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
|
||||
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
|
||||
account.sendVerifyEmailCode#7011509f email:string = account.SentEmailCode;
|
||||
account.verifyEmail#ecba39db email:string code:string = Bool;
|
||||
@ -1046,6 +1074,13 @@ account.cancelPasswordEmail#c1cbd5b6 = Bool;
|
||||
account.getContactSignUpNotification#9f07c728 = Bool;
|
||||
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
|
||||
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
|
||||
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
|
||||
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
|
||||
account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
|
||||
account.resetWallPapers#bb3b9804 = Bool;
|
||||
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
|
||||
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
|
||||
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
@ -1074,7 +1109,7 @@ messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int
|
||||
messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
|
||||
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
|
||||
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
|
||||
messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int = messages.AffectedHistory;
|
||||
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
@ -1107,7 +1142,7 @@ messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages
|
||||
messages.getStickers#43d4f2c emoticon:string hash:int = messages.Stickers;
|
||||
messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
|
||||
messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
|
||||
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
|
||||
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
|
||||
messages.importChatInvite#6c50051c hash:string = Updates;
|
||||
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
|
||||
@ -1115,7 +1150,6 @@ messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = m
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
|
||||
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
|
||||
messages.toggleChatAdmins#ec8bd9e1 chat_id:int enabled:Bool = Updates;
|
||||
messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
|
||||
messages.migrateChat#15a3b8e3 chat_id:int = Updates;
|
||||
messages.searchGlobal#9e3cacb0 q:string offset_date:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
|
||||
@ -1173,7 +1207,12 @@ messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer
|
||||
messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
|
||||
messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates;
|
||||
messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
|
||||
messages.getStatsURL#83f6c0cd peer:InputPeer = StatsURL;
|
||||
messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL;
|
||||
messages.editChatAbout#def60797 peer:InputPeer about:string = Bool;
|
||||
messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates;
|
||||
messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
|
||||
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
|
||||
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
|
||||
|
||||
updates.getState#edd4882a = updates.State;
|
||||
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
|
||||
@ -1223,8 +1262,7 @@ channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channe
|
||||
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
|
||||
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
|
||||
channels.createChannel#f4893d7f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string = Updates;
|
||||
channels.editAbout#13e27f1e channel:InputChannel about:string = Bool;
|
||||
channels.editAdmin#20b88214 channel:InputChannel user_id:InputUser admin_rights:ChannelAdminRights = Updates;
|
||||
channels.editAdmin#70f893ba channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights = Updates;
|
||||
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
|
||||
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
|
||||
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
|
||||
@ -1232,13 +1270,11 @@ channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
|
||||
channels.joinChannel#24b524c5 channel:InputChannel = Updates;
|
||||
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
|
||||
channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
|
||||
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
|
||||
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
|
||||
channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
|
||||
channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
|
||||
channels.editBanned#bfd915cd channel:InputChannel user_id:InputUser banned_rights:ChannelBannedRights = Updates;
|
||||
channels.editBanned#72796912 channel:InputChannel user_id:InputUser banned_rights:ChatBannedRights = Updates;
|
||||
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
|
||||
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
|
||||
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
|
||||
@ -1267,13 +1303,13 @@ phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtoc
|
||||
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
|
||||
phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
|
||||
phone.discardCall#78d413a6 peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
|
||||
phone.setCallRating#1c536a34 peer:InputPhoneCall rating:int comment:string = Updates;
|
||||
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
|
||||
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
|
||||
|
||||
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
|
||||
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
|
||||
langpack.getDifference#9d51e814 lang_code:string from_version:int = LangPackDifference;
|
||||
langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference;
|
||||
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
|
||||
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
|
||||
|
||||
// LAYER 91
|
||||
// LAYER 97
|
||||
|
@ -9,7 +9,10 @@ class {class_name}(Object):
|
||||
"""{docstring_args}
|
||||
"""
|
||||
|
||||
__slots__ = [{slots}]
|
||||
|
||||
ID = {object_id}
|
||||
QUALNAME = "{qualname}"
|
||||
|
||||
def __init__(self{arguments}):
|
||||
{fields}
|
||||
|
@ -22,7 +22,7 @@ import re
|
||||
import shutil
|
||||
|
||||
HOME = "compiler/error"
|
||||
DEST = "pyrogram/api/errors/exceptions"
|
||||
DEST = "pyrogram/errors/exceptions"
|
||||
NOTICE_PATH = "NOTICE"
|
||||
|
||||
|
||||
@ -73,7 +73,7 @@ def start():
|
||||
f_init.write("from .{}_{} import *\n".format(name.lower(), code))
|
||||
|
||||
with open("{}/source/{}".format(HOME, i), encoding="utf-8") as f_csv, \
|
||||
open("{}/{}_{}.py".format(DEST, name.lower(), code), "w", encoding="utf-8") as f_class:
|
||||
open("{}/{}_{}.py".format(DEST, name.lower(), code), "w", encoding="utf-8") as f_class:
|
||||
reader = csv.reader(f_csv, delimiter="\t")
|
||||
|
||||
super_class = caml(name)
|
||||
@ -134,7 +134,7 @@ def start():
|
||||
|
||||
if "__main__" == __name__:
|
||||
HOME = "."
|
||||
DEST = "../../pyrogram/api/errors/exceptions"
|
||||
DEST = "../../pyrogram/errors/exceptions"
|
||||
NOTICE_PATH = "../../NOTICE"
|
||||
|
||||
start()
|
||||
|
@ -88,5 +88,12 @@ MEDIA_INVALID The media is invalid
|
||||
BOT_SCORE_NOT_MODIFIED The bot score was not modified
|
||||
USER_BOT_REQUIRED The method can be used by bots only
|
||||
IMAGE_PROCESS_FAILED The server failed to process your image
|
||||
USERNAME_NOT_MODIFIED The username was not modified
|
||||
CALL_ALREADY_ACCEPTED The call is already accepted
|
||||
CALL_ALREADY_DECLINED The call is already declined
|
||||
PHOTO_EXT_INVALID The photo extension is invalid
|
||||
EXTERNAL_URL_INVALID The external media URL is invalid
|
||||
CHAT_NOT_MODIFIED The chat settings were not modified
|
||||
RESULTS_TOO_MUCH The result contains too many items
|
||||
RESULT_ID_DUPLICATE The result contains items with duplicated identifiers
|
||||
ACCESS_TOKEN_INVALID The bot access token is invalid
|
|
@ -1,12 +1,12 @@
|
||||
{notice}
|
||||
|
||||
from ..error import Error
|
||||
from ..rpc_error import RPCError
|
||||
|
||||
|
||||
class {super_class}(Error):
|
||||
class {super_class}(RPCError):
|
||||
{docstring}
|
||||
CODE = {code}
|
||||
"""``int``: Error Code"""
|
||||
"""``int``: RPC Error Code"""
|
||||
NAME = __doc__
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
class {sub_class}({super_class}):
|
||||
{docstring}
|
||||
ID = {id}
|
||||
"""``str``: Error ID"""
|
||||
"""``str``: RPC Error ID"""
|
||||
MESSAGE = __doc__
|
||||
|
||||
|
||||
|
@ -25,6 +25,10 @@ sys.path.insert(0, os.path.abspath('../..'))
|
||||
# Import after sys.path.insert() to avoid issues
|
||||
from pyrogram import __version__
|
||||
|
||||
from pygments.styles.friendly import FriendlyStyle
|
||||
|
||||
FriendlyStyle.background_color = "#f3f2f1"
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@ -60,7 +64,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Pyrogram'
|
||||
copyright = '2017-2018, Dan Tès'
|
||||
copyright = '2017-2019, Dan Tès'
|
||||
author = 'Dan Tès'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@ -85,7 +89,7 @@ language = None
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'tango'
|
||||
pygments_style = 'friendly'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
@ -1,8 +1,7 @@
|
||||
400 - Bad Request
|
||||
=================
|
||||
|
||||
.. module:: pyrogram.api.errors.BadRequest
|
||||
.. module:: pyrogram.errors.BadRequest
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.bad_request_400
|
||||
.. automodule:: pyrogram.errors.exceptions.bad_request_400
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
420 - Flood
|
||||
===========
|
||||
|
||||
.. module:: pyrogram.api.errors.Flood
|
||||
.. module:: pyrogram.errors.Flood
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.flood_420
|
||||
.. automodule:: pyrogram.errors.exceptions.flood_420
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
403 - Forbidden
|
||||
===============
|
||||
|
||||
.. module:: pyrogram.api.errors.Forbidden
|
||||
.. module:: pyrogram.errors.Forbidden
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.forbidden_403
|
||||
.. automodule:: pyrogram.errors.exceptions.forbidden_403
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
500 - Internal Server Error
|
||||
===========================
|
||||
|
||||
.. module:: pyrogram.api.errors.InternalServerError
|
||||
.. module:: pyrogram.errors.InternalServerError
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.internal_server_error_500
|
||||
.. automodule:: pyrogram.errors.exceptions.internal_server_error_500
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
406 - Not Acceptable
|
||||
====================
|
||||
|
||||
.. module:: pyrogram.api.errors.NotAcceptable
|
||||
.. module:: pyrogram.errors.NotAcceptable
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.not_acceptable_406
|
||||
.. automodule:: pyrogram.errors.exceptions.not_acceptable_406
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
303 - See Other
|
||||
===============
|
||||
|
||||
.. module:: pyrogram.api.errors.SeeOther
|
||||
.. module:: pyrogram.errors.SeeOther
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.see_other_303
|
||||
.. automodule:: pyrogram.errors.exceptions.see_other_303
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
401 - Unauthorized
|
||||
==================
|
||||
|
||||
.. module:: pyrogram.api.errors.Unauthorized
|
||||
.. module:: pyrogram.errors.Unauthorized
|
||||
|
||||
.. automodule:: pyrogram.api.errors.exceptions.unauthorized_401
|
||||
.. automodule:: pyrogram.errors.exceptions.unauthorized_401
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -1,8 +1,7 @@
|
||||
520 - Unknown Error
|
||||
===================
|
||||
|
||||
.. module:: pyrogram.api.errors.UnknownError
|
||||
.. module:: pyrogram.errors.UnknownError
|
||||
|
||||
.. autoexception:: pyrogram.api.errors.error.UnknownError
|
||||
.. autoexception:: pyrogram.errors.rpc_error.UnknownError
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
@ -26,7 +26,7 @@ Welcome to Pyrogram
|
||||
</a>
|
||||
<br>
|
||||
<a href="compiler/api/source/main_api.tl">
|
||||
<img src="https://img.shields.io/badge/schema-layer%2091-eda738.svg?longCache=true&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/schema-layer%2097-eda738.svg?longCache=true&colorA=262b30"
|
||||
alt="Schema Layer">
|
||||
</a>
|
||||
<a href="https://github.com/pyrogram/tgcrypto">
|
||||
@ -67,7 +67,7 @@ Features
|
||||
- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C.
|
||||
- **Documented**: Pyrogram API methods, types and public interfaces are well documented.
|
||||
- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted.
|
||||
- **Updated**, to the latest Telegram API version, currently Layer 91 on top of `MTProto 2.0`_.
|
||||
- **Updated**, to the latest Telegram API version, currently Layer 97 on top of `MTProto 2.0`_.
|
||||
- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code.
|
||||
- **Comprehensive**: Execute any advanced action an official client is able to do, and even more.
|
||||
|
||||
@ -115,7 +115,7 @@ To get started, press the Next button.
|
||||
functions/index
|
||||
types/index
|
||||
|
||||
.. _`Telegram`: https://telegram.org/
|
||||
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto/
|
||||
.. _`Telegram`: https://telegram.org
|
||||
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
|
||||
.. _`MTProto API`: https://core.telegram.org/api#telegram-api
|
||||
.. _`MTProto 2.0`: https://core.telegram.org/mtproto
|
||||
.. _`MTProto 2.0`: https://core.telegram.org/mtproto
|
||||
|
@ -31,6 +31,7 @@ Decorators
|
||||
|
||||
on_message
|
||||
on_callback_query
|
||||
on_inline_query
|
||||
on_deleted_messages
|
||||
on_user_status
|
||||
on_disconnect
|
||||
@ -56,6 +57,7 @@ Messages
|
||||
send_location
|
||||
send_venue
|
||||
send_contact
|
||||
send_cached_media
|
||||
send_chat_action
|
||||
edit_message_text
|
||||
edit_message_caption
|
||||
@ -67,6 +69,7 @@ Messages
|
||||
iter_history
|
||||
send_poll
|
||||
vote_poll
|
||||
close_poll
|
||||
retract_vote
|
||||
download_media
|
||||
|
||||
@ -97,6 +100,8 @@ Chats
|
||||
iter_chat_members
|
||||
get_dialogs
|
||||
iter_dialogs
|
||||
restrict_chat
|
||||
update_chat_username
|
||||
|
||||
Users
|
||||
-----
|
||||
@ -109,6 +114,7 @@ Users
|
||||
get_user_profile_photos
|
||||
set_user_profile_photo
|
||||
delete_user_profile_photos
|
||||
update_username
|
||||
|
||||
Contacts
|
||||
--------
|
||||
@ -139,10 +145,12 @@ Bots
|
||||
get_inline_bot_results
|
||||
send_inline_bot_result
|
||||
answer_callback_query
|
||||
answer_inline_query
|
||||
request_callback_answer
|
||||
send_game
|
||||
set_game_score
|
||||
get_game_high_scores
|
||||
answer_inline_query
|
||||
|
||||
|
||||
.. autoclass:: pyrogram.Client
|
||||
|
@ -9,6 +9,7 @@ Handlers
|
||||
MessageHandler
|
||||
DeletedMessagesHandler
|
||||
CallbackQueryHandler
|
||||
InlineQueryHandler
|
||||
UserStatusHandler
|
||||
DisconnectHandler
|
||||
RawUpdateHandler
|
||||
@ -22,6 +23,9 @@ Handlers
|
||||
.. autoclass:: CallbackQueryHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: InlineQueryHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: UserStatusHandler
|
||||
:members:
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
Error
|
||||
=====
|
||||
RPCError
|
||||
========
|
||||
|
||||
.. autoexception:: pyrogram.Error
|
||||
.. autoexception:: pyrogram.RPCError
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. toctree::
|
||||
../errors/SeeOther
|
@ -16,6 +16,7 @@ Users & Chats
|
||||
ChatPhoto
|
||||
ChatMember
|
||||
ChatMembers
|
||||
ChatPermissions
|
||||
Dialog
|
||||
Dialogs
|
||||
|
||||
@ -65,6 +66,7 @@ Input Media
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
InputMedia
|
||||
InputMediaPhoto
|
||||
InputMediaVideo
|
||||
InputMediaAudio
|
||||
@ -72,6 +74,25 @@ Input Media
|
||||
InputMediaDocument
|
||||
InputPhoneContact
|
||||
|
||||
Inline Mode
|
||||
------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
InlineQuery
|
||||
InlineQueryResult
|
||||
InlineQueryResultArticle
|
||||
|
||||
InputMessageContent
|
||||
-------------------
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
|
||||
InputMessageContent
|
||||
InputTextMessageContent
|
||||
|
||||
.. User & Chats
|
||||
------------
|
||||
|
||||
@ -96,6 +117,9 @@ Input Media
|
||||
.. autoclass:: ChatMembers
|
||||
:members:
|
||||
|
||||
.. autoclass:: ChatPermissions
|
||||
:members:
|
||||
|
||||
.. autoclass:: Dialog
|
||||
:members:
|
||||
|
||||
@ -195,6 +219,9 @@ Input Media
|
||||
.. Input Media
|
||||
-----------
|
||||
|
||||
.. autoclass:: InputMedia
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputMediaPhoto
|
||||
:members:
|
||||
|
||||
@ -212,3 +239,25 @@ Input Media
|
||||
|
||||
.. autoclass:: InputPhoneContact
|
||||
:members:
|
||||
|
||||
|
||||
.. Inline Mode
|
||||
-----------
|
||||
|
||||
.. autoclass:: InlineQuery
|
||||
:members:
|
||||
|
||||
.. autoclass:: InlineQueryResult
|
||||
:members:
|
||||
|
||||
.. autoclass:: InlineQueryResultArticle
|
||||
:members:
|
||||
|
||||
.. InputMessageContent
|
||||
-------------------
|
||||
|
||||
.. autoclass:: InputMessageContent
|
||||
:members:
|
||||
|
||||
.. autoclass:: InputTextMessageContent
|
||||
:members:
|
||||
|
@ -15,6 +15,6 @@ after the well established `Telegram Bot API`_ methods, thus offering a familiar
|
||||
Filters
|
||||
ChatAction
|
||||
ParseMode
|
||||
Error
|
||||
RPCError
|
||||
|
||||
.. _Telegram Bot API: https://core.telegram.org/bots/api#available-methods
|
||||
|
@ -1,40 +1,102 @@
|
||||
Advanced Usage
|
||||
==============
|
||||
|
||||
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main Telegram
|
||||
API with its raw functions and types.
|
||||
Pyrogram's API, which consists of well documented convenience methods_ and facade types_, exists to provide a much
|
||||
easier interface to the undocumented and often confusing Telegram API.
|
||||
|
||||
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main "raw"
|
||||
Telegram API with its functions and types.
|
||||
|
||||
Telegram Raw API
|
||||
----------------
|
||||
|
||||
If you can't find a high-level method for your needs or if you want complete, low-level access to the whole
|
||||
Telegram API, you have to use the raw :mod:`functions <pyrogram.api.functions>` and :mod:`types <pyrogram.api.types>`
|
||||
exposed by the ``pyrogram.api`` package and call any Telegram API method you wish using the
|
||||
:meth:`send() <pyrogram.Client.send>` method provided by the Client class.
|
||||
Telegram API, you have to use the raw :mod:`functions <pyrogram.api.functions>` and :mod:`types <pyrogram.api.types>`.
|
||||
|
||||
As already hinted, raw functions and types can be really confusing, mainly because people don't realize soon enough they
|
||||
accept *only* the right types and that all required parameters must be filled in. This section will therefore explain
|
||||
some pitfalls to take into consideration when working with the raw API.
|
||||
|
||||
.. hint::
|
||||
|
||||
Every available high-level method mentioned in the previous page is built on top of these raw functions.
|
||||
Every available high-level methods in Pyrogram is built on top of these raw functions.
|
||||
|
||||
Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already
|
||||
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
|
||||
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API (yet much more
|
||||
powerful).
|
||||
|
||||
If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
|
||||
|
||||
Caveats
|
||||
-------
|
||||
Invoking Functions
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
As hinted before, raw functions and types can be confusing, mainly because people don't realize they must accept
|
||||
*exactly* the right values, but also because most of them don't have enough Python experience to fully grasp how things
|
||||
work.
|
||||
Unlike the methods_ found in Pyrogram's API, which can be called in the usual simple way, functions to be invoked from
|
||||
the raw Telegram API have a different way of usage and are more complex.
|
||||
|
||||
This section will therefore explain some pitfalls to take into consideration when working with the raw API.
|
||||
First of all, both `raw functions`_ and `raw types`_ live in their respective packages (and sub-packages):
|
||||
``pyrogram.api.functions``, ``pyrogram.api.types``. They all exist as Python classes, meaning you need to create an
|
||||
instance of each every time you need them and fill them in with the correct values using named arguments.
|
||||
|
||||
Next, to actually invoke the raw function you have to use the :meth:`send() <pyrogram.Client.send>` method provided by
|
||||
the Client class and pass the function object you created.
|
||||
|
||||
Here's some examples:
|
||||
|
||||
- Update first name, last name and bio:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.UpdateProfile(
|
||||
first_name="Dan", last_name="Tès",
|
||||
about="Bio written from Pyrogram"
|
||||
)
|
||||
)
|
||||
|
||||
- Disable links to your account when someone forwards your messages:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.SetPrivacy(
|
||||
key=types.PrivacyKeyForwards(),
|
||||
rules=[types.InputPrivacyValueDisallowAll()]
|
||||
)
|
||||
)
|
||||
|
||||
- Invite users to your channel/supergroup:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.channels.InviteToChannel(
|
||||
channel=app.resolve_peer(123456789), # ID or Username
|
||||
users=[ # The users you want to invite
|
||||
app.resolve_peer(23456789), # By ID
|
||||
app.resolve_peer("username"), # By username
|
||||
app.resolve_peer("+393281234567"), # By phone number
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
Chat IDs
|
||||
^^^^^^^^
|
||||
|
||||
The way Telegram works makes it impossible to directly send a message to a user or a chat by using their IDs only.
|
||||
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed.
|
||||
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed. Pyrogram allows
|
||||
sending messages with IDs only thanks to cached access hashes.
|
||||
|
||||
There are three different InputPeer types, one for each kind of Telegram entity.
|
||||
Whenever an InputPeer is needed you must pass one of these:
|
||||
@ -56,66 +118,19 @@ kind of ID.
|
||||
|
||||
For example, given the ID *123456789*, here's how Pyrogram can tell entities apart:
|
||||
|
||||
- ``+ID`` - User: *123456789*
|
||||
- ``-ID`` - Chat: *-123456789*
|
||||
- ``-100ID`` - Channel (and Supergroup): *-100123456789*
|
||||
- ``+ID`` User: *123456789*
|
||||
- ``-ID`` Chat: *-123456789*
|
||||
- ``-100ID`` Channel (and Supergroup): *-100123456789*
|
||||
|
||||
So, every time you take a raw ID, make sure to translate it into the correct ID when you want to use it with an
|
||||
high-level method.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
- Update first name, last name and bio:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.UpdateProfile(
|
||||
first_name="Dan", last_name="Tès",
|
||||
about="Bio written from Pyrogram"
|
||||
)
|
||||
)
|
||||
|
||||
- Share your Last Seen time only with your contacts:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.account.SetPrivacy(
|
||||
key=types.InputPrivacyKeyStatusTimestamp(),
|
||||
rules=[types.InputPrivacyValueAllowContacts()]
|
||||
)
|
||||
)
|
||||
|
||||
- Invite users to your channel/supergroup:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram.api import functions, types
|
||||
|
||||
with Client("my_account") as app:
|
||||
app.send(
|
||||
functions.channels.InviteToChannel(
|
||||
channel=app.resolve_peer(123456789), # ID or Username
|
||||
users=[ # The users you want to invite
|
||||
app.resolve_peer(23456789), # By ID
|
||||
app.resolve_peer("username"), # By username
|
||||
app.resolve_peer("393281234567"), # By phone number
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
.. _methods: ../pyrogram/Client.html#messages
|
||||
.. _types: ../pyrogram/Types.html
|
||||
.. _plenty of them: ../pyrogram/Client.html#messages
|
||||
.. _Raw Functions: Usage.html#using-raw-functions
|
||||
.. _raw functions: ../pyrogram/functions
|
||||
.. _raw types: ../pyrogram/types
|
||||
.. _Community: https://t.me/PyrogramChat
|
@ -1,13 +1,13 @@
|
||||
Configuration File
|
||||
==================
|
||||
|
||||
As already mentioned in previous sections, Pyrogram can also be configured by the use of an INI file.
|
||||
As already mentioned in previous sections, Pyrogram can be configured by the use of an INI file.
|
||||
This page explains how this file is structured in Pyrogram, how to use it and why.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The idea behind using a configuration file is to help keeping your code free of settings (private) information such as
|
||||
The idea behind using a configuration file is to help keeping your code free of private settings information such as
|
||||
the API Key and Proxy without having you to even deal with how to load such settings. The configuration file, usually
|
||||
referred as ``config.ini`` file, is automatically loaded from the root of your working directory; all you need to do is
|
||||
fill in the necessary parts.
|
||||
@ -46,7 +46,7 @@ These are all the sections Pyrogram uses in its configuration file:
|
||||
Pyrogram
|
||||
^^^^^^^^
|
||||
|
||||
The ``[pyrogram]`` section contains your Telegram API credentials *api_id* and *api_hash*.
|
||||
The ``[pyrogram]`` section contains your Telegram API credentials: *api_id* and *api_hash*.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
|
@ -1,19 +1,19 @@
|
||||
Customize Sessions
|
||||
==================
|
||||
|
||||
As you may probably know, Telegram allows Users (and Bots) having more than one session (authorizations) registered
|
||||
As you may probably know, Telegram allows users (and bots) having more than one session (authorizations) registered
|
||||
in the system at the same time.
|
||||
|
||||
Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official
|
||||
app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram) and store some useful
|
||||
information about the client who generated them.
|
||||
app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram). They store some
|
||||
useful information such as the client who's using them and from which country and IP address.
|
||||
|
||||
|
||||
.. figure:: https://i.imgur.com/lzGPCdZ.png
|
||||
:width: 70%
|
||||
:align: center
|
||||
|
||||
A Pyrogram session running on Linux, Python 3.6.
|
||||
**A Pyrogram session running on Linux, Python 3.6.**
|
||||
|
||||
That's how a session looks like on the Android app, showing the three main pieces of information.
|
||||
|
||||
|
@ -4,18 +4,18 @@ Error Handling
|
||||
Errors are inevitable when working with the API, and they must be correctly handled with ``try..except`` blocks.
|
||||
|
||||
There are many errors that Telegram could return, but they all fall in one of these categories
|
||||
(which are in turn children of the :obj:`pyrogram.Error` superclass)
|
||||
(which are in turn children of the :obj:`RPCError <pyrogram.RPCError>` superclass):
|
||||
|
||||
- :obj:`303 - See Other <pyrogram.api.errors.SeeOther>`
|
||||
- :obj:`400 - Bad Request <pyrogram.api.errors.BadRequest>`
|
||||
- :obj:`401 - Unauthorized <pyrogram.api.errors.Unauthorized>`
|
||||
- :obj:`403 - Forbidden <pyrogram.api.errors.Forbidden>`
|
||||
- :obj:`406 - Not Acceptable <pyrogram.api.errors.NotAcceptable>`
|
||||
- :obj:`420 - Flood <pyrogram.api.errors.Flood>`
|
||||
- :obj:`500 - Internal Server Error <pyrogram.api.errors.InternalServerError>`
|
||||
- :obj:`303 - See Other <pyrogram.errors.SeeOther>`
|
||||
- :obj:`400 - Bad Request <pyrogram.errors.BadRequest>`
|
||||
- :obj:`401 - Unauthorized <pyrogram.errors.Unauthorized>`
|
||||
- :obj:`403 - Forbidden <pyrogram.errors.Forbidden>`
|
||||
- :obj:`406 - Not Acceptable <pyrogram.errors.NotAcceptable>`
|
||||
- :obj:`420 - Flood <pyrogram.errors.Flood>`
|
||||
- :obj:`500 - Internal Server Error <pyrogram.errors.InternalServerError>`
|
||||
|
||||
As stated above, there are really many (too many) errors, and in case Pyrogram does not know anything yet about a
|
||||
specific one, it raises a special :obj:`520 Unknown Error <pyrogram.api.errors.UnknownError>` exception and logs it
|
||||
specific one, it raises a special :obj:`520 Unknown Error <pyrogram.errors.UnknownError>` exception and logs it
|
||||
in the ``unknown_errors.txt`` file. Users are invited to report these unknown errors; in later versions of Pyrogram
|
||||
some kind of automatic error reporting module might be implemented.
|
||||
|
||||
@ -24,7 +24,7 @@ Examples
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram.api.errors import (
|
||||
from pyrogram.errors import (
|
||||
BadRequest, Flood, InternalServerError,
|
||||
SeeOther, Unauthorized, UnknownError
|
||||
)
|
||||
@ -45,13 +45,13 @@ Examples
|
||||
pass
|
||||
|
||||
Exception objects may also contain some informative values.
|
||||
E.g.: :obj:`FloodWait <pyrogram.api.errors.exceptions.flood_420.FloodWait>` holds the amount of seconds you have to wait
|
||||
E.g.: :obj:`FloodWait <pyrogram.errors.exceptions.flood_420.FloodWait>` holds the amount of seconds you have to wait
|
||||
before you can try again. The value is always stored in the ``x`` field of the returned exception object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import time
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from pyrogram.errors import FloodWait
|
||||
|
||||
try:
|
||||
...
|
||||
|
@ -1,24 +1,22 @@
|
||||
More on Updates
|
||||
===============
|
||||
|
||||
Here we'll show some advanced usages when working with updates.
|
||||
|
||||
.. note::
|
||||
This page makes use of Handlers and Filters to show you how to handle updates.
|
||||
Learn more at `Update Handling <UpdateHandling.html>`_ and `Using Filters <UsingFilters.html>`_.
|
||||
Here we'll show some advanced usages when working with `update handlers`_ and `filters`_.
|
||||
|
||||
Handler Groups
|
||||
--------------
|
||||
|
||||
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
|
||||
If you register handlers with overlapping (conflicting) filters, only the first one is executed and any other handler
|
||||
will be ignored. This is intended by design.
|
||||
|
||||
In order to process the same update more than once, you can register your handler in a different group.
|
||||
Groups are identified by a number (number 0 being the default) and are sorted, that is, a lower group number has a
|
||||
higher priority.
|
||||
In order to handle the very same update more than once, you have to register your handler in a different dispatching
|
||||
group. Dispatching groups hold one or more handlers and are processed sequentially, they are identified by a number
|
||||
(number 0 being the default) and sorted, that is, a lower group number has a higher priority:
|
||||
|
||||
For example, in:
|
||||
For example, take these two handlers:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 1, 6
|
||||
|
||||
@app.on_message(Filters.text | Filters.sticker)
|
||||
def text_or_sticker(client, message):
|
||||
@ -29,8 +27,8 @@ For example, in:
|
||||
def just_text(client, message):
|
||||
print("Just Text")
|
||||
|
||||
``just_text`` is never executed because ``text_or_sticker`` already handles texts. To enable it, simply register the
|
||||
function using a different group:
|
||||
Here, ``just_text`` is never executed because ``text_or_sticker``, which has been registered first, already handles
|
||||
texts (``Filters.text`` is shared and conflicting). To enable it, register the function using a different group:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -69,7 +67,7 @@ continue to propagate the same update to the next groups until all the handlers
|
||||
|
||||
@app.on_message(Filters.private, group=1)
|
||||
def _(client, message):
|
||||
print(1 / 0) # Unhandled exception: ZeroDivisionError
|
||||
raise Exception("Unhandled exception!") # Simulate an unhandled exception
|
||||
|
||||
|
||||
@app.on_message(Filters.private, group=2)
|
||||
@ -82,7 +80,7 @@ The output for each incoming update will therefore be:
|
||||
.. code-block:: text
|
||||
|
||||
0
|
||||
ZeroDivisionError: division by zero
|
||||
Exception: Unhandled exception!
|
||||
2
|
||||
|
||||
Stop Propagation
|
||||
@ -153,9 +151,9 @@ Continue Propagation
|
||||
|
||||
As opposed to `stopping the update propagation <#stop-propagation>`_ and also as an alternative to the
|
||||
`handler groups <#handler-groups>`_, you can signal the internal dispatcher to continue the update propagation within
|
||||
the group regardless of the next handler's filters. This allows you to register multiple handlers with overlapping
|
||||
filters in the same group; to let the dispatcher process the next handler you can do *one* of the following in each
|
||||
handler you want to grant permission to continue:
|
||||
**the same group** regardless of the next handler's filters. This allows you to register multiple handlers with
|
||||
overlapping filters in the same group; to let the dispatcher process the next handler you can do *one* of the following
|
||||
in each handler you want to grant permission to continue:
|
||||
|
||||
- Call the update's bound-method ``.continue_propagation()`` (preferred way).
|
||||
- Manually ``raise ContinuePropagation`` exception (more suitable for raw updates only).
|
||||
@ -218,4 +216,7 @@ The output of both (equivalent) examples will be:
|
||||
|
||||
0
|
||||
1
|
||||
2
|
||||
2
|
||||
|
||||
.. _`update handlers`: UpdateHandling.html
|
||||
.. _`filters`: UsingFilters.html
|
@ -13,8 +13,8 @@ Introduction
|
||||
------------
|
||||
|
||||
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
|
||||
your applications, you had to put your function definitions in separate files and register them inside your main script,
|
||||
like this:
|
||||
your applications, you had to put your function definitions in separate files and register them inside your main script
|
||||
after importing your modules, like this:
|
||||
|
||||
.. note::
|
||||
|
||||
@ -72,7 +72,7 @@ functions. So, what if you could? Smart Plugins solve this issue by taking care
|
||||
Using Smart Plugins
|
||||
-------------------
|
||||
|
||||
Setting up your Pyrogram project to accommodate Smart Plugins is straightforward:
|
||||
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
|
||||
|
||||
#. Create a new folder to store all the plugins (e.g.: "plugins", "handlers", ...).
|
||||
#. Put your python files full of plugins inside. Organize them as you wish.
|
||||
@ -129,18 +129,17 @@ Setting up your Pyrogram project to accommodate Smart Plugins is straightforward
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
plugins = dict(
|
||||
root="plugins"
|
||||
)
|
||||
plugins = dict(root="plugins")
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
|
||||
The first important thing to note is the new ``plugins`` folder. You can put *any python file* in *any subfolder* and
|
||||
each file can contain *any decorated function* (handlers) with one limitation: within a single module (file) you must
|
||||
use different names for each decorated function.
|
||||
|
||||
The second thing is telling Pyrogram where to look for your plugins: you can either use the *config.ini* file or
|
||||
the Client parameter "plugins"; the *root* value must match the name of your plugins folder. Your Pyrogram Client
|
||||
the Client parameter "plugins"; the *root* value must match the name of your plugins root folder. Your Pyrogram Client
|
||||
instance will **automatically** scan the folder upon starting to search for valid handlers and register them for you.
|
||||
|
||||
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
|
||||
@ -161,7 +160,7 @@ found inside each module will be, instead, loaded in the order they are defined,
|
||||
|
||||
This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or
|
||||
exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude``
|
||||
keys, either in the *config.ini* file or in the dictionary passed as Client argument. Here's how they work:
|
||||
directives, either in the *config.ini* file or in the dictionary passed as Client argument. Here's how they work:
|
||||
|
||||
- If both ``include`` and ``exclude`` are omitted, all plugins are loaded as described above.
|
||||
- If ``include`` is given, only the specified plugins will be loaded, in the order they are passed.
|
||||
@ -214,9 +213,7 @@ also organized in subfolders:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plugins = dict(
|
||||
root="plugins"
|
||||
)
|
||||
plugins = dict(root="plugins")
|
||||
|
||||
Client("my_account", plugins=plugins).run()
|
||||
|
||||
@ -293,7 +290,7 @@ Load/Unload Plugins at Runtime
|
||||
|
||||
In the `previous section <#specifying-the-plugins-to-include>`_ we've explained how to specify which plugins to load and
|
||||
which to ignore before your Client starts. Here we'll show, instead, how to unload and load again a previously
|
||||
registered plugins at runtime.
|
||||
registered plugin at runtime.
|
||||
|
||||
Each function decorated with the usual ``on_message`` decorator (or any other decorator that deals with Telegram updates
|
||||
) will be modified in such a way that, when you reference them later on, they will be actually pointing to a tuple of
|
||||
@ -314,14 +311,14 @@ attribute. Here's an example:
|
||||
|
||||
- Printing ``echo`` will show something like ``(<MessageHandler object at 0x10e3abc50>, 0)``.
|
||||
|
||||
- Printing ``echo[0].callback``, that is, the *callback* attribute of the first eleent of the tuple, which is an
|
||||
- Printing ``echo[0].callback``, that is, the *callback* attribute of the first element of the tuple, which is an
|
||||
Handler, will reveal the actual callback ``<function echo at 0x10e3b6598>``.
|
||||
|
||||
Unloading
|
||||
^^^^^^^^^
|
||||
|
||||
In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it (by importing the
|
||||
relevant module) and call :meth:`remove_handler <pyrogram.Client.remove_handler>` Client's method with your function
|
||||
In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it by importing the
|
||||
relevant module and call :meth:`remove_handler() <pyrogram.Client.remove_handler>` Client's method with your function
|
||||
name preceded by the star ``*`` operator as argument. Example:
|
||||
|
||||
- ``main.py``
|
||||
@ -346,7 +343,7 @@ Loading
|
||||
^^^^^^^
|
||||
|
||||
Similarly to the unloading process, in order to load again a previously unloaded plugin you do the same, but this time
|
||||
using :meth:`add_handler <pyrogram.Client.add_handler>` instead. Example:
|
||||
using :meth:`add_handler() <pyrogram.Client.add_handler>` instead. Example:
|
||||
|
||||
- ``main.py``
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
Update Handling
|
||||
===============
|
||||
|
||||
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
|
||||
and can be handled by registering one or more callback functions in your app by using `Handlers <../pyrogram/Handlers.html>`_.
|
||||
Let's now dive right into the core of the framework.
|
||||
|
||||
To put it simply, whenever an update is received from Telegram it will be dispatched and your previously defined callback
|
||||
function(s) matching it will be called back with the update itself as argument.
|
||||
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
|
||||
and are handled by registering one or more callback functions in your app using `Handlers <../pyrogram/Handlers.html>`_.
|
||||
|
||||
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
|
||||
function will be called.
|
||||
|
||||
Registering an Handler
|
||||
----------------------
|
||||
@ -15,13 +17,34 @@ To explain how handlers work let's have a look at the most used one, the
|
||||
updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles
|
||||
settings them up once you learn from this section.
|
||||
|
||||
Using add_handler()
|
||||
-------------------
|
||||
|
||||
The :meth:`add_handler() <pyrogram.Client.add_handler>` method takes any handler instance that wraps around your defined
|
||||
callback function and registers it in your Client. Here's a full example that prints out the content of a message as
|
||||
soon as it arrives:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, MessageHandler
|
||||
|
||||
|
||||
def my_function(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
my_handler = MessageHandler(my_function)
|
||||
app.add_handler(my_handler)
|
||||
|
||||
app.run()
|
||||
|
||||
Using Decorators
|
||||
----------------
|
||||
|
||||
The easiest and nicest way to register a MessageHandler is by decorating your function with the
|
||||
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
|
||||
of a message as soon as it arrives.
|
||||
A much nicer way to register a MessageHandler is by decorating your callback function with the
|
||||
:meth:`on_message() <pyrogram.Client.on_message>` decorator, which will still make use of add_handler() under the hood.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -37,23 +60,13 @@ of a message as soon as it arrives.
|
||||
|
||||
app.run()
|
||||
|
||||
Using add_handler()
|
||||
-------------------
|
||||
|
||||
If you prefer not to use decorators for any reason, there is an alternative way for registering Handlers.
|
||||
This is useful, for example, when you want to keep your callback functions in separate files.
|
||||
.. note::
|
||||
|
||||
.. code-block:: python
|
||||
Due to how these decorators work in Pyrogram, they will wrap your defined callback function in a tuple consisting of
|
||||
``(handler, group)``; this will be the value held by your function identifier (e.g.: *my_function* from the example
|
||||
above).
|
||||
|
||||
from pyrogram import Client, MessageHandler
|
||||
|
||||
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
app.add_handler(MessageHandler(my_handler))
|
||||
|
||||
app.run()
|
||||
In case, for some reason, you want to get your own function back after it has been decorated, you need to access
|
||||
``my_function[0].callback``, that is, the *callback* field of the *handler* object which is the first element in the
|
||||
tuple.
|
@ -1,17 +1,19 @@
|
||||
Using Filters
|
||||
=============
|
||||
|
||||
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
|
||||
:class:`Filters <pyrogram.Filters>`.
|
||||
So far we've seen how to register a callback function that executes every time a specific update comes from the server,
|
||||
but there's much more than that to come.
|
||||
|
||||
.. note::
|
||||
This page makes use of Handlers to show you how to handle updates.
|
||||
Learn more at `Update Handling <UpdateHandling.html>`_.
|
||||
Here we'll discuss about :class:`Filters <pyrogram.Filters>`. Filters enable a fine-grain control over what kind of
|
||||
updates are allowed or not to be passed in your callback functions, based on their inner details.
|
||||
|
||||
Let's start right away with a simple example:
|
||||
|
||||
- This example will show you how to **only** handle messages containing an :obj:`Audio <pyrogram.Audio>` object and
|
||||
ignore any other message:
|
||||
ignore any other message. Filters are passed as the first argument of the decorator:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4
|
||||
|
||||
from pyrogram import Filters
|
||||
|
||||
@ -20,9 +22,10 @@ For a finer grained control over what kind of messages will be allowed or not in
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- or, without decorators:
|
||||
- or, without decorators. Here filters are passed as the second argument of the handler constructor:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 8
|
||||
|
||||
from pyrogram import Filters, MessageHandler
|
||||
|
||||
@ -37,7 +40,7 @@ Combining Filters
|
||||
-----------------
|
||||
|
||||
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
|
||||
operators:
|
||||
operators ``~``, ``&`` and ``|``:
|
||||
|
||||
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
|
||||
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
|
||||
@ -74,7 +77,7 @@ can also accept arguments:
|
||||
def my_handler(client, message):
|
||||
print(message)
|
||||
|
||||
- Message is a **text** message matching the given **regex** pattern.
|
||||
- Message is a **text** message or a media **caption** matching the given **regex** pattern.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -104,17 +107,17 @@ Custom Filters
|
||||
--------------
|
||||
|
||||
Pyrogram already provides lots of built-in :class:`Filters <pyrogram.Filters>` to work with, but in case you can't find
|
||||
a specific one for your needs or want to build a custom filter by yourself (to be used in a different handler, for
|
||||
example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
a specific one for your needs or want to build a custom filter by yourself (to be used in a different kind of handler,
|
||||
for example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
|
||||
.. note::
|
||||
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`
|
||||
only.
|
||||
|
||||
An example to demonstrate how custom filters work is to show how to create and use one for the
|
||||
:obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by Bots;
|
||||
create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline keyboard to
|
||||
yourself. This allows you to test your filter by pressing the inline button:
|
||||
:obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by
|
||||
bots; create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline
|
||||
keyboard to yourself. This allows you to test your filter by pressing the inline button:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -133,26 +136,27 @@ Basic Filters
|
||||
|
||||
For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
|
||||
The code below creates a simple filter for hardcoded callback data. This filter will only allow callback queries
|
||||
containing "pyrogram" as data:
|
||||
The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries
|
||||
containing "Pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data
|
||||
equals to ``b"Pyrogram"``.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
hardcoded_data = Filters.create(
|
||||
name="HardcodedData",
|
||||
func=lambda filter, callback_query: callback_query.data == b"pyrogram"
|
||||
static_data = Filters.create(
|
||||
name="StaticdData",
|
||||
func=lambda flt, callback_query: callback_query.data == b"Pyrogram"
|
||||
)
|
||||
|
||||
The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same
|
||||
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter itself:
|
||||
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def func(filter, callback_query):
|
||||
return callback_query.data == b"pyrogram"
|
||||
def func(flt, callback_query):
|
||||
return callback_query.data == b"Pyrogram"
|
||||
|
||||
hardcoded_data = Filters.create(
|
||||
name="HardcodedData",
|
||||
static_data = Filters.create(
|
||||
name="StaticData",
|
||||
func=func
|
||||
)
|
||||
|
||||
@ -160,14 +164,14 @@ The filter usage remains the same:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(hardcoded_data)
|
||||
@app.on_callback_query(static_data)
|
||||
def pyrogram_data(client, callback_query):
|
||||
client.answer_callback_query(callback_query.id, "it works!")
|
||||
|
||||
Filters with Arguments
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A much cooler filter would be one that accepts "pyrogram" or any other data as argument at usage time.
|
||||
A much cooler filter would be one that accepts "Pyrogram" or any other data as argument at usage time.
|
||||
A dynamic filter like this will make use of the third parameter of :meth:`Filters.create() <pyrogram.Filters.create>`.
|
||||
|
||||
This is how a dynamic custom filter looks like:
|
||||
@ -177,7 +181,7 @@ This is how a dynamic custom filter looks like:
|
||||
def dynamic_data(data):
|
||||
return Filters.create(
|
||||
name="DynamicData",
|
||||
func=lambda filter, callback_query: filter.data == callback_query.data,
|
||||
func=lambda flt, callback_query: flt.data == callback_query.data,
|
||||
data=data # "data" kwarg is accessed with "filter.data"
|
||||
)
|
||||
|
||||
@ -185,6 +189,6 @@ And its usage:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@app.on_callback_query(dynamic_data(b"pyrogram"))
|
||||
@app.on_callback_query(dynamic_data(b"Pyrogram"))
|
||||
def pyrogram_data(client, callback_query):
|
||||
client.answer_callback_query(callback_query.id, "it works!")
|
@ -1,11 +1,11 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
Being a Python library, Pyrogram requires Python to be installed in your system.
|
||||
Being a Python library, **Pyrogram** requires Python to be installed in your system.
|
||||
We recommend using the latest version of Python 3 and pip.
|
||||
|
||||
Get Python 3 from https://www.python.org/downloads/ (or with your package manager) and pip
|
||||
by following the instructions at https://pip.pypa.io/en/latest/installing/.
|
||||
- Get **Python 3** from https://www.python.org/downloads/ (or with your package manager)
|
||||
- Get **pip** by following the instructions at https://pip.pypa.io/en/latest/installing/.
|
||||
|
||||
.. important::
|
||||
|
||||
@ -29,8 +29,12 @@ Install Pyrogram
|
||||
Bleeding Edge
|
||||
-------------
|
||||
|
||||
If you want the latest development version of Pyrogram, you can install it straight from the develop_
|
||||
branch using this command (note "develop.zip" in the link):
|
||||
Things are constantly evolving in Pyrogram, although new releases are published only when enough changes are added,
|
||||
but this doesn't mean you can't try new features right now!
|
||||
|
||||
In case you would like to try out the latest Pyrogram features and additions, the `GitHub repo`_ is always kept updated
|
||||
with new changes; you can install the development version straight from the ``develop`` branch using this command
|
||||
(note "develop.zip" in the link):
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@ -39,10 +43,10 @@ branch using this command (note "develop.zip" in the link):
|
||||
Asynchronous
|
||||
------------
|
||||
|
||||
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging client library after all), and here's
|
||||
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging framework after all), and here's
|
||||
where asyncio shines the most by providing extra performance while running on a single OS-level thread only.
|
||||
|
||||
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5+ required).
|
||||
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5.3+ required).
|
||||
Use this command to install (note "asyncio.zip" in the link):
|
||||
|
||||
.. code-block:: text
|
||||
@ -82,7 +86,7 @@ If no error shows up you are good to go.
|
||||
|
||||
>>> import pyrogram
|
||||
>>> pyrogram.__version__
|
||||
'0.11.0'
|
||||
'0.12.0'
|
||||
|
||||
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
|
||||
.. _develop: http://github.com/pyrogram/pyrogram
|
||||
.. _`Github repo`: http://github.com/pyrogram/pyrogram
|
||||
|
@ -15,23 +15,22 @@ If you already have one you can skip this step, otherwise:
|
||||
#. Fill out the form to register a new Telegram application.
|
||||
#. Done. The API key consists of two parts: **App api_id** and **App api_hash**.
|
||||
|
||||
|
||||
.. important::
|
||||
|
||||
This API key is personal and should be kept secret.
|
||||
This API key is personal and must be kept secret.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The API key obtained in the `previous step <#api-keys>`_ defines a token for your application allowing you to access
|
||||
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both Users and Bots**.
|
||||
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both users and bots**.
|
||||
|
||||
Having it handy, it's time to configure your Pyrogram project. There are two ways to do so, and you can choose what
|
||||
fits better for you:
|
||||
|
||||
- Create a new ``config.ini`` file at the root of your working directory, copy-paste the following and replace the
|
||||
**api_id** and **api_hash** values with your own. This is the preferred method because allows you
|
||||
to keep your credentials out of your code without having to deal with how to load them:
|
||||
**api_id** and **api_hash** values with your own. This is the preferred method because allows you to keep your
|
||||
credentials out of your code without having to deal with how to load them:
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
@ -39,8 +38,8 @@ fits better for you:
|
||||
api_id = 12345
|
||||
api_hash = 0123456789abcdef0123456789abcdef
|
||||
|
||||
- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash*
|
||||
parameters of the Client class. This way you can have full control on how to store and load your credentials:
|
||||
- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* parameters of the
|
||||
Client class. This way you can have full control on how to store and load your credentials:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -54,16 +53,16 @@ fits better for you:
|
||||
|
||||
.. note::
|
||||
|
||||
The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
|
||||
and *api_hash* parameters usage.
|
||||
From now on, the code snippets assume you are using the ``config.ini`` file, thus they won't show the *api_id* and
|
||||
*api_hash* parameters usage to keep them as clean as possible.
|
||||
|
||||
User Authorization
|
||||
------------------
|
||||
|
||||
In order to use the API, Telegram requires that Users be authorized via their phone numbers.
|
||||
Pyrogram automatically manages this access, all you need to do is create an instance of
|
||||
the :class:`Client <pyrogram.Client>` class by passing to it a ``session_name`` of your choice
|
||||
(e.g.: "my_account") and call the :meth:`run() <pyrogram.Client.run>` method:
|
||||
In order to use the API, Telegram requires that users be authorized via their phone numbers.
|
||||
Pyrogram automatically manages this access, all you need to do is create an instance of the
|
||||
:class:`Client <pyrogram.Client>` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call
|
||||
the :meth:`run() <pyrogram.Client.run>` method:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -80,30 +79,40 @@ and the **phone code** you will receive:
|
||||
Enter phone number: +39**********
|
||||
Is "+39**********" correct? (y/n): y
|
||||
Enter phone code: 32768
|
||||
Logged in successfully as Dan
|
||||
|
||||
After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing
|
||||
Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app,
|
||||
and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
||||
After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing Pyrogram
|
||||
executing API calls with your identity. This file will be loaded again when you restart your app, and as long as you
|
||||
keep the session alive, Pyrogram won't ask you again to enter your phone number.
|
||||
|
||||
.. important::
|
||||
|
||||
Your ``*.session`` files are personal and must be kept secret.
|
||||
|
||||
.. note::
|
||||
|
||||
The code above does nothing except asking for credentials and keeping the client online, hit ``CTRL+C`` now to stop
|
||||
your application and keep reading.
|
||||
|
||||
Bot Authorization
|
||||
-----------------
|
||||
|
||||
Bots are a special kind of users and are authorized via their tokens (instead of phone numbers), which are created by
|
||||
BotFather_. Bot tokens replace the Users' phone numbers only — you still need to
|
||||
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using Bots.
|
||||
Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by
|
||||
BotFather_. Bot tokens replace the users' phone numbers only — you still need to
|
||||
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using bots.
|
||||
|
||||
The authorization process is automatically managed. All you need to do is pass the bot token as ``session_name``.
|
||||
The session file will be named after the Bot user_id, which is ``123456.session`` for the example below.
|
||||
The authorization process is automatically managed. All you need to do is choose a ``session_name`` (can be anything,
|
||||
usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named
|
||||
after the session name, which will be ``pyrogrambot.session`` for the example below.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
app = Client(
|
||||
"pyrogrambot",
|
||||
bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
)
|
||||
app.run()
|
||||
|
||||
.. _installed Pyrogram: Installation.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
Usage
|
||||
=====
|
||||
|
||||
Having your `project set up`_ and your account authorized_, it's time to play with the API. Let's start!
|
||||
Having your `project set up`_ and your account authorized_, it's time to start playing with the API. Let's start!
|
||||
|
||||
High-level API
|
||||
--------------
|
||||
@ -11,34 +11,36 @@ named after the `Telegram Bot API`_.
|
||||
|
||||
Here's a simple example:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
app = Client("my_account")
|
||||
|
||||
app.start()
|
||||
app.start()
|
||||
|
||||
print(app.get_me())
|
||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
||||
app.send_location("me", 51.500729, -0.124583)
|
||||
print(app.get_me())
|
||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
||||
app.send_location("me", 51.500729, -0.124583)
|
||||
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
|
||||
|
||||
app.stop()
|
||||
app.stop()
|
||||
|
||||
You can also use Pyrogram in a context manager with the ``with`` statement. The Client will automatically
|
||||
:meth:`start <pyrogram.Client.start>` and :meth:`stop <pyrogram.Client.stop>` gracefully, even in case of unhandled
|
||||
exceptions in your code:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_account")
|
||||
app = Client("my_account")
|
||||
|
||||
with app:
|
||||
print(app.get_me())
|
||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
||||
app.send_location("me", 51.500729, -0.124583)
|
||||
with app:
|
||||
print(app.get_me())
|
||||
app.send_message("me", "Hi there! I'm using **Pyrogram**")
|
||||
app.send_location("me", 51.500729, -0.124583)
|
||||
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
|
||||
|
||||
More examples on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/examples>`_.
|
||||
|
||||
@ -46,4 +48,4 @@ More examples on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/exam
|
||||
.. _authorized: Setup.html#user-authorization
|
||||
.. _Telegram Bot API: https://core.telegram.org/bots/api
|
||||
.. _methods: ../pyrogram/Client.html#messages
|
||||
.. _types: ../pyrogram/Types.html
|
||||
.. _types: ../pyrogram/Types.html
|
||||
|
@ -10,13 +10,14 @@ can be freely used as basic building blocks for your own applications without wo
|
||||
|
||||
Example | Description
|
||||
---: | :---
|
||||
[**hello**](hello.py) | Demonstration of basic API usage
|
||||
[**echo**](echo.py) | Reply to every private text message
|
||||
[**hello_world**](hello_world.py) | Demonstration of basic API usage
|
||||
[**echobot**](echobot.py) | Echo every private text message
|
||||
[**welcome**](welcome.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat)
|
||||
[**history**](history.py) | Get the full message history of a chat
|
||||
[**chat_members**](chat_members.py) | Get all the members of a chat
|
||||
[**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
|
||||
[**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)
|
||||
|
@ -5,12 +5,12 @@ It uses the @on_callback_query decorator to register a CallbackQueryHandler.
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
|
||||
|
||||
|
||||
@app.on_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()
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
app = Client("my_count")
|
||||
app = Client("my_account")
|
||||
target = "pyrogramchat" # Target channel/supergroup
|
||||
|
||||
with app:
|
||||
|
54
examples/inline_queries.py
Normal file
54
examples/inline_queries.py
Normal 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()
|
@ -10,7 +10,7 @@ like send_audio(), send_document(), send_location(), etc...
|
||||
from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
|
||||
|
||||
# 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:
|
||||
app.send_message(
|
||||
@ -33,19 +33,17 @@ with app:
|
||||
reply_markup=InlineKeyboardMarkup(
|
||||
[
|
||||
[ # First row
|
||||
|
||||
InlineKeyboardButton( # Generates a callback query when pressed
|
||||
"Button",
|
||||
callback_data=b"data"
|
||||
), # Note how callback_data must be bytes
|
||||
callback_data=b"data" # Note how callback_data must be bytes
|
||||
),
|
||||
InlineKeyboardButton( # Opens a web URL
|
||||
"URL",
|
||||
url="https://docs.pyrogram.ml"
|
||||
),
|
||||
],
|
||||
[ # Second row
|
||||
# Opens the inline interface
|
||||
InlineKeyboardButton(
|
||||
InlineKeyboardButton( # Opens the inline interface
|
||||
"Choose chat",
|
||||
switch_inline_query="pyrogram"
|
||||
),
|
||||
|
@ -24,25 +24,13 @@ if sys.version_info[:3] in [(3, 5, 0), (3, 5, 1), (3, 5, 2)]:
|
||||
# Monkey patch the standard "typing" module because Python versions from 3.5.0 to 3.5.2 have a broken one.
|
||||
sys.modules["typing"] = typing
|
||||
|
||||
__copyright__ = "Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>".replace(
|
||||
"\xe8",
|
||||
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||
)
|
||||
__version__ = "0.12.0"
|
||||
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
||||
__version__ = "0.11.1.develop"
|
||||
__copyright__ = "Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>".replace(
|
||||
"\xe8", "e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||
)
|
||||
|
||||
from .api.errors import Error
|
||||
from .client.types import (
|
||||
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
|
||||
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, User, UserStatus,
|
||||
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove,
|
||||
Poll, PollOption, ChatPreview, StopPropagation, ContinuePropagation, Game, CallbackGame, GameHighScore,
|
||||
GameHighScores
|
||||
)
|
||||
from .client import (
|
||||
Client, ChatAction, ParseMode, Emoji,
|
||||
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
|
||||
RawUpdateHandler, DisconnectHandler, UserStatusHandler, Filters
|
||||
)
|
||||
from .errors import RPCError
|
||||
from .client import *
|
||||
from .client.handlers import *
|
||||
from .client.types import *
|
||||
|
@ -26,6 +26,10 @@ from .primitives import Int, Long
|
||||
class FutureSalt(Object):
|
||||
ID = 0x0949d9dc
|
||||
|
||||
__slots__ = ["valid_since", "valid_until", "salt"]
|
||||
|
||||
QUALNAME = "FutureSalt"
|
||||
|
||||
def __init__(self, valid_since: int or datetime, valid_until: int or datetime, salt: int):
|
||||
self.valid_since = valid_since
|
||||
self.valid_until = valid_until
|
||||
|
@ -27,6 +27,10 @@ from .primitives import Int, Long
|
||||
class FutureSalts(Object):
|
||||
ID = 0xae500895
|
||||
|
||||
__slots__ = ["req_msg_id", "now", "salts"]
|
||||
|
||||
QUALNAME = "FutureSalts"
|
||||
|
||||
def __init__(self, req_msg_id: int, now: int or datetime, salts: list):
|
||||
self.req_msg_id = req_msg_id
|
||||
self.now = now
|
||||
|
@ -26,6 +26,10 @@ from .primitives import Int, Bytes
|
||||
class GzipPacked(Object):
|
||||
ID = 0x3072cfa1
|
||||
|
||||
__slots__ = ["packed_data"]
|
||||
|
||||
QUALNAME = "GzipPacked"
|
||||
|
||||
def __init__(self, packed_data: Object):
|
||||
self.packed_data = packed_data
|
||||
|
||||
|
@ -25,6 +25,10 @@ from .primitives import Int, Long
|
||||
class Message(Object):
|
||||
ID = 0x5bb8e511 # hex(crc32(b"message msg_id:long seqno:int bytes:int body:Object = Message"))
|
||||
|
||||
__slots__ = ["msg_id", "seq_no", "length", "body"]
|
||||
|
||||
QUALNAME = "Message"
|
||||
|
||||
def __init__(self, body: Object, msg_id: int, seq_no: int, length: int):
|
||||
self.msg_id = msg_id
|
||||
self.seq_no = seq_no
|
||||
|
@ -26,6 +26,10 @@ from .primitives import Int
|
||||
class MsgContainer(Object):
|
||||
ID = 0x73f1f8dc
|
||||
|
||||
__slots__ = ["messages"]
|
||||
|
||||
QUALNAME = "MsgContainer"
|
||||
|
||||
def __init__(self, messages: list):
|
||||
self.messages = messages
|
||||
|
||||
|
@ -19,14 +19,16 @@
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from io import BytesIO
|
||||
from json import JSONEncoder, dumps
|
||||
|
||||
from ..all import objects
|
||||
from json import dumps
|
||||
|
||||
|
||||
class Object:
|
||||
all = {}
|
||||
|
||||
__slots__ = []
|
||||
|
||||
QUALNAME = "Base"
|
||||
|
||||
@staticmethod
|
||||
def read(b: BytesIO, *args):
|
||||
return Object.all[int.from_bytes(b.read(4), "little")].read(b, *args)
|
||||
@ -35,20 +37,11 @@ class Object:
|
||||
pass
|
||||
|
||||
def __str__(self) -> str:
|
||||
return dumps(self, cls=Encoder, indent=4)
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return True
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
return self.__dict__ == other.__dict__
|
||||
return dumps(self, indent=4, default=default, ensure_ascii=False)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.write())
|
||||
|
||||
def __call__(self):
|
||||
pass
|
||||
|
||||
def __getitem__(self, item):
|
||||
return getattr(self, item)
|
||||
|
||||
@ -62,29 +55,18 @@ def remove_none(obj):
|
||||
return obj
|
||||
|
||||
|
||||
class Encoder(JSONEncoder):
|
||||
def default(self, o: Object):
|
||||
try:
|
||||
content = o.__dict__
|
||||
except AttributeError:
|
||||
if isinstance(o, datetime):
|
||||
return o.strftime("%d-%b-%Y %H:%M:%S")
|
||||
else:
|
||||
return repr(o)
|
||||
def default(o: "Object"):
|
||||
try:
|
||||
content = {i: getattr(o, i) for i in o.__slots__}
|
||||
|
||||
name = o.__class__.__name__
|
||||
o = objects.get(getattr(o, "ID", None), None)
|
||||
|
||||
if o is not None:
|
||||
if o.startswith("pyrogram.client"):
|
||||
r = remove_none(OrderedDict([("_", "pyrogram:" + name)] + [i for i in content.items()]))
|
||||
r.pop("_client", None)
|
||||
|
||||
return r
|
||||
else:
|
||||
return OrderedDict(
|
||||
[("_", o.replace("pyrogram.api.types.", "telegram:"))]
|
||||
+ [i for i in content.items()]
|
||||
)
|
||||
return remove_none(
|
||||
OrderedDict(
|
||||
[("_", o.QUALNAME)]
|
||||
+ [i for i in content.items()]
|
||||
)
|
||||
)
|
||||
except AttributeError:
|
||||
if isinstance(o, datetime):
|
||||
return o.strftime("%d-%b-%Y %H:%M:%S")
|
||||
else:
|
||||
return None
|
||||
return repr(o)
|
||||
|
@ -19,8 +19,7 @@
|
||||
from .client import Client
|
||||
from .ext import BaseClient, ChatAction, Emoji, ParseMode
|
||||
from .filters import Filters
|
||||
from .handlers import (
|
||||
MessageHandler, DeletedMessagesHandler,
|
||||
CallbackQueryHandler, RawUpdateHandler,
|
||||
DisconnectHandler, UserStatusHandler
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Client", "BaseClient", "ChatAction", "Emoji", "ParseMode", "Filters",
|
||||
]
|
||||
|
@ -39,7 +39,11 @@ from typing import Union, List, Type
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.core import Object
|
||||
from pyrogram.api.errors import (
|
||||
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 (
|
||||
PhoneMigrate, NetworkMigrate, PhoneNumberInvalid,
|
||||
PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty,
|
||||
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
|
||||
@ -47,13 +51,8 @@ from pyrogram.api.errors import (
|
||||
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied,
|
||||
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 .dispatcher import Dispatcher
|
||||
from .ext import utils, Syncer, BaseClient
|
||||
from .ext import utils, Syncer, BaseClient, Dispatcher
|
||||
from .methods import Methods
|
||||
from .session_storage import (
|
||||
SessionDoesNotExist, SessionStorage, MemorySessionStorage, JsonSessionStorage,
|
||||
@ -70,9 +69,10 @@ class Client(Methods, BaseClient):
|
||||
|
||||
Args:
|
||||
session_name (``str``):
|
||||
Name to uniquely identify a session of either a User or a Bot, e.g.: "my_main_account".
|
||||
You still can use bot token here, but it will be deprecated in next release.
|
||||
Note: as long as a valid User session file exists, Pyrogram won't ask you again to input your phone number.
|
||||
Name to uniquely identify a session of either a User or a Bot, e.g.: "my_account". This name will be used
|
||||
to save a file to disk that stores details needed for reconnecting without asking again for credentials.
|
||||
Note for bots: You can pass a bot token here, but this usage will be deprecated in next releases.
|
||||
Use *bot_token* instead.
|
||||
|
||||
api_id (``int``, *optional*):
|
||||
The *api_id* part of your Telegram API Key, as integer. E.g.: 12345
|
||||
@ -182,31 +182,35 @@ class Client(Methods, BaseClient):
|
||||
Defaults to False (normal session).
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
session_name: Union[str, SessionStorage],
|
||||
api_id: Union[int, str] = None,
|
||||
api_hash: str = None,
|
||||
app_version: str = None,
|
||||
device_model: str = None,
|
||||
system_version: str = None,
|
||||
lang_code: str = None,
|
||||
ipv6: bool = False,
|
||||
proxy: dict = None,
|
||||
test_mode: bool = False,
|
||||
phone_number: str = None,
|
||||
phone_code: Union[str, callable] = None,
|
||||
password: str = None,
|
||||
recovery_code: callable = None,
|
||||
force_sms: bool = False,
|
||||
bot_token: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
workers: int = BaseClient.WORKERS,
|
||||
workdir: str = BaseClient.WORKDIR,
|
||||
config_file: str = BaseClient.CONFIG_FILE,
|
||||
plugins: dict = None,
|
||||
no_updates: bool = None,
|
||||
takeout: bool = None):
|
||||
terms_of_service_displayed = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session_name: str,
|
||||
api_id: Union[int, str] = None,
|
||||
api_hash: str = None,
|
||||
app_version: str = None,
|
||||
device_model: str = None,
|
||||
system_version: str = None,
|
||||
lang_code: str = None,
|
||||
ipv6: bool = False,
|
||||
proxy: dict = None,
|
||||
test_mode: bool = False,
|
||||
phone_number: str = None,
|
||||
phone_code: Union[str, callable] = None,
|
||||
password: str = None,
|
||||
recovery_code: callable = None,
|
||||
force_sms: bool = False,
|
||||
bot_token: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
workers: int = BaseClient.WORKERS,
|
||||
workdir: str = BaseClient.WORKDIR,
|
||||
config_file: str = BaseClient.CONFIG_FILE,
|
||||
plugins: dict = None,
|
||||
no_updates: bool = None,
|
||||
takeout: bool = None
|
||||
):
|
||||
|
||||
if isinstance(session_name, str):
|
||||
if session_name == ':memory:':
|
||||
@ -222,6 +226,8 @@ class Client(Methods, BaseClient):
|
||||
|
||||
super().__init__(session_storage)
|
||||
|
||||
super().__init__(session_storage)
|
||||
|
||||
self.session_name = str(session_name) # TODO: build correct session name
|
||||
self.api_id = int(api_id) if api_id else None
|
||||
self.api_hash = api_hash
|
||||
@ -277,7 +283,7 @@ class Client(Methods, BaseClient):
|
||||
Requires no parameters.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ConnectionError`` in case you try to start an already started Client.
|
||||
"""
|
||||
if self.is_started:
|
||||
@ -288,10 +294,10 @@ class Client(Methods, BaseClient):
|
||||
self.session_storage.is_bot = True
|
||||
self.bot_token = self.session_storage._session_name
|
||||
self.session_storage._session_name = self.session_storage._session_name.split(":")[0]
|
||||
warnings.warn('\nYou are using a bot token as session name.\n'
|
||||
'It will be deprecated in next update, please use session file name to load '
|
||||
'existing sessions and bot_token argument to create new sessions.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
warnings.warn('\nWARNING: You are using a bot token as session name!\n'
|
||||
'This usage will be deprecated soon. Please use a session file name to load '
|
||||
'an existing session and the bot_token argument to create new sessions.\n'
|
||||
'More info: https://docs.pyrogram.ml/start/Setup#bot-authorization\n')
|
||||
|
||||
self.load_config()
|
||||
self.load_session()
|
||||
@ -309,6 +315,7 @@ class Client(Methods, BaseClient):
|
||||
try:
|
||||
if self.session_storage.user_id is None:
|
||||
if self.bot_token is None:
|
||||
self.is_bot = False
|
||||
self.authorize_user()
|
||||
else:
|
||||
self.session_storage.is_bot = True
|
||||
@ -446,7 +453,7 @@ class Client(Methods, BaseClient):
|
||||
Requires no parameters.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.start()
|
||||
self.idle()
|
||||
@ -558,9 +565,10 @@ class Client(Methods, BaseClient):
|
||||
try:
|
||||
r = self.send(
|
||||
functions.auth.SendCode(
|
||||
self.phone_number,
|
||||
self.api_id,
|
||||
self.api_hash
|
||||
phone_number=self.phone_number,
|
||||
api_id=self.api_id,
|
||||
api_hash=self.api_hash,
|
||||
settings=types.CodeSettings()
|
||||
)
|
||||
)
|
||||
except (PhoneMigrate, NetworkMigrate) as e:
|
||||
@ -604,8 +612,9 @@ class Client(Methods, BaseClient):
|
||||
phone_code_hash = r.phone_code_hash
|
||||
terms_of_service = r.terms_of_service
|
||||
|
||||
if terms_of_service:
|
||||
if terms_of_service and not Client.terms_of_service_displayed:
|
||||
print("\n" + terms_of_service.text + "\n")
|
||||
Client.terms_of_service_displayed = True
|
||||
|
||||
if self.force_sms:
|
||||
self.send(
|
||||
@ -640,9 +649,9 @@ class Client(Methods, BaseClient):
|
||||
try:
|
||||
r = self.send(
|
||||
functions.auth.SignIn(
|
||||
self.phone_number,
|
||||
phone_code_hash,
|
||||
self.phone_code
|
||||
phone_number=self.phone_number,
|
||||
phone_code_hash=phone_code_hash,
|
||||
phone_code=self.phone_code
|
||||
)
|
||||
)
|
||||
except PhoneNumberUnoccupied:
|
||||
@ -653,11 +662,11 @@ class Client(Methods, BaseClient):
|
||||
try:
|
||||
r = self.send(
|
||||
functions.auth.SignUp(
|
||||
self.phone_number,
|
||||
phone_code_hash,
|
||||
self.phone_code,
|
||||
self.first_name,
|
||||
self.last_name
|
||||
phone_number=self.phone_number,
|
||||
phone_code_hash=phone_code_hash,
|
||||
phone_code=self.phone_code,
|
||||
first_name=self.first_name,
|
||||
last_name=self.last_name
|
||||
)
|
||||
)
|
||||
except PhoneNumberOccupied:
|
||||
@ -751,7 +760,11 @@ class Client(Methods, BaseClient):
|
||||
break
|
||||
|
||||
if terms_of_service:
|
||||
assert self.send(functions.help.AcceptTermsOfService(terms_of_service.id))
|
||||
assert self.send(
|
||||
functions.help.AcceptTermsOfService(
|
||||
id=terms_of_service.id
|
||||
)
|
||||
)
|
||||
|
||||
self.password = None
|
||||
self.session_storage.user_id = r.user.id
|
||||
@ -992,16 +1005,16 @@ class Client(Methods, BaseClient):
|
||||
Timeout in seconds.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
if not self.is_started:
|
||||
raise ConnectionError("Client has not been started")
|
||||
|
||||
if self.no_updates:
|
||||
data = functions.InvokeWithoutUpdates(data)
|
||||
data = functions.InvokeWithoutUpdates(query=data)
|
||||
|
||||
if self.takeout_id:
|
||||
data = functions.InvokeWithTakeout(self.takeout_id, data)
|
||||
data = functions.InvokeWithTakeout(takeout_id=self.takeout_id, query=data)
|
||||
|
||||
r = self.session.send(data, retries, timeout)
|
||||
|
||||
@ -1118,7 +1131,7 @@ class Client(Methods, BaseClient):
|
||||
|
||||
try:
|
||||
module = import_module(module_path)
|
||||
except ModuleNotFoundError:
|
||||
except ImportError:
|
||||
log.warning('[LOAD] Ignoring non-existent module "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
@ -1154,7 +1167,7 @@ class Client(Methods, BaseClient):
|
||||
|
||||
try:
|
||||
module = import_module(module_path)
|
||||
except ModuleNotFoundError:
|
||||
except ImportError:
|
||||
log.warning('[UNLOAD] Ignoring non-existent module "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
@ -1241,7 +1254,7 @@ class Client(Methods, BaseClient):
|
||||
On success, the resolved peer id is returned in form of an InputPeer object.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``KeyError`` in case the peer doesn't exist in the internal database.
|
||||
"""
|
||||
try:
|
||||
@ -1276,7 +1289,7 @@ class Client(Methods, BaseClient):
|
||||
self.fetch_peers(
|
||||
self.send(
|
||||
functions.users.GetUsers(
|
||||
id=[types.InputUser(peer_id, 0)]
|
||||
id=[types.InputUser(user_id=peer_id, access_hash=0)]
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1284,7 +1297,7 @@ class Client(Methods, BaseClient):
|
||||
if str(peer_id).startswith("-100"):
|
||||
self.send(
|
||||
functions.channels.GetChannels(
|
||||
id=[types.InputChannel(int(str(peer_id)[4:]), 0)]
|
||||
id=[types.InputChannel(channel_id=int(str(peer_id)[4:]), access_hash=0)]
|
||||
)
|
||||
)
|
||||
else:
|
||||
@ -1348,7 +1361,7 @@ class Client(Methods, BaseClient):
|
||||
On success, the uploaded file is returned in form of an InputFile object.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
part_size = 512 * 1024
|
||||
file_size = os.path.getsize(path)
|
||||
@ -1591,8 +1604,8 @@ class Client(Methods, BaseClient):
|
||||
|
||||
hashes = session.send(
|
||||
functions.upload.GetCdnFileHashes(
|
||||
r.file_token,
|
||||
offset
|
||||
file_token=r.file_token,
|
||||
offset=offset
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
from .base_client import BaseClient
|
||||
from .chat_action import ChatAction
|
||||
from .dispatcher import Dispatcher
|
||||
from .emoji import Emoji
|
||||
from .parse_mode import ParseMode
|
||||
from .syncer import Syncer
|
||||
|
@ -74,8 +74,8 @@ class BaseClient:
|
||||
self.rnd_id = MsgId
|
||||
self.channels_pts = {}
|
||||
|
||||
self.markdown = Markdown(self.session_storage)
|
||||
self.html = HTML(self.session_storage)
|
||||
self.markdown = Markdown(self.session_storage, self)
|
||||
self.html = HTML(self.session_storage, self)
|
||||
|
||||
self.session = None
|
||||
self.media_sessions = {}
|
||||
@ -122,3 +122,6 @@ class BaseClient:
|
||||
|
||||
def get_chat_members_count(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def answer_inline_query(self, *args, **kwargs):
|
||||
pass
|
||||
|
@ -24,7 +24,10 @@ from threading import Thread
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import types
|
||||
from ..handlers import CallbackQueryHandler, MessageHandler, RawUpdateHandler, UserStatusHandler, DeletedMessagesHandler
|
||||
from ..handlers import (
|
||||
CallbackQueryHandler, MessageHandler, DeletedMessagesHandler,
|
||||
UserStatusHandler, RawUpdateHandler, InlineQueryHandler
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -73,7 +76,10 @@ class Dispatcher:
|
||||
(types.UpdateUserStatus,):
|
||||
lambda upd, usr, cht: (
|
||||
pyrogram.UserStatus._parse(self.client, upd.status, upd.user_id), UserStatusHandler
|
||||
)
|
||||
),
|
||||
|
||||
(types.UpdateBotInlineQuery,):
|
||||
lambda upd, usr, cht: (pyrogram.InlineQuery._parse(self.client, upd, usr), InlineQueryHandler)
|
||||
}
|
||||
|
||||
self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple}
|
@ -67,10 +67,10 @@ def get_peer_id(input_peer) -> int:
|
||||
|
||||
def get_input_peer(peer_id: int, access_hash: int):
|
||||
return (
|
||||
types.InputPeerUser(peer_id, access_hash) if peer_id > 0
|
||||
else types.InputPeerChannel(int(str(peer_id)[4:]), access_hash)
|
||||
types.InputPeerUser(user_id=peer_id, access_hash=access_hash) if peer_id > 0
|
||||
else types.InputPeerChannel(channel_id=int(str(peer_id)[4:]), access_hash=access_hash)
|
||||
if (str(peer_id).startswith("-100") and access_hash)
|
||||
else types.InputPeerChat(-peer_id)
|
||||
else types.InputPeerChat(chat_id=-peer_id)
|
||||
)
|
||||
|
||||
|
||||
|
@ -115,7 +115,7 @@ class Filters:
|
||||
voice = create("Voice", lambda _, m: bool(m.voice))
|
||||
"""Filter messages that contain :obj:`Voice <pyrogram.Voice>` note objects."""
|
||||
|
||||
video_note = create("Voice", lambda _, m: bool(m.video_note))
|
||||
video_note = create("VideoNote", lambda _, m: bool(m.video_note))
|
||||
"""Filter messages that contain :obj:`VideoNote <pyrogram.VideoNote>` objects."""
|
||||
|
||||
contact = create("Contact", lambda _, m: bool(m.contact))
|
||||
@ -222,14 +222,16 @@ class Filters:
|
||||
- poll"""
|
||||
|
||||
@staticmethod
|
||||
def command(command: str or list,
|
||||
prefix: str or list = "/",
|
||||
separator: str = " ",
|
||||
case_sensitive: bool = False):
|
||||
def command(
|
||||
commands: str or list,
|
||||
prefix: str or list = "/",
|
||||
separator: str = " ",
|
||||
case_sensitive: bool = False
|
||||
):
|
||||
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
|
||||
|
||||
Args:
|
||||
command (``str`` | ``list``):
|
||||
commands (``str`` | ``list``):
|
||||
The command or list of commands as string the filter should look for.
|
||||
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*
|
||||
@ -249,31 +251,25 @@ class Filters:
|
||||
Examples: when True, command="Start" would trigger /Start but not /start.
|
||||
"""
|
||||
|
||||
def f(_, m):
|
||||
if m.text:
|
||||
for i in _.p:
|
||||
if m.text.startswith(i):
|
||||
t = m.text.split(_.s)
|
||||
c, a = t[0][len(i):], t[1:]
|
||||
c = c if _.cs else c.lower()
|
||||
m.command = ([c] + a) if c in _.c else None
|
||||
def func(flt, message):
|
||||
text = message.text or message.caption
|
||||
|
||||
if text:
|
||||
for p in flt.p:
|
||||
if text.startswith(p):
|
||||
s = text.split(flt.s)
|
||||
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
|
||||
|
||||
return bool(m.command)
|
||||
return bool(message.command)
|
||||
|
||||
return create(
|
||||
"Command",
|
||||
f,
|
||||
c={command if case_sensitive
|
||||
else command.lower()}
|
||||
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
|
||||
)
|
||||
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("Command", func=func, c=commands, p=prefixes, s=separator, cs=case_sensitive)
|
||||
|
||||
@staticmethod
|
||||
def regex(pattern, flags: int = 0):
|
||||
@ -311,21 +307,20 @@ class Filters:
|
||||
|
||||
def __init__(self, users: int or str or list = None):
|
||||
users = [] if users is None else users if type(users) is list else [users]
|
||||
|
||||
super().__init__(
|
||||
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in users}
|
||||
if type(users) is list else
|
||||
{"me" if users in ["me", "self"] else users.lower().strip("@") if type(users) is str else users}
|
||||
"me" if u in ["me", "self"]
|
||||
else u.lower().strip("@") if type(u) is str
|
||||
else u for u in users
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
return bool(
|
||||
message.from_user
|
||||
and (message.from_user.id in self
|
||||
or (message.from_user.username
|
||||
and message.from_user.username.lower() in self)
|
||||
or ("me" in self
|
||||
and message.from_user.is_self))
|
||||
)
|
||||
return (message.from_user
|
||||
and (message.from_user.id in self
|
||||
or (message.from_user.username
|
||||
and message.from_user.username.lower() in self)
|
||||
or ("me" in self
|
||||
and message.from_user.is_self)))
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class chat(Filter, set):
|
||||
@ -343,21 +338,21 @@ class Filters:
|
||||
|
||||
def __init__(self, chats: int or str or list = None):
|
||||
chats = [] if chats is None else chats if type(chats) is list else [chats]
|
||||
|
||||
super().__init__(
|
||||
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in chats}
|
||||
if type(chats) is list else
|
||||
{"me" if chats in ["me", "self"] else chats.lower().strip("@") if type(chats) is str else chats}
|
||||
"me" if c in ["me", "self"]
|
||||
else c.lower().strip("@") if type(c) is str
|
||||
else c for c in chats
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
return bool(
|
||||
message.chat
|
||||
and (message.chat.id in self
|
||||
or (message.chat.username
|
||||
and message.chat.username.lower() in self)
|
||||
or ("me" in self and message.from_user
|
||||
and message.from_user.is_self
|
||||
and not message.outgoing))
|
||||
)
|
||||
return (message.chat
|
||||
and (message.chat.id in self
|
||||
or (message.chat.username
|
||||
and message.chat.username.lower() in self)
|
||||
or ("me" in self
|
||||
and message.from_user
|
||||
and message.from_user.is_self
|
||||
and not message.outgoing)))
|
||||
|
||||
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))
|
||||
|
@ -19,6 +19,12 @@
|
||||
from .callback_query_handler import CallbackQueryHandler
|
||||
from .deleted_messages_handler import DeletedMessagesHandler
|
||||
from .disconnect_handler import DisconnectHandler
|
||||
from .inline_query_handler import InlineQueryHandler
|
||||
from .message_handler import MessageHandler
|
||||
from .raw_update_handler import RawUpdateHandler
|
||||
from .user_status_handler import UserStatusHandler
|
||||
|
||||
__all__ = [
|
||||
"MessageHandler", "DeletedMessagesHandler", "CallbackQueryHandler", "RawUpdateHandler", "DisconnectHandler",
|
||||
"UserStatusHandler", "InlineQueryHandler"
|
||||
]
|
||||
|
54
pyrogram/client/handlers/inline_query_handler.py
Normal file
54
pyrogram/client/handlers/inline_query_handler.py
Normal file
@ -0,0 +1,54 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .handler import Handler
|
||||
|
||||
|
||||
class InlineQueryHandler(Handler):
|
||||
"""The InlineQuery handler class. Used to handle inline queries.
|
||||
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
|
||||
|
||||
For a nicer way to register this handler, have a look at the
|
||||
:meth:`on_inline_query() <pyrogram.Client.on_inline_query>` decorator.
|
||||
|
||||
Args:
|
||||
callback (``callable``):
|
||||
Pass a function that will be called when a new InlineQuery arrives. It takes *(client, inline_query)*
|
||||
as positional arguments (look at the section below for a detailed description).
|
||||
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
Pass one or more filters to allow only a subset of inline queries to be passed
|
||||
in your callback function.
|
||||
|
||||
Other parameters:
|
||||
client (:obj:`Client <pyrogram.Client>`):
|
||||
The Client itself, useful when you want to call other API methods inside the inline query handler.
|
||||
|
||||
inline_query (:obj:`InlineQuery <pyrogram.InlineQuery>`):
|
||||
The received inline query.
|
||||
"""
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, callback_query):
|
||||
return (
|
||||
self.filters(callback_query)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
@ -17,6 +17,7 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .answer_callback_query import AnswerCallbackQuery
|
||||
from .answer_inline_query import AnswerInlineQuery
|
||||
from .get_game_high_scores import GetGameHighScores
|
||||
from .get_inline_bot_results import GetInlineBotResults
|
||||
from .request_callback_answer import RequestCallbackAnswer
|
||||
@ -27,6 +28,7 @@ from .set_game_score import SetGameScore
|
||||
|
||||
class Bots(
|
||||
AnswerCallbackQuery,
|
||||
AnswerInlineQuery,
|
||||
GetInlineBotResults,
|
||||
RequestCallbackAnswer,
|
||||
SendInlineBotResult,
|
||||
|
@ -21,12 +21,14 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class AnswerCallbackQuery(BaseClient):
|
||||
def answer_callback_query(self,
|
||||
callback_query_id: str,
|
||||
text: str = None,
|
||||
show_alert: bool = None,
|
||||
url: str = None,
|
||||
cache_time: int = 0):
|
||||
def answer_callback_query(
|
||||
self,
|
||||
callback_query_id: str,
|
||||
text: str = None,
|
||||
show_alert: bool = None,
|
||||
url: str = None,
|
||||
cache_time: int = 0
|
||||
):
|
||||
"""Use this method to send answers to callback queries sent from inline keyboards.
|
||||
The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
|
||||
|
||||
@ -55,7 +57,7 @@ class AnswerCallbackQuery(BaseClient):
|
||||
True, on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.SetBotCallbackAnswer(
|
||||
|
91
pyrogram/client/methods/bots/answer_inline_query.py
Normal file
91
pyrogram/client/methods/bots/answer_inline_query.py
Normal file
@ -0,0 +1,91 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import List
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.client.ext import BaseClient
|
||||
from ...types.inline_mode import InlineQueryResult
|
||||
|
||||
|
||||
class AnswerInlineQuery(BaseClient):
|
||||
def answer_inline_query(
|
||||
self,
|
||||
inline_query_id: str,
|
||||
results: List[InlineQueryResult],
|
||||
cache_time: int = 300,
|
||||
is_personal: bool = None,
|
||||
next_offset: str = "",
|
||||
switch_pm_text: str = "",
|
||||
switch_pm_parameter: str = ""
|
||||
):
|
||||
"""Use this method to send answers to an inline query.
|
||||
No more than 50 results per query are allowed.
|
||||
|
||||
Args:
|
||||
inline_query_id (``str``):
|
||||
Unique identifier for the answered query.
|
||||
|
||||
results (List of :obj:`InlineQueryResult <pyrogram.InlineQueryResult>`):
|
||||
A list of results for the inline query.
|
||||
|
||||
cache_time (``int``, *optional*):
|
||||
The maximum amount of time in seconds that the result of the inline query may be cached on the server.
|
||||
Defaults to 300.
|
||||
|
||||
is_personal (``bool``, *optional*):
|
||||
Pass True, if results may be cached on the server side only for the user that sent the query.
|
||||
By default, results may be returned to any user who sends the same query.
|
||||
|
||||
next_offset (``str``, *optional*):
|
||||
Pass the offset that a client should send in the next query with the same text to receive more results.
|
||||
Pass an empty string if there are no more results or if you don‘t support pagination.
|
||||
Offset length can’t exceed 64 bytes.
|
||||
|
||||
switch_pm_text (``str``, *optional*):
|
||||
If passed, clients will display a button with specified text that switches the user to a private chat
|
||||
with the bot and sends the bot a start message with the parameter switch_pm_parameter
|
||||
|
||||
switch_pm_parameter (``str``, *optional*):
|
||||
`Deep-linking <https://core.telegram.org/bots#deep-linking>`_ parameter for the /start message sent to
|
||||
the bot when user presses the switch button. 1-64 characters, only A-Z, a-z, 0-9, _ and - are allowed.
|
||||
|
||||
Example: An inline bot that sends YouTube videos can ask the user to connect the bot to their YouTube
|
||||
account to adapt search results accordingly. To do this, it displays a "Connect your YouTube account"
|
||||
button above the results, or even before showing any. The user presses the button, switches to a private
|
||||
chat with the bot and, in doing so, passes a start parameter that instructs the bot to return an oauth
|
||||
link. Once done, the bot can offer a switch_inline button so that the user can easily return to the chat
|
||||
where they wanted to use the bot's inline capabilities.
|
||||
|
||||
Returns:
|
||||
On success, True is returned.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.SetInlineBotResults(
|
||||
query_id=int(inline_query_id),
|
||||
results=[r.write() for r in results],
|
||||
cache_time=cache_time,
|
||||
gallery=None,
|
||||
private=is_personal or None,
|
||||
next_offset=next_offset or None,
|
||||
switch_pm=types.InlineBotSwitchPM(
|
||||
text=switch_pm_text,
|
||||
start_param=switch_pm_parameter
|
||||
) if switch_pm_text else None
|
||||
)
|
||||
)
|
@ -24,10 +24,12 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class GetGameHighScores(BaseClient):
|
||||
def get_game_high_scores(self,
|
||||
user_id: Union[int, str],
|
||||
chat_id: Union[int, str],
|
||||
message_id: int = None):
|
||||
def get_game_high_scores(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
chat_id: Union[int, str],
|
||||
message_id: int = None
|
||||
):
|
||||
"""Use this method to get data for high score tables.
|
||||
|
||||
Args:
|
||||
@ -50,7 +52,7 @@ class GetGameHighScores(BaseClient):
|
||||
On success, a :obj:`GameHighScores <pyrogram.GameHighScores>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
# TODO: inline_message_id
|
||||
|
||||
|
@ -19,17 +19,19 @@
|
||||
from typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.errors import UnknownError
|
||||
from pyrogram.errors import UnknownError
|
||||
from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class GetInlineBotResults(BaseClient):
|
||||
def get_inline_bot_results(self,
|
||||
bot: Union[int, str],
|
||||
query: str,
|
||||
offset: str = "",
|
||||
latitude: float = None,
|
||||
longitude: float = None):
|
||||
def get_inline_bot_results(
|
||||
self,
|
||||
bot: Union[int, str],
|
||||
query: str,
|
||||
offset: str = "",
|
||||
latitude: float = None,
|
||||
longitude: float = None
|
||||
):
|
||||
"""Use this method to get bot results via inline queries.
|
||||
You can then send a result using :obj:`send_inline_bot_result <pyrogram.Client.send_inline_bot_result>`
|
||||
|
||||
@ -56,7 +58,7 @@ class GetInlineBotResults(BaseClient):
|
||||
On Success, :obj:`BotResults <pyrogram.api.types.messages.BotResults>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``TimeoutError`` if the bot fails to answer within 10 seconds
|
||||
"""
|
||||
# TODO: Don't return the raw type
|
||||
|
@ -23,12 +23,14 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class RequestCallbackAnswer(BaseClient):
|
||||
def request_callback_answer(self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
callback_data: bytes):
|
||||
"""Use this method to request a callback answer from bots. This is the equivalent of clicking an
|
||||
inline button containing callback data.
|
||||
def request_callback_answer(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
callback_data: bytes
|
||||
):
|
||||
"""Use this method to request a callback answer from bots.
|
||||
This is the equivalent of clicking an inline button containing callback data.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
@ -47,7 +49,7 @@ class RequestCallbackAnswer(BaseClient):
|
||||
or as an alert.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``TimeoutError`` if the bot fails to answer within 10 seconds.
|
||||
"""
|
||||
return self.send(
|
||||
|
@ -24,15 +24,19 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class SendGame(BaseClient):
|
||||
def send_game(self,
|
||||
chat_id: Union[int, str],
|
||||
game_short_name: str,
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None,
|
||||
reply_markup: Union["pyrogram.InlineKeyboardMarkup",
|
||||
"pyrogram.ReplyKeyboardMarkup",
|
||||
"pyrogram.ReplyKeyboardRemove",
|
||||
"pyrogram.ForceReply"] = None) -> "pyrogram.Message":
|
||||
def send_game(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
game_short_name: str,
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None,
|
||||
reply_markup: Union[
|
||||
"pyrogram.InlineKeyboardMarkup",
|
||||
"pyrogram.ReplyKeyboardMarkup",
|
||||
"pyrogram.ReplyKeyboardRemove",
|
||||
"pyrogram.ForceReply"
|
||||
] = None
|
||||
) -> "pyrogram.Message":
|
||||
"""Use this method to send a game.
|
||||
|
||||
Args:
|
||||
@ -59,7 +63,7 @@ class SendGame(BaseClient):
|
||||
On success, the sent :obj:`Message` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(
|
||||
functions.messages.SendMedia(
|
||||
|
@ -23,13 +23,15 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class SendInlineBotResult(BaseClient):
|
||||
def send_inline_bot_result(self,
|
||||
chat_id: Union[int, str],
|
||||
query_id: int,
|
||||
result_id: str,
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None,
|
||||
hide_via: bool = None):
|
||||
def send_inline_bot_result(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
query_id: int,
|
||||
result_id: str,
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None,
|
||||
hide_via: bool = None
|
||||
):
|
||||
"""Use this method to send an inline bot result.
|
||||
Bot results can be retrieved using :obj:`get_inline_bot_results <pyrogram.Client.get_inline_bot_results>`
|
||||
|
||||
@ -59,7 +61,7 @@ class SendInlineBotResult(BaseClient):
|
||||
On success, the sent Message is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.SendInlineBotResult(
|
||||
|
@ -24,13 +24,15 @@ from pyrogram.client.ext import BaseClient
|
||||
|
||||
|
||||
class SetGameScore(BaseClient):
|
||||
def set_game_score(self,
|
||||
user_id: Union[int, str],
|
||||
score: int,
|
||||
force: bool = None,
|
||||
disable_edit_message: bool = None,
|
||||
chat_id: Union[int, str] = None,
|
||||
message_id: int = None):
|
||||
def set_game_score(
|
||||
self,
|
||||
user_id: Union[int, str],
|
||||
score: int,
|
||||
force: bool = None,
|
||||
disable_edit_message: bool = None,
|
||||
chat_id: Union[int, str] = None,
|
||||
message_id: int = None
|
||||
):
|
||||
# inline_message_id: str = None): TODO Add inline_message_id
|
||||
"""Use this method to set the score of the specified user in a game.
|
||||
|
||||
@ -65,7 +67,7 @@ class SetGameScore(BaseClient):
|
||||
otherwise returns True.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
:class:`BotScoreNotModified` if the new score is not greater than the user's current score in the chat and force is False.
|
||||
"""
|
||||
r = self.send(
|
||||
|
@ -31,12 +31,14 @@ from .kick_chat_member import KickChatMember
|
||||
from .leave_chat import LeaveChat
|
||||
from .pin_chat_message import PinChatMessage
|
||||
from .promote_chat_member import PromoteChatMember
|
||||
from .restrict_chat import RestrictChat
|
||||
from .restrict_chat_member import RestrictChatMember
|
||||
from .set_chat_description import SetChatDescription
|
||||
from .set_chat_photo import SetChatPhoto
|
||||
from .set_chat_title import SetChatTitle
|
||||
from .unban_chat_member import UnbanChatMember
|
||||
from .unpin_chat_message import UnpinChatMessage
|
||||
from .update_chat_username import UpdateChatUsername
|
||||
|
||||
|
||||
class Chats(
|
||||
@ -60,6 +62,8 @@ class Chats(
|
||||
GetChatMembersCount,
|
||||
GetChatPreview,
|
||||
IterDialogs,
|
||||
IterChatMembers
|
||||
IterChatMembers,
|
||||
UpdateChatUsername,
|
||||
RestrictChat
|
||||
):
|
||||
pass
|
||||
|
@ -23,8 +23,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class DeleteChatPhoto(BaseClient):
|
||||
def delete_chat_photo(self,
|
||||
chat_id: Union[int, str]) -> bool:
|
||||
def delete_chat_photo(
|
||||
self,
|
||||
chat_id: Union[int, str]
|
||||
) -> bool:
|
||||
"""Use this method to delete a chat photo.
|
||||
Photos can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
@ -41,7 +43,7 @@ class DeleteChatPhoto(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
@ -23,8 +23,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class ExportChatInviteLink(BaseClient):
|
||||
def export_chat_invite_link(self,
|
||||
chat_id: Union[int, str]) -> str:
|
||||
def export_chat_invite_link(
|
||||
self,
|
||||
chat_id: Union[int, str]
|
||||
) -> str:
|
||||
"""Use this method to generate a new invite link for a chat; any previously generated link is revoked.
|
||||
|
||||
You must be an administrator in the chat for this to work and have the appropriate admin rights.
|
||||
@ -38,14 +40,14 @@ class ExportChatInviteLink(BaseClient):
|
||||
On success, the exported invite link as string is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChat):
|
||||
return self.send(
|
||||
functions.messages.ExportChatInvite(
|
||||
chat_id=peer.chat_id
|
||||
peer=peer.chat_id
|
||||
)
|
||||
).link
|
||||
elif isinstance(peer, types.InputPeerChannel):
|
||||
|
@ -24,10 +24,13 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class GetChat(BaseClient):
|
||||
def get_chat(self,
|
||||
chat_id: Union[int, str]) -> "pyrogram.Chat":
|
||||
"""Use this method to get up to date information about the chat (current name of the user for
|
||||
one-on-one conversations, current username of a user, group or channel, etc.)
|
||||
def get_chat(
|
||||
self,
|
||||
chat_id: Union[int, str]
|
||||
) -> "pyrogram.Chat":
|
||||
"""Use this method to get up to date information about the chat.
|
||||
Information include current name of the user for one-on-one conversations, current username of a user, group or
|
||||
channel, etc.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
@ -39,7 +42,7 @@ class GetChat(BaseClient):
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` in case the chat invite link refers to a chat you haven't joined yet.
|
||||
"""
|
||||
match = self.INVITE_LINK_RE.match(str(chat_id))
|
||||
@ -67,10 +70,10 @@ class GetChat(BaseClient):
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
r = self.send(functions.channels.GetFullChannel(peer))
|
||||
r = self.send(functions.channels.GetFullChannel(channel=peer))
|
||||
elif isinstance(peer, (types.InputPeerUser, types.InputPeerSelf)):
|
||||
r = self.send(functions.users.GetFullUser(peer))
|
||||
r = self.send(functions.users.GetFullUser(id=peer))
|
||||
else:
|
||||
r = self.send(functions.messages.GetFullChat(peer.chat_id))
|
||||
r = self.send(functions.messages.GetFullChat(chat_id=peer.chat_id))
|
||||
|
||||
return pyrogram.Chat._parse_full(self, r)
|
||||
|
@ -19,14 +19,17 @@
|
||||
from typing import Union
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types, errors
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.errors import UserNotParticipant
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class GetChatMember(BaseClient):
|
||||
def get_chat_member(self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str]) -> "pyrogram.ChatMember":
|
||||
def get_chat_member(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str]
|
||||
) -> "pyrogram.ChatMember":
|
||||
"""Use this method to get information about one member of a chat.
|
||||
|
||||
Args:
|
||||
@ -42,7 +45,7 @@ class GetChatMember(BaseClient):
|
||||
On success, a :obj:`ChatMember <pyrogram.ChatMember>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
chat_id = self.resolve_peer(chat_id)
|
||||
user_id = self.resolve_peer(user_id)
|
||||
@ -55,10 +58,10 @@ class GetChatMember(BaseClient):
|
||||
)
|
||||
|
||||
for member in pyrogram.ChatMembers._parse(self, full_chat).chat_members:
|
||||
if member.user.id == user_id.user_id:
|
||||
if member.user.is_self:
|
||||
return member
|
||||
else:
|
||||
raise errors.UserNotParticipant
|
||||
raise UserNotParticipant
|
||||
elif isinstance(chat_id, types.InputPeerChannel):
|
||||
r = self.send(
|
||||
functions.channels.GetParticipant(
|
||||
|
@ -16,12 +16,17 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Filters:
|
||||
ALL = "all"
|
||||
@ -33,12 +38,14 @@ class Filters:
|
||||
|
||||
|
||||
class GetChatMembers(BaseClient):
|
||||
def get_chat_members(self,
|
||||
chat_id: Union[int, str],
|
||||
offset: int = 0,
|
||||
limit: int = 200,
|
||||
query: str = "",
|
||||
filter: str = Filters.ALL) -> "pyrogram.ChatMembers":
|
||||
def get_chat_members(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
offset: int = 0,
|
||||
limit: int = 200,
|
||||
query: str = "",
|
||||
filter: str = Filters.ALL
|
||||
) -> "pyrogram.ChatMembers":
|
||||
"""Use this method to get a chunk of the members list of a chat.
|
||||
|
||||
You can get up to 200 chat members at once.
|
||||
@ -82,7 +89,7 @@ class GetChatMembers(BaseClient):
|
||||
On success, a :obj:`ChatMembers` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if you used an invalid filter or a chat_id that belongs to a user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
@ -92,7 +99,7 @@ class GetChatMembers(BaseClient):
|
||||
self,
|
||||
self.send(
|
||||
functions.messages.GetFullChat(
|
||||
peer.chat_id
|
||||
chat_id=peer.chat_id
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -114,17 +121,22 @@ class GetChatMembers(BaseClient):
|
||||
else:
|
||||
raise ValueError("Invalid filter \"{}\"".format(filter))
|
||||
|
||||
return pyrogram.ChatMembers._parse(
|
||||
self,
|
||||
self.send(
|
||||
functions.channels.GetParticipants(
|
||||
channel=peer,
|
||||
filter=filter,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
hash=0
|
||||
while True:
|
||||
try:
|
||||
return pyrogram.ChatMembers._parse(
|
||||
self,
|
||||
self.send(
|
||||
functions.channels.GetParticipants(
|
||||
channel=peer,
|
||||
filter=filter,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
hash=0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
time.sleep(e.x)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
@ -23,8 +23,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class GetChatMembersCount(BaseClient):
|
||||
def get_chat_members_count(self,
|
||||
chat_id: Union[int, str]) -> int:
|
||||
def get_chat_members_count(
|
||||
self,
|
||||
chat_id: Union[int, str]
|
||||
) -> int:
|
||||
"""Use this method to get the number of members in a chat.
|
||||
|
||||
Args:
|
||||
@ -35,7 +37,7 @@ class GetChatMembersCount(BaseClient):
|
||||
On success, an integer is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
@ -22,8 +22,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class GetChatPreview(BaseClient):
|
||||
def get_chat_preview(self,
|
||||
invite_link: str):
|
||||
def get_chat_preview(
|
||||
self,
|
||||
invite_link: str
|
||||
):
|
||||
"""Use this method to get the preview of a chat using the invite link.
|
||||
|
||||
This method only returns a chat preview, if you want to join a chat use :meth:`join_chat`
|
||||
@ -36,7 +38,7 @@ class GetChatPreview(BaseClient):
|
||||
Either :obj:`Chat` or :obj:`ChatPreview`, depending on whether you already joined the chat or not.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` in case of an invalid invite_link.
|
||||
"""
|
||||
match = self.INVITE_LINK_RE.match(invite_link)
|
||||
|
@ -21,18 +21,20 @@ import time
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from pyrogram.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GetDialogs(BaseClient):
|
||||
def get_dialogs(self,
|
||||
offset_date: int = 0,
|
||||
limit: int = 100,
|
||||
pinned_only: bool = False) -> "pyrogram.Dialogs":
|
||||
"""Use this method to get a chunk of the user's dialogs
|
||||
def get_dialogs(
|
||||
self,
|
||||
offset_date: int = 0,
|
||||
limit: int = 100,
|
||||
pinned_only: bool = False
|
||||
) -> "pyrogram.Dialogs":
|
||||
"""Use this method to get a chunk of the user's dialogs.
|
||||
|
||||
You can get up to 100 dialogs at once.
|
||||
For a more convenient way of getting a user's dialogs see :meth:`iter_dialogs`.
|
||||
@ -54,7 +56,7 @@ class GetDialogs(BaseClient):
|
||||
On success, a :obj:`Dialogs` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
while True:
|
||||
|
@ -20,6 +20,7 @@ from string import ascii_lowercase
|
||||
from typing import Union, Generator
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
@ -37,11 +38,13 @@ QUERYABLE_FILTERS = (Filters.ALL, Filters.KICKED, Filters.RESTRICTED)
|
||||
|
||||
|
||||
class IterChatMembers(BaseClient):
|
||||
def iter_chat_members(self,
|
||||
chat_id: Union[int, str],
|
||||
limit: int = 0,
|
||||
query: str = "",
|
||||
filter: str = Filters.ALL) -> Generator["pyrogram.ChatMember", None, None]:
|
||||
def iter_chat_members(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
limit: int = 0,
|
||||
query: str = "",
|
||||
filter: str = Filters.ALL
|
||||
) -> Generator["pyrogram.ChatMember", None, None]:
|
||||
"""Use this method to iterate through the members of a chat sequentially.
|
||||
|
||||
This convenience method does the same as repeatedly calling :meth:`get_chat_members` in a loop, thus saving you
|
||||
@ -75,13 +78,14 @@ class IterChatMembers(BaseClient):
|
||||
A generator yielding :obj:`ChatMember <pyrogram.ChatMember>` objects.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
current = 0
|
||||
yielded = set()
|
||||
queries = [query] if query else QUERIES
|
||||
total = limit or (1 << 31) - 1
|
||||
limit = min(200, total)
|
||||
resolved_chat_id = self.resolve_peer(chat_id)
|
||||
|
||||
filter = (
|
||||
Filters.RECENT
|
||||
@ -107,6 +111,9 @@ class IterChatMembers(BaseClient):
|
||||
if not chat_members:
|
||||
break
|
||||
|
||||
if isinstance(resolved_chat_id, types.InputPeerChat):
|
||||
total = len(chat_members)
|
||||
|
||||
offset += len(chat_members)
|
||||
|
||||
for chat_member in chat_members:
|
||||
|
@ -23,9 +23,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class IterDialogs(BaseClient):
|
||||
def iter_dialogs(self,
|
||||
offset_date: int = 0,
|
||||
limit: int = 0) -> Generator["pyrogram.Dialog", None, None]:
|
||||
def iter_dialogs(
|
||||
self,
|
||||
offset_date: int = 0,
|
||||
limit: int = 0
|
||||
) -> Generator["pyrogram.Dialog", None, None]:
|
||||
"""Use this method to iterate through a user's dialogs sequentially.
|
||||
|
||||
This convenience method does the same as repeatedly calling :meth:`get_dialogs` in a loop, thus saving you from
|
||||
@ -44,7 +46,7 @@ class IterDialogs(BaseClient):
|
||||
A generator yielding :obj:`Dialog <pyrogram.Dialog>` objects.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
current = 0
|
||||
total = limit or (1 << 31) - 1
|
||||
|
@ -16,13 +16,16 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class JoinChat(BaseClient):
|
||||
def join_chat(self,
|
||||
chat_id: str):
|
||||
def join_chat(
|
||||
self,
|
||||
chat_id: str
|
||||
):
|
||||
"""Use this method to join a group chat or channel.
|
||||
|
||||
Args:
|
||||
@ -30,17 +33,24 @@ class JoinChat(BaseClient):
|
||||
Unique identifier for the target chat in form of a *t.me/joinchat/* link or username of the target
|
||||
channel/supergroup (in the format @username).
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
match = self.INVITE_LINK_RE.match(chat_id)
|
||||
|
||||
if match:
|
||||
return self.send(
|
||||
chat = self.send(
|
||||
functions.messages.ImportChatInvite(
|
||||
hash=match.group(1)
|
||||
)
|
||||
)
|
||||
if isinstance(chat.chats[0], types.Chat):
|
||||
return pyrogram.Chat._parse_chat_chat(self, chat.chats[0])
|
||||
elif isinstance(chat.chats[0], types.Channel):
|
||||
return pyrogram.Chat._parse_channel_chat(self, chat.chats[0])
|
||||
else:
|
||||
resolved_peer = self.send(
|
||||
functions.contacts.ResolveUsername(
|
||||
@ -53,8 +63,10 @@ class JoinChat(BaseClient):
|
||||
access_hash=resolved_peer.chats[0].access_hash
|
||||
)
|
||||
|
||||
return self.send(
|
||||
chat = self.send(
|
||||
functions.channels.JoinChannel(
|
||||
channel=channel
|
||||
)
|
||||
)
|
||||
|
||||
return pyrogram.Chat._parse_channel_chat(self, chat.chats[0])
|
||||
|
@ -24,10 +24,12 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class KickChatMember(BaseClient):
|
||||
def kick_chat_member(self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
until_date: int = 0) -> Union["pyrogram.Message", bool]:
|
||||
def kick_chat_member(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
until_date: int = 0
|
||||
) -> Union["pyrogram.Message", bool]:
|
||||
"""Use this method to kick a user from a group, a supergroup or a channel.
|
||||
In the case of supergroups and channels, the user will not be able to return to the group on their own using
|
||||
invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must
|
||||
@ -55,7 +57,7 @@ class KickChatMember(BaseClient):
|
||||
On success, either True or a service :obj:`Message <pyrogram.Message>` will be returned (when applicable).
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
chat_peer = self.resolve_peer(chat_id)
|
||||
user_peer = self.resolve_peer(user_id)
|
||||
@ -65,7 +67,7 @@ class KickChatMember(BaseClient):
|
||||
functions.channels.EditBanned(
|
||||
channel=chat_peer,
|
||||
user_id=user_peer,
|
||||
banned_rights=types.ChannelBannedRights(
|
||||
banned_rights=types.ChatBannedRights(
|
||||
until_date=until_date,
|
||||
view_messages=True,
|
||||
send_messages=True,
|
||||
|
@ -23,9 +23,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class LeaveChat(BaseClient):
|
||||
def leave_chat(self,
|
||||
chat_id: Union[int, str],
|
||||
delete: bool = False):
|
||||
def leave_chat(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
delete: bool = False
|
||||
):
|
||||
"""Use this method to leave a group chat or channel.
|
||||
|
||||
Args:
|
||||
@ -37,7 +39,7 @@ class LeaveChat(BaseClient):
|
||||
Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -23,10 +23,12 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class PinChatMessage(BaseClient):
|
||||
def pin_chat_message(self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
disable_notification: bool = None) -> bool:
|
||||
def pin_chat_message(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
disable_notification: bool = None
|
||||
) -> bool:
|
||||
"""Use this method to pin a message in a group, channel or your own chat.
|
||||
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in
|
||||
the supergroup or "can_edit_messages" admin right in the channel.
|
||||
@ -46,7 +48,7 @@ class PinChatMessage(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.messages.UpdatePinnedMessage(
|
||||
@ -55,3 +57,5 @@ class PinChatMessage(BaseClient):
|
||||
silent=disable_notification or None
|
||||
)
|
||||
)
|
||||
|
||||
return True
|
||||
|
@ -23,18 +23,21 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class PromoteChatMember(BaseClient):
|
||||
def promote_chat_member(self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
can_change_info: bool = True,
|
||||
can_post_messages: bool = False,
|
||||
can_edit_messages: bool = False,
|
||||
can_delete_messages: bool = True,
|
||||
can_invite_users: bool = True,
|
||||
can_restrict_members: bool = True,
|
||||
can_pin_messages: bool = False,
|
||||
can_promote_members: bool = False) -> bool:
|
||||
def promote_chat_member(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
can_change_info: bool = True,
|
||||
can_post_messages: bool = False,
|
||||
can_edit_messages: bool = False,
|
||||
can_delete_messages: bool = True,
|
||||
can_restrict_members: bool = True,
|
||||
can_invite_users: bool = True,
|
||||
can_pin_messages: bool = False,
|
||||
can_promote_members: bool = False
|
||||
) -> bool:
|
||||
"""Use this method to promote or demote a user in a supergroup or a channel.
|
||||
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
Pass False for all boolean parameters to demote a user.
|
||||
|
||||
@ -58,12 +61,12 @@ class PromoteChatMember(BaseClient):
|
||||
can_delete_messages (``bool``, *optional*):
|
||||
Pass True, if the administrator can delete messages of other users.
|
||||
|
||||
can_invite_users (``bool``, *optional*):
|
||||
Pass True, if the administrator can invite new users to the chat.
|
||||
|
||||
can_restrict_members (``bool``, *optional*):
|
||||
Pass True, if the administrator can restrict, ban or unban chat members.
|
||||
|
||||
can_invite_users (``bool``, *optional*):
|
||||
Pass True, if the administrator can invite new users to the chat.
|
||||
|
||||
can_pin_messages (``bool``, *optional*):
|
||||
Pass True, if the administrator can pin messages, supergroups only.
|
||||
|
||||
@ -76,23 +79,21 @@ class PromoteChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.channels.EditAdmin(
|
||||
channel=self.resolve_peer(chat_id),
|
||||
user_id=self.resolve_peer(user_id),
|
||||
admin_rights=types.ChannelAdminRights(
|
||||
admin_rights=types.ChatAdminRights(
|
||||
change_info=can_change_info or None,
|
||||
post_messages=can_post_messages or None,
|
||||
edit_messages=can_edit_messages or None,
|
||||
delete_messages=can_delete_messages or None,
|
||||
ban_users=can_restrict_members or None,
|
||||
invite_users=can_invite_users or None,
|
||||
invite_link=can_invite_users or None,
|
||||
pin_messages=can_pin_messages or None,
|
||||
add_admins=can_promote_members or None,
|
||||
manage_call=None
|
||||
)
|
||||
)
|
||||
)
|
||||
|
143
pyrogram/client/methods/chats/restrict_chat.py
Normal file
143
pyrogram/client/methods/chats/restrict_chat.py
Normal file
@ -0,0 +1,143 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
from ...types.user_and_chats import Chat
|
||||
|
||||
|
||||
class RestrictChat(BaseClient):
|
||||
def restrict_chat(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
can_send_messages: bool = False,
|
||||
can_send_media_messages: bool = False,
|
||||
can_send_other_messages: bool = False,
|
||||
can_add_web_page_previews: bool = False,
|
||||
can_send_polls: bool = False,
|
||||
can_change_info: bool = False,
|
||||
can_invite_users: bool = False,
|
||||
can_pin_messages: bool = False
|
||||
) -> Chat:
|
||||
"""Use this method to restrict a chat.
|
||||
Pass True for all boolean parameters to lift restrictions from a chat.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
|
||||
can_send_messages (``bool``, *optional*):
|
||||
Pass True, if the user can send text messages, contacts, locations and venues.
|
||||
|
||||
can_send_media_messages (``bool``, *optional*):
|
||||
Pass True, if the user can send audios, documents, photos, videos, video notes and voice notes,
|
||||
implies can_send_messages.
|
||||
|
||||
can_send_other_messages (``bool``, *optional*):
|
||||
Pass True, if the user can send animations, games, stickers and use inline bots,
|
||||
implies can_send_media_messages.
|
||||
|
||||
can_add_web_page_previews (``bool``, *optional*):
|
||||
Pass True, if the user may add web page previews to their messages, implies can_send_media_messages.
|
||||
|
||||
can_send_polls (``bool``, *optional*):
|
||||
Pass True, if the user can send polls, implies can_send_media_messages.
|
||||
|
||||
can_change_info (``bool``, *optional*):
|
||||
Pass True, if the user can change the chat title, photo and other settings.
|
||||
|
||||
can_invite_users (``bool``, *optional*):
|
||||
Pass True, if the user can invite new users to the chat.
|
||||
|
||||
can_pin_messages (``bool``, *optional*):
|
||||
Pass True, if the user can pin messages.
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
send_messages = True
|
||||
send_media = True
|
||||
send_stickers = True
|
||||
send_gifs = True
|
||||
send_games = True
|
||||
send_inline = True
|
||||
embed_links = True
|
||||
send_polls = True
|
||||
change_info = True
|
||||
invite_users = True
|
||||
pin_messages = True
|
||||
|
||||
if can_send_messages:
|
||||
send_messages = None
|
||||
|
||||
if can_send_media_messages:
|
||||
send_messages = None
|
||||
send_media = None
|
||||
|
||||
if can_send_other_messages:
|
||||
send_messages = None
|
||||
send_media = None
|
||||
send_stickers = None
|
||||
send_gifs = None
|
||||
send_games = None
|
||||
send_inline = None
|
||||
|
||||
if can_add_web_page_previews:
|
||||
send_messages = None
|
||||
send_media = None
|
||||
embed_links = None
|
||||
|
||||
if can_send_polls:
|
||||
send_messages = None
|
||||
send_polls = None
|
||||
|
||||
if can_change_info:
|
||||
change_info = None
|
||||
|
||||
if can_invite_users:
|
||||
invite_users = None
|
||||
|
||||
if can_pin_messages:
|
||||
pin_messages = None
|
||||
|
||||
r = self.send(
|
||||
functions.messages.EditChatDefaultBannedRights(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
banned_rights=types.ChatBannedRights(
|
||||
until_date=0,
|
||||
send_messages=send_messages,
|
||||
send_media=send_media,
|
||||
send_stickers=send_stickers,
|
||||
send_gifs=send_gifs,
|
||||
send_games=send_games,
|
||||
send_inline=send_inline,
|
||||
embed_links=embed_links,
|
||||
send_polls=send_polls,
|
||||
change_info=change_info,
|
||||
invite_users=invite_users,
|
||||
pin_messages=pin_messages
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return Chat._parse_chat(self, r.chats[0])
|
@ -20,20 +20,28 @@ from typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
from ...types.user_and_chats import Chat
|
||||
|
||||
|
||||
class RestrictChatMember(BaseClient):
|
||||
def restrict_chat_member(self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
until_date: int = 0,
|
||||
can_send_messages: bool = False,
|
||||
can_send_media_messages: bool = False,
|
||||
can_send_other_messages: bool = False,
|
||||
can_add_web_page_previews: bool = False) -> bool:
|
||||
"""Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for
|
||||
this to work and must have the appropriate admin rights. Pass True for all boolean parameters to lift
|
||||
restrictions from a user.
|
||||
def restrict_chat_member(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str],
|
||||
until_date: int = 0,
|
||||
can_send_messages: bool = False,
|
||||
can_send_media_messages: bool = False,
|
||||
can_send_other_messages: bool = False,
|
||||
can_add_web_page_previews: bool = False,
|
||||
can_send_polls: bool = False,
|
||||
can_change_info: bool = False,
|
||||
can_invite_users: bool = False,
|
||||
can_pin_messages: bool = False
|
||||
) -> Chat:
|
||||
"""Use this method to restrict a user in a supergroup.
|
||||
|
||||
The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights.
|
||||
Pass True for all boolean parameters to lift restrictions from a user.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
@ -60,13 +68,25 @@ class RestrictChatMember(BaseClient):
|
||||
implies can_send_media_messages.
|
||||
|
||||
can_add_web_page_previews (``bool``, *optional*):
|
||||
Pass True, if the user may add web page previews to their messages, implies can_send_media_messages
|
||||
Pass True, if the user may add web page previews to their messages, implies can_send_media_messages.
|
||||
|
||||
can_send_polls (``bool``, *optional*):
|
||||
Pass True, if the user can send polls, implies can_send_media_messages.
|
||||
|
||||
can_change_info (``bool``, *optional*):
|
||||
Pass True, if the user can change the chat title, photo and other settings.
|
||||
|
||||
can_invite_users (``bool``, *optional*):
|
||||
Pass True, if the user can invite new users to the chat.
|
||||
|
||||
can_pin_messages (``bool``, *optional*):
|
||||
Pass True, if the user can pin messages.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
send_messages = True
|
||||
send_media = True
|
||||
@ -75,6 +95,10 @@ class RestrictChatMember(BaseClient):
|
||||
send_games = True
|
||||
send_inline = True
|
||||
embed_links = True
|
||||
send_polls = True
|
||||
change_info = True
|
||||
invite_users = True
|
||||
pin_messages = True
|
||||
|
||||
if can_send_messages:
|
||||
send_messages = None
|
||||
@ -84,6 +108,7 @@ class RestrictChatMember(BaseClient):
|
||||
send_media = None
|
||||
|
||||
if can_send_other_messages:
|
||||
send_messages = None
|
||||
send_media = None
|
||||
send_stickers = None
|
||||
send_gifs = None
|
||||
@ -91,14 +116,28 @@ class RestrictChatMember(BaseClient):
|
||||
send_inline = None
|
||||
|
||||
if can_add_web_page_previews:
|
||||
send_messages = None
|
||||
send_media = None
|
||||
embed_links = None
|
||||
|
||||
self.send(
|
||||
if can_send_polls:
|
||||
send_messages = None
|
||||
send_polls = None
|
||||
|
||||
if can_change_info:
|
||||
change_info = None
|
||||
|
||||
if can_invite_users:
|
||||
invite_users = None
|
||||
|
||||
if can_pin_messages:
|
||||
pin_messages = None
|
||||
|
||||
r = self.send(
|
||||
functions.channels.EditBanned(
|
||||
channel=self.resolve_peer(chat_id),
|
||||
user_id=self.resolve_peer(user_id),
|
||||
banned_rights=types.ChannelBannedRights(
|
||||
banned_rights=types.ChatBannedRights(
|
||||
until_date=until_date,
|
||||
send_messages=send_messages,
|
||||
send_media=send_media,
|
||||
@ -106,9 +145,13 @@ class RestrictChatMember(BaseClient):
|
||||
send_gifs=send_gifs,
|
||||
send_games=send_games,
|
||||
send_inline=send_inline,
|
||||
embed_links=embed_links
|
||||
embed_links=embed_links,
|
||||
send_polls=send_polls,
|
||||
change_info=change_info,
|
||||
invite_users=invite_users,
|
||||
pin_messages=pin_messages
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return True
|
||||
return Chat._parse_chat(self, r.chats[0])
|
||||
|
@ -23,9 +23,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatDescription(BaseClient):
|
||||
def set_chat_description(self,
|
||||
chat_id: Union[int, str],
|
||||
description: str) -> bool:
|
||||
def set_chat_description(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
description: str
|
||||
) -> bool:
|
||||
"""Use this method to change the description of a supergroup or a channel.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
@ -40,20 +42,18 @@ class SetChatDescription(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
if isinstance(peer, (types.InputPeerChannel, types.InputPeerChat)):
|
||||
self.send(
|
||||
functions.channels.EditAbout(
|
||||
channel=peer,
|
||||
functions.messages.EditChatAbout(
|
||||
peer=peer,
|
||||
about=description
|
||||
)
|
||||
)
|
||||
elif isinstance(peer, types.InputPeerChat):
|
||||
raise ValueError("The chat_id \"{}\" belongs to a basic group".format(chat_id))
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))
|
||||
|
||||
|
@ -26,9 +26,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatPhoto(BaseClient):
|
||||
def set_chat_photo(self,
|
||||
chat_id: Union[int, str],
|
||||
photo: str) -> bool:
|
||||
def set_chat_photo(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
photo: str
|
||||
) -> bool:
|
||||
"""Use this method to set a new profile photo for the chat.
|
||||
Photos can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
@ -48,7 +50,7 @@ class SetChatPhoto(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
@ -23,9 +23,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetChatTitle(BaseClient):
|
||||
def set_chat_title(self,
|
||||
chat_id: Union[int, str],
|
||||
title: str) -> bool:
|
||||
def set_chat_title(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
title: str
|
||||
) -> bool:
|
||||
"""Use this method to change the title of a chat.
|
||||
Titles can't be changed for private chats.
|
||||
You must be an administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
@ -45,7 +47,7 @@ class SetChatTitle(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
@ -23,9 +23,11 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class UnbanChatMember(BaseClient):
|
||||
def unban_chat_member(self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str]) -> bool:
|
||||
def unban_chat_member(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
user_id: Union[int, str]
|
||||
) -> bool:
|
||||
"""Use this method to unban a previously kicked user in a supergroup or channel.
|
||||
The user will **not** return to the group or channel automatically, but will be able to join via link, etc.
|
||||
You must be an administrator for this to work.
|
||||
@ -42,13 +44,13 @@ class UnbanChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.channels.EditBanned(
|
||||
channel=self.resolve_peer(chat_id),
|
||||
user_id=self.resolve_peer(user_id),
|
||||
banned_rights=types.ChannelBannedRights(
|
||||
banned_rights=types.ChatBannedRights(
|
||||
until_date=0
|
||||
)
|
||||
)
|
||||
|
@ -23,8 +23,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class UnpinChatMessage(BaseClient):
|
||||
def unpin_chat_message(self,
|
||||
chat_id: Union[int, str]) -> bool:
|
||||
def unpin_chat_message(
|
||||
self,
|
||||
chat_id: Union[int, str]
|
||||
) -> bool:
|
||||
"""Use this method to unpin a message in a group, channel or your own chat.
|
||||
You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin
|
||||
right in the supergroup or "can_edit_messages" admin right in the channel.
|
||||
@ -37,7 +39,7 @@ class UnpinChatMessage(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.messages.UpdatePinnedMessage(
|
||||
|
61
pyrogram/client/methods/chats/update_chat_username.py
Normal file
61
pyrogram/client/methods/chats/update_chat_username.py
Normal file
@ -0,0 +1,61 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class UpdateChatUsername(BaseClient):
|
||||
def update_chat_username(
|
||||
self,
|
||||
chat_id: Union[int, str],
|
||||
username: Union[str, None]
|
||||
) -> bool:
|
||||
"""Use this method to update a channel or a supergroup username.
|
||||
|
||||
To update your own username (for users only, not bots) you can use :meth:`update_username`.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``)
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
username (``str`` | ``None``):
|
||||
Username to set. Pass "" (empty string) or None to remove the username.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to a user or chat.
|
||||
"""
|
||||
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
return bool(
|
||||
self.send(
|
||||
functions.channels.UpdateUsername(
|
||||
channel=peer,
|
||||
username=username or ""
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user or chat".format(chat_id))
|
@ -24,8 +24,10 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class AddContacts(BaseClient):
|
||||
def add_contacts(self,
|
||||
contacts: List["pyrogram.InputPhoneContact"]):
|
||||
def add_contacts(
|
||||
self,
|
||||
contacts: List["pyrogram.InputPhoneContact"]
|
||||
):
|
||||
"""Use this method to add contacts to your Telegram address book.
|
||||
|
||||
Args:
|
||||
@ -36,7 +38,7 @@ class AddContacts(BaseClient):
|
||||
On success, the added contacts are returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
imported_contacts = self.send(
|
||||
functions.contacts.ImportContacts(
|
||||
|
@ -19,14 +19,16 @@
|
||||
from typing import List
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.errors import PeerIdInvalid
|
||||
from pyrogram.errors import PeerIdInvalid
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class DeleteContacts(BaseClient):
|
||||
def delete_contacts(self,
|
||||
ids: List[int]):
|
||||
"""Use this method to delete contacts from your Telegram address book
|
||||
def delete_contacts(
|
||||
self,
|
||||
ids: List[int]
|
||||
):
|
||||
"""Use this method to delete contacts from your Telegram address book.
|
||||
|
||||
Args:
|
||||
ids (List of ``int``):
|
||||
@ -37,7 +39,7 @@ class DeleteContacts(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
contacts = []
|
||||
|
||||
|
@ -21,7 +21,7 @@ import time
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from pyrogram.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -35,11 +35,11 @@ class GetContacts(BaseClient):
|
||||
On success, a list of :obj:`User` objects is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
:class:`RPCError <pyrogram.RPCError>` in case of a Telegram RPC error.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
contacts = self.send(functions.contacts.GetContacts(0))
|
||||
contacts = self.send(functions.contacts.GetContacts(hash=0))
|
||||
except FloodWait as e:
|
||||
log.warning("get_contacts flood: waiting {} seconds".format(e.x))
|
||||
time.sleep(e.x)
|
||||
|
@ -19,6 +19,7 @@
|
||||
from .on_callback_query import OnCallbackQuery
|
||||
from .on_deleted_messages import OnDeletedMessages
|
||||
from .on_disconnect import OnDisconnect
|
||||
from .on_inline_query import OnInlineQuery
|
||||
from .on_message import OnMessage
|
||||
from .on_raw_update import OnRawUpdate
|
||||
from .on_user_status import OnUserStatus
|
||||
@ -30,6 +31,7 @@ class Decorators(
|
||||
OnCallbackQuery,
|
||||
OnRawUpdate,
|
||||
OnDisconnect,
|
||||
OnUserStatus
|
||||
OnUserStatus,
|
||||
OnInlineQuery
|
||||
):
|
||||
pass
|
||||
|
@ -25,19 +25,13 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnCallbackQuery(BaseClient):
|
||||
def on_callback_query(self=None,
|
||||
filters=None,
|
||||
group: int = 0) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
callback queries. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`CallbackQueryHandler`.
|
||||
|
||||
.. note::
|
||||
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
|
||||
|
||||
To reference your own function after it has been decorated, you need to access
|
||||
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
|
||||
first element in the tuple.
|
||||
def on_callback_query(
|
||||
self=None,
|
||||
filters=None,
|
||||
group: int = 0
|
||||
) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling callback queries.
|
||||
This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`.
|
||||
|
||||
Args:
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
|
@ -25,19 +25,13 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnDeletedMessages(BaseClient):
|
||||
def on_deleted_messages(self=None,
|
||||
filters=None,
|
||||
group: int = 0) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
deleted messages. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`DeletedMessagesHandler`.
|
||||
|
||||
.. note::
|
||||
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
|
||||
|
||||
To reference your own function after it has been decorated, you need to access
|
||||
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
|
||||
first element in the tuple.
|
||||
def on_deleted_messages(
|
||||
self=None,
|
||||
filters=None,
|
||||
group: int = 0
|
||||
) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling deleted messages.
|
||||
This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`.
|
||||
|
||||
Args:
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
|
@ -23,9 +23,8 @@ from ...ext import BaseClient
|
||||
|
||||
class OnDisconnect(BaseClient):
|
||||
def on_disconnect(self=None) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
disconnections. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`DisconnectHandler`.
|
||||
"""Use this decorator to automatically register a function for handling disconnections.
|
||||
This does the same thing as :meth:`add_handler` using the :class:`DisconnectHandler`.
|
||||
"""
|
||||
|
||||
def decorator(func: callable) -> Handler:
|
||||
|
59
pyrogram/client/methods/decorators/on_inline_query.py
Normal file
59
pyrogram/client/methods/decorators/on_inline_query.py
Normal file
@ -0,0 +1,59 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.client.filters.filter import Filter
|
||||
from pyrogram.client.handlers.handler import Handler
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnInlineQuery(BaseClient):
|
||||
def on_inline_query(
|
||||
self=None,
|
||||
filters=None,
|
||||
group: int = 0
|
||||
) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling inline queries.
|
||||
This does the same thing as :meth:`add_handler` using the :class:`InlineQueryHandler`.
|
||||
|
||||
Args:
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
Pass one or more filters to allow only a subset of inline queries to be passed
|
||||
in your function.
|
||||
|
||||
group (``int``, *optional*):
|
||||
The group identifier, defaults to 0.
|
||||
"""
|
||||
|
||||
def decorator(func: callable) -> Tuple[Handler, int]:
|
||||
if isinstance(func, tuple):
|
||||
func = func[0].callback
|
||||
|
||||
handler = pyrogram.InlineQueryHandler(func, filters)
|
||||
|
||||
if isinstance(self, Filter):
|
||||
return pyrogram.InlineQueryHandler(func, self), group if filters is None else filters
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
@ -25,19 +25,13 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnMessage(BaseClient):
|
||||
def on_message(self=None,
|
||||
filters=None,
|
||||
group: int = 0) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
messages. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`MessageHandler`.
|
||||
|
||||
.. note::
|
||||
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
|
||||
|
||||
To reference your own function after it has been decorated, you need to access
|
||||
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
|
||||
first element in the tuple.
|
||||
def on_message(
|
||||
self=None,
|
||||
filters=None,
|
||||
group: int = 0
|
||||
) -> callable:
|
||||
"""Use this decorator to automatically register a function for handling messages.
|
||||
This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`.
|
||||
|
||||
Args:
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user