Merge develop -> asyncio

This commit is contained in:
Dan 2019-06-02 19:13:17 +02:00
commit d4dbff3226
131 changed files with 1813 additions and 1535 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: delivrance
custom: https://docs.pyrogram.org/support-pyrogram

View File

@ -333,6 +333,7 @@ def start():
docstring_args = "No parameters required."
docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args
docstring_args = "Attributes:\n LAYER: ``{}``\n\n ".format(layer) + docstring_args
if c.section == "functions":
docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type)

View File

@ -22,10 +22,13 @@ inputPeerSelf#7da07ec9 = InputPeer;
inputPeerChat#179be863 chat_id:int = InputPeer;
inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;
inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer;
inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer;
inputUserEmpty#b98886cf = InputUser;
inputUserSelf#f7c1b13f = InputUser;
inputUser#d8292816 user_id:int access_hash:long = InputUser;
inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser;
inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
@ -60,9 +63,12 @@ inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;
inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#196683d9 id:long access_hash:long file_reference:bytes = InputFileLocation;
inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation;
inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;
peerUser#9db1bc6d user_id:int = Peer;
peerChat#bad0e5bb chat_id:int = Peer;
@ -79,14 +85,11 @@ storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;
fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileLocation;
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 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;
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 scam:flags.24?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;
userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
@ -98,11 +101,11 @@ userStatusLastMonth#77ebc742 = UserStatus;
chatEmpty#9ba2d800 id:int = 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#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;
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 scam:flags.19?true has_link:flags.20?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#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;
chatFull#1b7c9db3 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 folder_id:flags.11?int = ChatFull;
channelFull#9882e516 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 folder_id:flags.11?int linked_chat_id:flags.13?int pts:int = ChatFull;
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
chatParticipantCreator#da13538a user_id:int = ChatParticipant;
@ -112,11 +115,11 @@ chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?
chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
messageEmpty#83e5de54 id:int = Message;
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
@ -147,7 +150,7 @@ messageActionHistoryClear#9fbab604 = MessageAction;
messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction;
messageActionPaymentSent#40699cd0 currency:string total_amount:long = MessageAction;
messageActionPhoneCall#80e11a7f flags:# call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#abe9affe domain:string = MessageAction;
@ -155,10 +158,11 @@ messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
messageActionContactSignUp#f3f25f76 = MessageAction;
dialog#e4def5db flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
photoEmpty#2331b22d id:long = Photo;
photo#9c477dd8 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> = Photo;
photo#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo;
photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
@ -196,7 +200,7 @@ inputReportReasonChildAbuse#adf44ee3 = ReportReason;
inputReportReasonOther#e1746d0a text:string = ReportReason;
inputReportReasonCopyright#9b89f93a = ReportReason;
userFull#8ea4a881 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int = UserFull;
userFull#745559cc flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true user:User about:flags.1?string link:contacts.Link profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
contact#f911c994 user_id:int mutual:Bool = Contact;
@ -221,7 +225,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#a6c47aaa flags:# inexact:flags.1?true count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#c8edce1e flags:# inexact:flags.1?true count:int next_rate:flags.0?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;
@ -271,14 +275,14 @@ updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings
updateServiceNotification#ebe46819 flags:# popup:flags.0?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
updateUserPhone#12b9417b user_id:int phone:string = Update;
updateReadHistoryInbox#9961fd5c peer:Peer max_id:int pts:int pts_count:int = Update;
updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer max_id:int still_unread_count:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update;
updateChannel#b6d45656 channel_id:int = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
updateReadChannelInbox#4214f37f channel_id:int max_id:int = Update;
updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts: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;
updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
@ -300,8 +304,8 @@ updateRecentStickers#9a422c20 = Update;
updateConfig#a229dd06 = Update;
updatePtsChanged#3354678f = Update;
updateChannelWebPage#40771900 channel_id:int webpage:WebPage pts:int pts_count:int = Update;
updateDialogPinned#19d27f3c flags:# pinned:flags.0?true peer:DialogPeer = Update;
updatePinnedDialogs#ea4cb65b flags:# order:flags.0?Vector<DialogPeer> = Update;
updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update;
updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector<DialogPeer> = Update;
updateBotWebhookJSON#8317c0c3 data:DataJSON = Update;
updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update;
updateBotShippingQuery#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update;
@ -318,6 +322,7 @@ updateUserPinnedMessage#4c43da18 user_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;
updateFolderPeers#19360dc0 folder_peers:Vector<FolderPeer> pts:int pts_count:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -344,7 +349,7 @@ upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
config#e6ca25f6 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int = Config;
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
@ -413,6 +418,7 @@ inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey;
privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
privacyKeyChatInvite#500e6dfa = PrivacyKey;
@ -420,6 +426,7 @@ privacyKeyPhoneCall#3d662b7b = PrivacyKey;
privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
privacyKeyForwards#69ec56a3 = PrivacyKey;
privacyKeyProfilePhoto#96151fed = PrivacyKey;
privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
@ -427,6 +434,8 @@ inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueAllowChatParticipants#4c81c1ba chats:Vector<int> = InputPrivacyRule;
inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector<int> = InputPrivacyRule;
privacyValueAllowContacts#fffe1bac = PrivacyRule;
privacyValueAllowAll#65427b82 = PrivacyRule;
@ -434,8 +443,10 @@ privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
privacyValueDisallowAll#8b73e763 = PrivacyRule;
privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
privacyValueAllowChatParticipants#18be796b chats:Vector<int> = PrivacyRule;
privacyValueDisallowChatParticipants#acae0690 chats:Vector<int> = PrivacyRule;
account.privacyRules#554abb6f rules:Vector<PrivacyRule> users:Vector<User> = account.PrivacyRules;
account.privacyRules#50a04e45 rules:Vector<PrivacyRule> chats:Vector<Chat> users:Vector<User> = account.PrivacyRules;
accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;
@ -459,7 +470,6 @@ messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMess
contactLinkUnknown#5f4f9247 = ContactLink;
contactLinkNone#feedd3ad = ContactLink;
contactLinkHasPhone#268f3f59 = ContactLink;
contactLinkContact#d502c2d0 = ContactLink;
webPageEmpty#eb1477e8 id:long = WebPage;
@ -485,13 +495,13 @@ chatInviteEmpty#69df3769 = ExportedChatInvite;
chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#db74f558 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:ChatPhoto participants_count:int participants:flags.4?Vector<User> = ChatInvite;
chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
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;
stickerSet#eeb46f27 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 thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
@ -507,6 +517,8 @@ keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
keyboardButtonGame#50f41ccf text:string = KeyboardButton;
keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
@ -533,13 +545,14 @@ messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
inputChannelEmpty#ee8c1e86 = InputChannel;
inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = InputChannel;
contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;
messageRange#ae30253 min_id:int max_id:int = MessageRange;
updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference;
updates.channelDifferenceTooLong#6a9d7b35 flags:# final:flags.0?true pts:int timeout:flags.1?int top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
@ -628,6 +641,8 @@ topPeerCategoryCorrespondents#637b7ed = TopPeerCategory;
topPeerCategoryGroups#bd17a14a = TopPeerCategory;
topPeerCategoryChannels#161d9628 = TopPeerCategory;
topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory;
topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory;
topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory;
topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers;
@ -767,11 +782,11 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co
inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
phoneCallEmpty#5366c915 id:long = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#83761ce4 id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#6d003d3f id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#e6f9ddf3 flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connection:PhoneConnection alternative_connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
@ -797,7 +812,7 @@ langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:fl
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;
channelAdminLogEventActionChangePhoto#b82f55c3 prev_photo:ChatPhoto new_photo:ChatPhoto = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction;
@ -812,6 +827,7 @@ channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputSticker
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeLinkedChat#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int action:ChannelAdminLogEventAction = ChannelAdminLogEvent;
@ -843,8 +859,10 @@ inputMessageReplyTo#bad88395 id:int = InputMessage;
inputMessagePinned#86872538 = InputMessage;
inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer;
inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer;
dialogPeer#e56dbf05 peer:Peer = DialogPeer;
dialogPeerFolder#514519e2 folder_id:int = DialogPeer;
messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets;
messages.foundStickerSets#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets;
@ -1000,6 +1018,22 @@ emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int k
emojiURL#a575739d url:string = EmojiURL;
emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage;
fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation;
folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder;
inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer;
folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer;
messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter;
urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult;
urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult;
urlAuthResultDefault#a9d6db1f = UrlAuthResult;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1098,14 +1132,14 @@ contacts.unblock#e54100bd id:InputUser = Bool;
contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
contacts.search#11f812d8 q:string limit:int = contacts.Found;
contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
contacts.getTopPeers#d4982db5 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true offset:int limit:int hash:int = contacts.TopPeers;
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
contacts.resetSaved#879537f1 = Bool;
contacts.getSaved#82f1e39f = Vector<SavedContact>;
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#b098aee6 flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
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;
@ -1152,7 +1186,7 @@ messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_par
messages.getMessagesViews#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
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;
messages.searchGlobal#f79c611 q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
@ -1185,8 +1219,8 @@ messages.getCommonChats#d0a48c4 user_id:InputUser max_id:int limit:int = message
messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats;
messages.getWebPage#32ca8f91 url:string hash:int = WebPage;
messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
messages.reorderPinnedDialogs#5b51d63f flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool;
messages.getPinnedDialogs#e254d64e = messages.PeerDialogs;
messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector<InputDialogPeer> = Bool;
messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs;
messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool;
messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool;
messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia;
@ -1212,7 +1246,11 @@ 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.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
messages.getSearchCounters#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@ -1281,6 +1319,9 @@ channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool
channels.deleteHistory#af369d42 channel:InputChannel max_id:int = Bool;
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
channels.getBroadcastsForDiscussion#1a87f304 = messages.Chats;
channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
@ -1298,11 +1339,11 @@ stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = mes
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
phone.getCallConfig#55451fa9 = DataJSON;
phone.requestCall#5b95b3d4 user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
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.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = 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;
@ -1312,7 +1353,7 @@ langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:i
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;
// LAYER 97
folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;
folders.deleteFolder#1c295881 folder_id:int = Updates;
// Ports
channels.exportInvite#c7560885 channel:InputChannel = ExportedChatInvite;
// LAYER 100

View File

@ -18,6 +18,7 @@
import ast
import os
import re
import shutil
HOME = "compiler/docs"
@ -29,8 +30,10 @@ TYPES_PATH = "pyrogram/api/types"
FUNCTIONS_BASE = "functions"
TYPES_BASE = "types"
shutil.rmtree(TYPES_BASE, ignore_errors=True)
shutil.rmtree(FUNCTIONS_BASE, ignore_errors=True)
def snek(s: str):
s = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", s)
return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s).lower()
def generate(source_path, base):
@ -50,9 +53,11 @@ def generate(source_path, base):
for node in ast.walk(p):
if isinstance(node, ast.ClassDef):
name = node.name
break
else:
continue
# name = "".join([str(j.title()) for j in os.path.splitext(i)[0].split("_")])
full_path = os.path.basename(path) + "/" + name + ".rst"
full_path = os.path.basename(path) + "/" + snek(name).replace("_", "-") + ".rst"
if level:
full_path = base + "/" + full_path
@ -65,7 +70,7 @@ def generate(source_path, base):
title=name,
title_markup="=" * len(name),
full_class_path="pyrogram.api.{}".format(
os.path.splitext(full_path)[0].replace("/", ".")
".".join(full_path.split("/")[:-1]) + "." + name
)
)
)
@ -82,7 +87,7 @@ def generate(source_path, base):
entities = []
for i in v:
entities.append(i)
entities.append(snek(i).replace("_", "-"))
if k != base:
inner_path = base + "/" + k + "/index" + ".rst"
@ -98,6 +103,7 @@ def generate(source_path, base):
with open(DESTINATION + "/" + inner_path, "w", encoding="utf-8") as f:
if k == base:
f.write(":tocdepth: 1\n\n")
k = "Raw " + k
f.write(
toctree.format(
@ -115,6 +121,8 @@ def start():
global page_template
global toctree
shutil.rmtree(DESTINATION, ignore_errors=True)
with open(HOME + "/template/page.txt", encoding="utf-8") as f:
page_template = f.read()

View File

@ -99,3 +99,4 @@ RESULT_ID_DUPLICATE The result contains items with duplicated identifiers
ACCESS_TOKEN_INVALID The bot access token is invalid
INVITE_HASH_EXPIRED The chat invite link is no longer valid
USER_BANNED_IN_CHANNEL You are limited, check @SpamBot for details
MESSAGE_EDIT_TIME_EXPIRED You can no longer edit this message
1 id message
99 ACCESS_TOKEN_INVALID The bot access token is invalid
100 INVITE_HASH_EXPIRED The chat invite link is no longer valid
101 USER_BANNED_IN_CHANNEL You are limited, check @SpamBot for details
102 MESSAGE_EDIT_TIME_EXPIRED You can no longer edit this message

View File

@ -2,6 +2,7 @@ id message
AUTH_KEY_UNREGISTERED The key is not registered in the system
AUTH_KEY_INVALID The key is invalid
USER_DEACTIVATED The user has been deleted/deactivated
USER_DEACTIVATED_BAN The user has been deleted/deactivated
SESSION_REVOKED The authorization has been invalidated, because of the user terminating all sessions
SESSION_EXPIRED The authorization has expired
ACTIVE_USER_REQUIRED The method is only available to already activated users

1 id message
2 AUTH_KEY_UNREGISTERED The key is not registered in the system
3 AUTH_KEY_INVALID The key is invalid
4 USER_DEACTIVATED The user has been deleted/deactivated
5 USER_DEACTIVATED_BAN The user has been deleted/deactivated
6 SESSION_REVOKED The authorization has been invalidated, because of the user terminating all sessions
7 SESSION_EXPIRED The authorization has expired
8 ACTIVE_USER_REQUIRED The method is only available to already activated users

View File

@ -23,11 +23,11 @@ canonical = "https://docs.pyrogram.org/"
dirs = {
".": ("weekly", 1.0),
"intro": ("weekly", 0.8),
"start": ("weekly", 0.8),
"api": ("weekly", 0.6),
"topics": ("weekly", 0.6),
"telegram": ("weekly", 0.4)
"intro": ("weekly", 0.9),
"start": ("weekly", 0.9),
"api": ("weekly", 0.8),
"topics": ("weekly", 0.8),
"telegram": ("weekly", 0.6)
}

View File

@ -22,43 +22,65 @@ some of the required arguments.
.. currentmodule:: pyrogram
- Message_
- CallbackQuery_
- InlineQuery_
.. _Message:
Index
-----
Message
^^^^^^^
.. hlist::
:columns: 3
- :meth:`~Message.click`
- :meth:`~Message.delete`
- :meth:`~Message.download`
- :meth:`~Message.edit`
- :meth:`~Message.edit_caption`
- :meth:`~Message.edit_media`
- :meth:`~Message.edit_reply_markup`
- :meth:`~Message.forward`
- :meth:`~Message.pin`
- :meth:`~Message.reply`
- :meth:`~Message.reply_animation`
- :meth:`~Message.reply_audio`
- :meth:`~Message.reply_cached_media`
- :meth:`~Message.reply_chat_action`
- :meth:`~Message.reply_contact`
- :meth:`~Message.reply_document`
- :meth:`~Message.reply_game`
- :meth:`~Message.reply_inline_bot_result`
- :meth:`~Message.reply_location`
- :meth:`~Message.reply_media_group`
- :meth:`~Message.reply_photo`
- :meth:`~Message.reply_poll`
- :meth:`~Message.reply_sticker`
- :meth:`~Message.reply_venue`
- :meth:`~Message.reply_video`
- :meth:`~Message.reply_video_note`
- :meth:`~Message.reply_voice`
CallbackQuery
^^^^^^^^^^^^^
.. hlist::
:columns: 2
- :meth:`~CallbackQuery.answer`
InlineQuery
^^^^^^^^^^^
.. hlist::
:columns: 2
- :meth:`~InlineQuery.answer`
-----
Details
-------
- :meth:`Message.click()`
- :meth:`Message.delete()`
- :meth:`Message.download()`
- :meth:`Message.edit()`
- :meth:`Message.edit_caption()`
- :meth:`Message.edit_media()`
- :meth:`Message.edit_reply_markup()`
- :meth:`Message.forward()`
- :meth:`Message.pin()`
- :meth:`Message.reply()`
- :meth:`Message.reply_animation()`
- :meth:`Message.reply_audio()`
- :meth:`Message.reply_cached_media()`
- :meth:`Message.reply_chat_action()`
- :meth:`Message.reply_contact()`
- :meth:`Message.reply_document()`
- :meth:`Message.reply_game()`
- :meth:`Message.reply_inline_bot_result()`
- :meth:`Message.reply_location()`
- :meth:`Message.reply_media_group()`
- :meth:`Message.reply_photo()`
- :meth:`Message.reply_poll()`
- :meth:`Message.reply_sticker()`
- :meth:`Message.reply_venue()`
- :meth:`Message.reply_video()`
- :meth:`Message.reply_video_note()`
- :meth:`Message.reply_voice()`
.. Message
.. automethod:: Message.click()
.. automethod:: Message.delete()
.. automethod:: Message.download()
@ -87,16 +109,8 @@ Message
.. automethod:: Message.reply_video_note()
.. automethod:: Message.reply_voice()
.. _CallbackQuery:
CallbackQuery
-------------
.. CallbackQuery
.. automethod:: CallbackQuery.answer()
.. _InlineQuery:
InlineQuery
-----------
.. InlineQuery
.. automethod:: InlineQuery.answer()

View File

@ -1,13 +1,13 @@
Decorators
==========
While still being methods bound to the :obj:`Client <pyrogram.Client>` class, decorators are of a special kind and thus deserve a
dedicated page.
While still being methods bound to the :class:`~pyrogram.Client` class, decorators are of a special kind and thus
deserve a dedicated page.
Decorators are able to register callback functions for handling updates in a much easier and cleaner way compared to
`Handlers <Handlers.html>`_; they do so by instantiating the correct handler and calling
:meth:`add_handler() <pyrogram.Client.add_handler>`, automatically. All you need to do is adding the decorators on top
of your functions.
:doc:`Handlers <handlers>`; they do so by instantiating the correct handler and calling
:meth:`~pyrogram.Client.add_handler`, automatically. All you need to do is adding the decorators on top of your
functions.
.. code-block:: python
:emphasize-lines: 6
@ -24,25 +24,34 @@ of your functions.
app.run()
.. currentmodule:: pyrogram.Client
.. currentmodule:: pyrogram
.. autosummary::
:nosignatures:
Index
-----
on_message
on_callback_query
on_inline_query
on_deleted_messages
on_user_status
on_poll
on_disconnect
on_raw_update
.. hlist::
:columns: 3
.. automethod:: pyrogram.Client.on_message()
.. automethod:: pyrogram.Client.on_callback_query()
.. automethod:: pyrogram.Client.on_inline_query()
.. automethod:: pyrogram.Client.on_deleted_messages()
.. automethod:: pyrogram.Client.on_user_status()
.. automethod:: pyrogram.Client.on_poll()
.. automethod:: pyrogram.Client.on_disconnect()
.. automethod:: pyrogram.Client.on_raw_update()
- :meth:`~Client.on_message`
- :meth:`~Client.on_callback_query`
- :meth:`~Client.on_inline_query`
- :meth:`~Client.on_deleted_messages`
- :meth:`~Client.on_user_status`
- :meth:`~Client.on_poll`
- :meth:`~Client.on_disconnect`
- :meth:`~Client.on_raw_update`
-----
Details
-------
.. Decorators
.. autodecorator:: pyrogram.Client.on_message()
.. autodecorator:: pyrogram.Client.on_callback_query()
.. autodecorator:: pyrogram.Client.on_inline_query()
.. autodecorator:: pyrogram.Client.on_deleted_messages()
.. autodecorator:: pyrogram.Client.on_user_status()
.. autodecorator:: pyrogram.Client.on_poll()
.. autodecorator:: pyrogram.Client.on_disconnect()
.. autodecorator:: pyrogram.Client.on_raw_update()

View File

@ -3,8 +3,8 @@ Update Handlers
Handlers are used to instruct Pyrogram about which kind of updates you'd like to handle with your callback functions.
For a much more convenient way of registering callback functions have a look at `Decorators <Decorators.html>`_ instead.
In case you decided to manually create a handler, use :meth:`add_handler() <pyrogram.Client.add_handler>` to register
For a much more convenient way of registering callback functions have a look at :doc:`Decorators <decorators>` instead.
In case you decided to manually create a handler, use :class:`~pyrogram.Client.add_handler` to register
it.
.. code-block:: python
@ -25,18 +25,27 @@ it.
.. currentmodule:: pyrogram
.. autosummary::
:nosignatures:
Index
-----
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
InlineQueryHandler
UserStatusHandler
PollHandler
DisconnectHandler
RawUpdateHandler
.. hlist::
:columns: 3
- :class:`MessageHandler`
- :class:`DeletedMessagesHandler`
- :class:`CallbackQueryHandler`
- :class:`InlineQueryHandler`
- :class:`UserStatusHandler`
- :class:`PollHandler`
- :class:`DisconnectHandler`
- :class:`RawUpdateHandler`
-----
Details
-------
.. Handlers
.. autoclass:: MessageHandler()
.. autoclass:: DeletedMessagesHandler()
.. autoclass:: CallbackQueryHandler()

View File

@ -1,7 +1,7 @@
Available Methods
=================
All Pyrogram methods listed here are bound to a :obj:`Client <pyrogram.Client>` instance.
All Pyrogram methods listed here are bound to a :class:`~pyrogram.Client` instance.
.. code-block:: python
:emphasize-lines: 6
@ -13,253 +13,253 @@ All Pyrogram methods listed here are bound to a :obj:`Client <pyrogram.Client>`
with app:
app.send_message("haskell", "hi")
.. currentmodule:: pyrogram.Client
.. currentmodule:: pyrogram
Index
-----
Utilities
---------
^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 4
start
stop
restart
idle
run
add_handler
remove_handler
send
resolve_peer
save_file
stop_transmission
- :meth:`~Client.start`
- :meth:`~Client.stop`
- :meth:`~Client.restart`
- :meth:`~Client.idle`
- :meth:`~Client.run`
- :meth:`~Client.add_handler`
- :meth:`~Client.remove_handler`
- :meth:`~Client.send`
- :meth:`~Client.resolve_peer`
- :meth:`~Client.save_file`
- :meth:`~Client.stop_transmission`
Messages
--------
^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
send_message
forward_messages
send_photo
send_audio
send_document
send_sticker
send_video
send_animation
send_voice
send_video_note
send_media_group
send_location
send_venue
send_contact
send_cached_media
send_chat_action
edit_message_text
edit_message_caption
edit_message_reply_markup
edit_message_media
delete_messages
get_messages
get_history
get_history_count
iter_history
send_poll
vote_poll
stop_poll
retract_vote
download_media
- :meth:`~Client.send_message`
- :meth:`~Client.forward_messages`
- :meth:`~Client.send_photo`
- :meth:`~Client.send_audio`
- :meth:`~Client.send_document`
- :meth:`~Client.send_sticker`
- :meth:`~Client.send_animated_sticker`
- :meth:`~Client.send_video`
- :meth:`~Client.send_animation`
- :meth:`~Client.send_voice`
- :meth:`~Client.send_video_note`
- :meth:`~Client.send_media_group`
- :meth:`~Client.send_location`
- :meth:`~Client.send_venue`
- :meth:`~Client.send_contact`
- :meth:`~Client.send_cached_media`
- :meth:`~Client.send_chat_action`
- :meth:`~Client.edit_message_text`
- :meth:`~Client.edit_message_caption`
- :meth:`~Client.edit_message_reply_markup`
- :meth:`~Client.edit_message_media`
- :meth:`~Client.delete_messages`
- :meth:`~Client.get_messages`
- :meth:`~Client.get_history`
- :meth:`~Client.get_history_count`
- :meth:`~Client.iter_history`
- :meth:`~Client.send_poll`
- :meth:`~Client.vote_poll`
- :meth:`~Client.stop_poll`
- :meth:`~Client.retract_vote`
- :meth:`~Client.download_media`
Chats
-----
^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
join_chat
leave_chat
kick_chat_member
unban_chat_member
restrict_chat_member
promote_chat_member
export_chat_invite_link
set_chat_photo
delete_chat_photo
set_chat_title
set_chat_description
pin_chat_message
unpin_chat_message
get_chat
get_chat_member
get_chat_members
get_chat_members_count
iter_chat_members
get_dialogs
iter_dialogs
get_dialogs_count
restrict_chat
update_chat_username
- :meth:`~Client.join_chat`
- :meth:`~Client.leave_chat`
- :meth:`~Client.kick_chat_member`
- :meth:`~Client.unban_chat_member`
- :meth:`~Client.restrict_chat_member`
- :meth:`~Client.promote_chat_member`
- :meth:`~Client.export_chat_invite_link`
- :meth:`~Client.set_chat_photo`
- :meth:`~Client.delete_chat_photo`
- :meth:`~Client.set_chat_title`
- :meth:`~Client.set_chat_description`
- :meth:`~Client.pin_chat_message`
- :meth:`~Client.unpin_chat_message`
- :meth:`~Client.get_chat`
- :meth:`~Client.get_chat_member`
- :meth:`~Client.get_chat_members`
- :meth:`~Client.get_chat_members_count`
- :meth:`~Client.iter_chat_members`
- :meth:`~Client.get_dialogs`
- :meth:`~Client.iter_dialogs`
- :meth:`~Client.get_dialogs_count`
- :meth:`~Client.restrict_chat`
- :meth:`~Client.update_chat_username`
Users
-----
^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
get_me
get_users
get_user_profile_photos
get_user_profile_photos_count
set_user_profile_photo
delete_user_profile_photos
update_username
- :meth:`~Client.get_me`
- :meth:`~Client.get_users`
- :meth:`~Client.get_profile_photos`
- :meth:`~Client.get_profile_photos_count`
- :meth:`~Client.iter_profile_photos`
- :meth:`~Client.set_profile_photo`
- :meth:`~Client.delete_profile_photos`
- :meth:`~Client.update_username`
- :meth:`~Client.get_user_dc`
Contacts
--------
^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
add_contacts
get_contacts
get_contacts_count
delete_contacts
- :meth:`~Client.add_contacts`
- :meth:`~Client.get_contacts`
- :meth:`~Client.get_contacts_count`
- :meth:`~Client.delete_contacts`
Password
--------
^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
enable_cloud_password
change_cloud_password
remove_cloud_password
- :meth:`~Client.enable_cloud_password`
- :meth:`~Client.change_cloud_password`
- :meth:`~Client.remove_cloud_password`
Bots
----
^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
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
- :meth:`~Client.get_inline_bot_results`
- :meth:`~Client.send_inline_bot_result`
- :meth:`~Client.answer_callback_query`
- :meth:`~Client.answer_inline_query`
- :meth:`~Client.request_callback_answer`
- :meth:`~Client.send_game`
- :meth:`~Client.set_game_score`
- :meth:`~Client.get_game_high_scores`
-----
Details
-------
.. Utilities
---------
.. automethod:: pyrogram.Client.start()
.. automethod:: pyrogram.Client.stop()
.. automethod:: pyrogram.Client.restart()
.. automethod:: pyrogram.Client.idle()
.. automethod:: pyrogram.Client.run()
.. automethod:: pyrogram.Client.add_handler()
.. automethod:: pyrogram.Client.remove_handler()
.. automethod:: pyrogram.Client.send()
.. automethod:: pyrogram.Client.resolve_peer()
.. automethod:: pyrogram.Client.save_file()
.. automethod:: pyrogram.Client.stop_transmission()
.. automethod:: Client.start()
.. automethod:: Client.stop()
.. automethod:: Client.restart()
.. automethod:: Client.idle()
.. automethod:: Client.run()
.. automethod:: Client.add_handler()
.. automethod:: Client.remove_handler()
.. automethod:: Client.send()
.. automethod:: Client.resolve_peer()
.. automethod:: Client.save_file()
.. automethod:: Client.stop_transmission()
.. Messages
--------
.. automethod:: pyrogram.Client.send_message()
.. automethod:: pyrogram.Client.forward_messages()
.. automethod:: pyrogram.Client.send_photo()
.. automethod:: pyrogram.Client.send_audio()
.. automethod:: pyrogram.Client.send_document()
.. automethod:: pyrogram.Client.send_sticker()
.. automethod:: pyrogram.Client.send_video()
.. automethod:: pyrogram.Client.send_animation()
.. automethod:: pyrogram.Client.send_voice()
.. automethod:: pyrogram.Client.send_video_note()
.. automethod:: pyrogram.Client.send_media_group()
.. automethod:: pyrogram.Client.send_location()
.. automethod:: pyrogram.Client.send_venue()
.. automethod:: pyrogram.Client.send_contact()
.. automethod:: pyrogram.Client.send_cached_media()
.. automethod:: pyrogram.Client.send_chat_action()
.. automethod:: pyrogram.Client.edit_message_text()
.. automethod:: pyrogram.Client.edit_message_caption()
.. automethod:: pyrogram.Client.edit_message_reply_markup()
.. automethod:: pyrogram.Client.edit_message_media()
.. automethod:: pyrogram.Client.delete_messages()
.. automethod:: pyrogram.Client.get_messages()
.. automethod:: pyrogram.Client.get_history()
.. automethod:: pyrogram.Client.get_history_count()
.. automethod:: pyrogram.Client.iter_history()
.. automethod:: pyrogram.Client.send_poll()
.. automethod:: pyrogram.Client.vote_poll()
.. automethod:: pyrogram.Client.stop_poll()
.. automethod:: pyrogram.Client.retract_vote()
.. automethod:: pyrogram.Client.download_media()
.. automethod:: Client.send_message()
.. automethod:: Client.forward_messages()
.. automethod:: Client.send_photo()
.. automethod:: Client.send_audio()
.. automethod:: Client.send_document()
.. automethod:: Client.send_sticker()
.. automethod:: Client.send_animated_sticker()
.. automethod:: Client.send_video()
.. automethod:: Client.send_animation()
.. automethod:: Client.send_voice()
.. automethod:: Client.send_video_note()
.. automethod:: Client.send_media_group()
.. automethod:: Client.send_location()
.. automethod:: Client.send_venue()
.. automethod:: Client.send_contact()
.. automethod:: Client.send_cached_media()
.. automethod:: Client.send_chat_action()
.. automethod:: Client.edit_message_text()
.. automethod:: Client.edit_message_caption()
.. automethod:: Client.edit_message_reply_markup()
.. automethod:: Client.edit_message_media()
.. automethod:: Client.delete_messages()
.. automethod:: Client.get_messages()
.. automethod:: Client.get_history()
.. automethod:: Client.get_history_count()
.. automethod:: Client.iter_history()
.. automethod:: Client.send_poll()
.. automethod:: Client.vote_poll()
.. automethod:: Client.stop_poll()
.. automethod:: Client.retract_vote()
.. automethod:: Client.download_media()
.. Chats
-----
.. automethod:: pyrogram.Client.join_chat()
.. automethod:: pyrogram.Client.leave_chat()
.. automethod:: pyrogram.Client.kick_chat_member()
.. automethod:: pyrogram.Client.unban_chat_member()
.. automethod:: pyrogram.Client.restrict_chat_member()
.. automethod:: pyrogram.Client.promote_chat_member()
.. automethod:: pyrogram.Client.export_chat_invite_link()
.. automethod:: pyrogram.Client.set_chat_photo()
.. automethod:: pyrogram.Client.delete_chat_photo()
.. automethod:: pyrogram.Client.set_chat_title()
.. automethod:: pyrogram.Client.set_chat_description()
.. automethod:: pyrogram.Client.pin_chat_message()
.. automethod:: pyrogram.Client.unpin_chat_message()
.. automethod:: pyrogram.Client.get_chat()
.. automethod:: pyrogram.Client.get_chat_member()
.. automethod:: pyrogram.Client.get_chat_members()
.. automethod:: pyrogram.Client.get_chat_members_count()
.. automethod:: pyrogram.Client.iter_chat_members()
.. automethod:: pyrogram.Client.get_dialogs()
.. automethod:: pyrogram.Client.iter_dialogs()
.. automethod:: pyrogram.Client.get_dialogs_count()
.. automethod:: pyrogram.Client.restrict_chat()
.. automethod:: pyrogram.Client.update_chat_username()
.. automethod:: Client.join_chat()
.. automethod:: Client.leave_chat()
.. automethod:: Client.kick_chat_member()
.. automethod:: Client.unban_chat_member()
.. automethod:: Client.restrict_chat_member()
.. automethod:: Client.promote_chat_member()
.. automethod:: Client.export_chat_invite_link()
.. automethod:: Client.set_chat_photo()
.. automethod:: Client.delete_chat_photo()
.. automethod:: Client.set_chat_title()
.. automethod:: Client.set_chat_description()
.. automethod:: Client.pin_chat_message()
.. automethod:: Client.unpin_chat_message()
.. automethod:: Client.get_chat()
.. automethod:: Client.get_chat_member()
.. automethod:: Client.get_chat_members()
.. automethod:: Client.get_chat_members_count()
.. automethod:: Client.iter_chat_members()
.. automethod:: Client.get_dialogs()
.. automethod:: Client.iter_dialogs()
.. automethod:: Client.get_dialogs_count()
.. automethod:: Client.restrict_chat()
.. automethod:: Client.update_chat_username()
.. Users
-----
.. automethod:: pyrogram.Client.get_me()
.. automethod:: pyrogram.Client.get_users()
.. automethod:: pyrogram.Client.get_user_profile_photos()
.. automethod:: pyrogram.Client.get_user_profile_photos_count()
.. automethod:: pyrogram.Client.set_user_profile_photo()
.. automethod:: pyrogram.Client.delete_user_profile_photos()
.. automethod:: pyrogram.Client.update_username()
.. automethod:: Client.get_me()
.. automethod:: Client.get_users()
.. automethod:: Client.get_profile_photos()
.. automethod:: Client.get_profile_photos_count()
.. automethod:: Client.iter_profile_photos()
.. automethod:: Client.set_profile_photo()
.. automethod:: Client.delete_profile_photos()
.. automethod:: Client.update_username()
.. automethod:: Client.get_user_dc()
.. Contacts
--------
.. automethod:: pyrogram.Client.add_contacts()
.. automethod:: pyrogram.Client.get_contacts()
.. automethod:: pyrogram.Client.get_contacts_count()
.. automethod:: pyrogram.Client.delete_contacts()
.. automethod:: Client.add_contacts()
.. automethod:: Client.get_contacts()
.. automethod:: Client.get_contacts_count()
.. automethod:: Client.delete_contacts()
.. Password
--------
.. automethod:: pyrogram.Client.enable_cloud_password()
.. automethod:: pyrogram.Client.change_cloud_password()
.. automethod:: pyrogram.Client.remove_cloud_password()
.. automethod:: Client.enable_cloud_password()
.. automethod:: Client.change_cloud_password()
.. automethod:: Client.remove_cloud_password()
.. Bots
----
.. automethod:: pyrogram.Client.get_inline_bot_results()
.. automethod:: pyrogram.Client.send_inline_bot_result()
.. automethod:: pyrogram.Client.answer_callback_query()
.. automethod:: pyrogram.Client.answer_inline_query()
.. automethod:: pyrogram.Client.request_callback_answer()
.. automethod:: pyrogram.Client.send_game()
.. automethod:: pyrogram.Client.set_game_score()
.. automethod:: pyrogram.Client.get_game_high_scores()
.. automethod:: Client.get_inline_bot_results()
.. automethod:: Client.send_inline_bot_result()
.. automethod:: Client.answer_callback_query()
.. automethod:: Client.answer_inline_query()
.. automethod:: Client.request_callback_answer()
.. automethod:: Client.send_game()
.. automethod:: Client.set_game_score()
.. automethod:: Client.get_game_high_scores()

View File

@ -15,102 +15,108 @@ All Pyrogram types listed here are accessible through the main package directly.
.. currentmodule:: pyrogram
Index
-----
Users & Chats
-------------
^^^^^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 5
User
UserStatus
Chat
ChatPreview
ChatPhoto
ChatMember
ChatMembers
ChatPermissions
Dialog
Dialogs
- :class:`User`
- :class:`UserStatus`
- :class:`Chat`
- :class:`ChatPreview`
- :class:`ChatPhoto`
- :class:`ChatMember`
- :class:`ChatMembers`
- :class:`ChatPermissions`
- :class:`Dialog`
- :class:`Dialogs`
Messages & Media
----------------
^^^^^^^^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 5
Message
Messages
MessageEntity
Photo
PhotoSize
UserProfilePhotos
Audio
Document
Animation
Video
Voice
VideoNote
Contact
Location
Venue
Sticker
Game
Poll
PollOption
- :class:`Message`
- :class:`Messages`
- :class:`MessageEntity`
- :class:`Photo`
- :class:`Photos`
- :class:`Thumbnail`
- :class:`Audio`
- :class:`Document`
- :class:`Animation`
- :class:`Video`
- :class:`Voice`
- :class:`VideoNote`
- :class:`Contact`
- :class:`Location`
- :class:`Venue`
- :class:`Sticker`
- :class:`Game`
- :class:`Poll`
- :class:`PollOption`
Keyboards
---------
^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 4
ReplyKeyboardMarkup
KeyboardButton
ReplyKeyboardRemove
InlineKeyboardMarkup
InlineKeyboardButton
ForceReply
CallbackQuery
GameHighScore
GameHighScores
CallbackGame
- :class:`ReplyKeyboardMarkup`
- :class:`KeyboardButton`
- :class:`ReplyKeyboardRemove`
- :class:`InlineKeyboardMarkup`
- :class:`InlineKeyboardButton`
- :class:`ForceReply`
- :class:`CallbackQuery`
- :class:`GameHighScore`
- :class:`GameHighScores`
- :class:`CallbackGame`
Input Media
-----------
^^^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 4
InputMedia
InputMediaPhoto
InputMediaVideo
InputMediaAudio
InputMediaAnimation
InputMediaDocument
InputPhoneContact
- :class:`InputMedia`
- :class:`InputMediaPhoto`
- :class:`InputMediaVideo`
- :class:`InputMediaAudio`
- :class:`InputMediaAnimation`
- :class:`InputMediaDocument`
- :class:`InputPhoneContact`
Inline Mode
------------
^^^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
InlineQuery
InlineQueryResult
InlineQueryResultArticle
- :class:`InlineQuery`
- :class:`InlineQueryResult`
- :class:`InlineQueryResultArticle`
InputMessageContent
-------------------
^^^^^^^^^^^^^^^^^^^
.. autosummary::
:nosignatures:
.. hlist::
:columns: 3
InputMessageContent
InputTextMessageContent
- :class:`InputMessageContent`
- :class:`InputTextMessageContent`
-----
Details
-------
.. User & Chats
------------
.. autoclass:: User()
.. autoclass:: UserStatus()
.. autoclass:: Chat()
@ -123,14 +129,12 @@ InputMessageContent
.. autoclass:: Dialogs()
.. Messages & Media
----------------
.. autoclass:: Message()
.. autoclass:: Messages()
.. autoclass:: MessageEntity()
.. autoclass:: Photo()
.. autoclass:: PhotoSize()
.. autoclass:: UserProfilePhotos()
.. autoclass:: Photos()
.. autoclass:: Thumbnail()
.. autoclass:: Audio()
.. autoclass:: Document()
.. autoclass:: Animation()
@ -146,8 +150,6 @@ InputMessageContent
.. autoclass:: PollOption()
.. Keyboards
---------
.. autoclass:: ReplyKeyboardMarkup()
.. autoclass:: KeyboardButton()
.. autoclass:: ReplyKeyboardRemove()
@ -160,8 +162,6 @@ InputMessageContent
.. autoclass:: CallbackGame()
.. Input Media
-----------
.. autoclass:: InputMedia()
.. autoclass:: InputMediaPhoto()
.. autoclass:: InputMediaVideo()
@ -171,14 +171,10 @@ InputMessageContent
.. autoclass:: InputPhoneContact()
.. Inline Mode
-----------
.. autoclass:: InlineQuery()
.. autoclass:: InlineQueryResult()
.. autoclass:: InlineQueryResultArticle()
.. InputMessageContent
-------------------
.. autoclass:: InputMessageContent()
.. autoclass:: InputTextMessageContent()

View File

@ -43,7 +43,6 @@ autodoc_member_order = "bysource"
version = __version__
release = version
version_rst = ".. |version| replace:: {}".format(version)
templates_path = ["_templates"]
@ -61,7 +60,8 @@ html_theme_options = {
"collapse_navigation": True,
"sticky_navigation": False,
"logo_only": True,
"display_version": True
"display_version": True,
"style_external_links": True
}
html_logo = "_images/pyrogram.png"

View File

@ -17,10 +17,9 @@ What is Pyrogram?
**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and
C. It enables you to easily create custom applications for both user and bot identities (bot API alternative) via the
`MTProto API`_ with the Python programming language.
:doc:`MTProto API <topics/mtproto-vs-botapi>` with the Python programming language.
.. _Telegram: https://telegram.org
.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api
Where does the name come from?
------------------------------
@ -47,19 +46,17 @@ Why Pyrogram?
- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted.
- **Updated**, to make use of the latest Telegram API version and features.
- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed.
- **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.
- **Pluggable**: The :doc:`Smart Plugin <topics/smart-plugins>` system allows to write components with minimal
boilerplate code.
- **Comprehensive**: Execute any :doc:`advanced action <topics/advanced-usage>` an official client is able to do, and
even more.
.. _TgCrypto: https://github.com/pyrogram/tgcrypto
.. _Smart Plugin: topics/smart-plugins
.. _advanced action: topics/advanced-usage
What can MTProto do more than the Bot API?
------------------------------------------
For a detailed answer, please refer to the `MTProto vs. Bot API`_ page.
.. _MTProto vs. Bot API: topics/mtproto-vs-botapi
For a detailed answer, please refer to the :doc:`MTProto vs. Bot API <topics/mtproto-vs-botapi>` page.
Why do I need an API key for bots?
----------------------------------
@ -97,9 +94,9 @@ Telegram is slowly changing some server's internals and it's doing it in such a
inevitably. Not only this, but it seems that the new, hypothetical, file ids could also possibly expire at anytime, thus
losing the *persistence* feature.
This change will most likely affect the official `Bot API <topics/mtproto-vs-botapi#what-is-the-bot-api>`_ too
(unless Telegram implements some workarounds server-side to keep backwards compatibility, which Pyrogram could in turn
make use of) and we can expect a proper notice from Telegram.
This change will most likely affect the official :doc:`Bot API <topics/mtproto-vs-botapi>` too (unless Telegram
implements some workarounds server-side to keep backwards compatibility, which Pyrogram could in turn make use of) and
we can expect a proper notice from Telegram.
Can I use multiple clients at once on the same account?
-------------------------------------------------------
@ -125,8 +122,8 @@ from the beginning every time, and use one separate session for each parallel cl
I started a client and nothing happens!
---------------------------------------
If you are connecting from Russia, China or Iran `you need a proxy`_, because Telegram could be partially or
totally blocked in those countries.
If you are connecting from Russia, China or Iran :doc:`you need a proxy <topics/proxy>`, because Telegram could be
partially or totally blocked in those countries.
Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on
the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable network
@ -146,8 +143,6 @@ fails or not:
- DC4: ``149.154.167.91``
- DC5: ``91.108.56.149``
.. _you need a proxy: topics/proxy
I keep getting PEER_ID_INVALID error!
-------------------------------------------
@ -160,6 +155,15 @@ things:
chats).
- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``.
My verification code expires immediately!
-----------------------------------------
That is because you likely shared it across any of your Telegram chats. Yes, that's right: the server keeps scanning the
messages you send and if an active verification code is found it will immediately expire, automatically.
The reason behind this is to protect unaware users from giving their account access to any potential scammer, but if you
legitimately want to share your account(s) verification codes, consider scrambling them, e.g. ``12345````1-2-3-4-5``.
My account has been deactivated/limited!
----------------------------------------
@ -179,23 +183,15 @@ However, you might be right, and your account was deactivated/limited without an
mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at
recover@telegram.org, contact `@smstelegram`_ on Twitter or use `this form`_.
Are there any secret easter eggs?
---------------------------------
Yes. If you found one, `let me know`_!
.. _let me know: https://t.me/pyrogram
.. _@smstelegram: https://twitter.com/smstelegram
.. _this form: https://telegram.org/support
About the License
-----------------
.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png
:align: left
Pyrogram is free software and is currently licensed under the terms of the
`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it
provided that modifications are described and licensed for free under LGPLv3+.
In other words: you can use and integrate Pyrogram into your own code --- either open source, under the same or
different license, or even proprietary --- without being required to release the source code of your own applications.
However, any modifications to the library itself are required to be published for free under the same LGPLv3+ license.
.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser
.. _Bug Report: https://github.com/pyrogram/pyrogram/issues/new?labels=bug&template=bug_report.md
.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md

View File

@ -18,7 +18,7 @@ general. Some words may as well link to dedicated articles in case the topic is
API key
A secret code used to authenticate and/or authorize a specific application to Telegram in order for it to
control how the API is being used, for example, to prevent abuses of the API.
`More on API keys <intro/setup#api-keys>`_.
:doc:`More on API keys <intro/setup>`.
DC
Also known as *data center*, is a place where lots of computer systems are housed and used together in order to
@ -30,21 +30,21 @@ general. Some words may as well link to dedicated articles in case the topic is
RPCError
An error caused by an RPC which must be returned in place of the successful result in order to let the caller
know something went wrong. `More on RPCError <start/errors>`_.
know something went wrong. :doc:`More on RPCError <start/errors>`.
MTProto
The name of the custom-made, open and encrypted protocol by Telegram, implemented in Pyrogram.
`More on MTProto <topics/mtproto-vs-botapi>`_.
:doc:`More on MTProto <topics/mtproto-vs-botapi>`.
MTProto API
The Telegram main API Pyrogram makes use of, which is able to connect both users and normal bots to Telegram
using MTProto as application layer protocol and execute any method Telegram provides from its public TL-schema.
`More on MTProto API <topics/mtproto-vs-botapi#what-is-the-mtproto-api>`_.
:doc:`More on MTProto API <topics/mtproto-vs-botapi>`.
Bot API
The Telegram Bot API that is able to only connect normal bots only to Telegram using HTTP as application layer
protocol and allows to execute a sub-set of the main Telegram API.
`More on Bot API <topics/mtproto-vs-botapi#what-is-the-bot-api>`_.
:doc:`More on Bot API <topics/mtproto-vs-botapi>`.
Pyrogrammer
A developer that uses Pyrogram to build Telegram applications.
@ -65,11 +65,11 @@ general. Some words may as well link to dedicated articles in case the topic is
Handler
An object that wraps around a callback function that is *actually meant* to be registered into the framework,
which will then be able to handle a specific kind of events, such as a new incoming message, for example.
`More on Handlers <start/updates>`_.
:doc:`More on Handlers <start/updates>`.
Decorator
Also known as *function decorator*, in Python, is a callable object that is used to modify another function.
Decorators in Pyrogram are used to automatically register callback functions for handling updates.
`More on Decorators <start/updates#using-decorators>`_.
:doc:`More on Decorators <start/updates>`.
.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md

View File

@ -42,10 +42,9 @@ Welcome to Pyrogram
**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and
C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the
`MTProto API`_.
:doc:`MTProto API <topics/mtproto-vs-botapi>`.
.. _Telegram: https://telegram.org
.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api
How the Documentation is Organized
----------------------------------
@ -60,15 +59,10 @@ First Steps
.. hlist::
:columns: 2
- `Quick Start`_: Overview to get you started quickly.
- `Calling Methods`_: How to call Pyrogram's methods.
- `Handling Updates`_: How to handle Telegram updates.
- `Error Handling`_: How to handle API errors correctly.
.. _Quick Start: intro/quickstart
.. _Calling Methods: start/invoking
.. _Handling Updates: start/updates
.. _Error Handling: start/errors
- :doc:`Quick Start <intro/quickstart>`: Overview to get you started quickly.
- :doc:`Calling Methods <start/invoking>`: How to call Pyrogram's methods.
- :doc:`Handling Updates <start/updates>`: How to handle Telegram updates.
- :doc:`Error Handling <start/errors>`: How to handle API errors correctly.
API Reference
-------------
@ -76,15 +70,10 @@ API Reference
.. hlist::
:columns: 2
- `Pyrogram Client`_: Reference details about the Client class.
- `Available Methods`_: List of available high-level methods.
- `Available Types`_: List of available high-level types.
- `Bound Methods`_: List of convenient bound methods.
.. _Pyrogram Client: ./api/client
.. _Available Methods: api/methods
.. _Available Types: api/types
.. _Bound Methods: api/bound-methods
- :doc:`Pyrogram Client <api/client>`: Reference details about the Client class.
- :doc:`Available Methods <api/methods>`: List of available high-level methods.
- :doc:`Available Types <api/types>`: List of available high-level types.
- :doc:`Bound Methods <api/bound-methods>`: List of convenient bound methods.
Meta
----
@ -92,17 +81,12 @@ Meta
.. hlist::
:columns: 2
- `Pyrogram FAQ`_: Answers to common Pyrogram questions.
- `Pyrogram Glossary`_: List of words with brief explanations.
- `Release Notes`_: Release notes for Pyrogram releases.
- `Powered by Pyrogram`_: Collection of Pyrogram Projects.
- `Support Pyrogram`_: Ways to show your appreciation.
.. _Pyrogram FAQ: faq
.. _Pyrogram Glossary: glossary
.. _Release Notes: releases
.. _Powered by Pyrogram: powered-by
.. _Support Pyrogram: support-pyrogram
- :doc:`Pyrogram FAQ <faq>`: Answers to common Pyrogram questions.
- :doc:`Pyrogram Glossary <glossary>`: List of words with brief explanations.
- :doc:`Release Notes <releases>`: Release notes for Pyrogram releases.
- :doc:`Powered by Pyrogram <powered-by>`: Collection of Pyrogram Projects.
- :doc:`Support Pyrogram <support-pyrogram>`: Ways to show your appreciation.
- :doc:`About the License <license>`: Information about the Project license.
.. toctree::
:hidden:
@ -163,6 +147,7 @@ Meta
releases
powered-by
support-pyrogram
license
.. toctree::
:hidden:
@ -170,3 +155,5 @@ Meta
telegram/functions/index
telegram/types/index
Last updated on |today|

View File

@ -20,7 +20,7 @@ Install Pyrogram
$ pip3 install -U pyrogram
- or, with TgCrypto_ as extra requirement (recommended):
- or, with :doc:`TgCrypto <../topics/tgcrypto>` as extra requirement (recommended):
.. code-block:: text
@ -89,5 +89,4 @@ If no error shows up you are good to go.
>>> pyrogram.__version__
'|version|'
.. _TgCrypto: ../topics/tgcrypto
.. _`Github repo`: http://github.com/pyrogram/pyrogram

View File

@ -43,7 +43,7 @@ Enjoy the API
That was just a quick overview that barely scratched the surface!
In the next few pages of the introduction, we'll take a much more in-depth look of what we have just done above.
Feeling eager to continue? You can take a shortcut to `Calling Methods`_ and come back later to learn some more details.
Feeling eager to continue? You can take a shortcut to :doc:`Calling Methods <../start/invoking>` and come back later to
learn some more details.
.. _community: //t.me/Pyrogram
.. _Calling Methods: ../start/invoking

View File

@ -1,8 +1,8 @@
Project Setup
=============
We have just `installed Pyrogram`_. In this page we'll discuss what you need to do in order to set up a project with
the library. Let's see how it's done.
We have just :doc:`installed Pyrogram <install>`. In this page we'll discuss what you need to do in order to set up a
project with the library. Let's see how it's done.
API Keys
--------
@ -26,7 +26,7 @@ The very first step requires you to obtain a valid Telegram API key (API id/hash
Configuration
-------------
Having the API key from the `previous step <#api-keys>`_ in handy, we can now begin to configure a Pyrogram project.
Having the API key from the previous step in handy, we can now begin to configure a Pyrogram project.
There are two ways to do so, and you can choose what fits better for you:
- First option (recommended): create a new ``config.ini`` file at the root of your working directory, copy-paste the
@ -57,5 +57,3 @@ There are two ways to do so, and you can choose what fits better for you:
To keep code snippets clean and concise, from now on it is assumed you are making use of the ``config.ini`` file,
thus, the *api_id* and *api_hash* parameters usage won't be shown anymore.
.. _installed Pyrogram: install.html

15
docs/source/license.rst Normal file
View File

@ -0,0 +1,15 @@
About the License
=================
.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png
:align: left
Pyrogram is free software and is currently licensed under the terms of the
`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it
provided that modifications are described and licensed for free under LGPLv3+.
In other words: you can use and integrate Pyrogram into your own code --- either open source, under the same or a
different license, or even proprietary --- without being required to release the source code of your own applications.
However, any modifications to the library itself are required to be published for free under the same LGPLv3+ license.
.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser

View File

@ -1,7 +1,7 @@
Authorization
=============
Once a `project is set up`_, you will still have to follow a few steps before you can actually use Pyrogram to make
Once a :doc:`project is set up <../intro/setup>`, you will still have to follow a few steps before you can actually use Pyrogram to make
API calls. This section provides all the information you need in order to authorize yourself as user or bot.
User Authorization
@ -9,8 +9,8 @@ User Authorization
In order to use the API, Telegram requires that users be authorized via their phone numbers.
Pyrogram automatically manages this process, 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:
:class:`~pyrogram.Client` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call
the :meth:`~pyrogram.Client.run` method:
.. code-block:: python
@ -47,7 +47,7 @@ Bot Authorization
Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by
the `Bot Father`_. Bot tokens replace the users' phone numbers only — you still need to
`configure a Telegram API key <../intro/setup#configuration>`_ with Pyrogram, even when using bots.
:doc:`configure a Telegram API key <../intro/setup>` with Pyrogram, even when using bots.
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
@ -64,6 +64,5 @@ after the session name, which will be ``my_bot.session`` for the example below.
app.run()
.. _project is set up: ../intro/setup
.. _Country Code: https://en.wikipedia.org/wiki/List_of_country_calling_codes
.. _Bot Father: https://t.me/botfather

View File

@ -1,8 +1,8 @@
Calling Methods
===============
At this point, we have successfully `installed Pyrogram`_ and authorized_ our account; we are now aiming towards the
core of the library. It's time to start playing with the API!
At this point, we have successfully :doc:`installed Pyrogram <../intro/install>` and :doc:`authorized <auth>` our
account; we are now aiming towards the core of the library. It's time to start playing with the API!
Basic Usage
-----------
@ -63,8 +63,8 @@ Context Manager
---------------
You can also use Pyrogram's Client 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. The example above can be therefore rewritten in a much nicer way:
:meth:`~pyrogram.Client.start` and :meth:`~pyrogram.Client.stop` gracefully, even in case of unhandled exceptions in
your code. The example above can be therefore rewritten in a much nicer way:
.. code-block:: python
@ -79,6 +79,3 @@ exceptions in your code. The example above can be therefore rewritten in a much
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
More examples can be found on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/examples>`_.
.. _installed Pyrogram: ../intro/install.html
.. _authorized: ../intro/setup.html

View File

@ -1,8 +1,8 @@
Handling Updates
================
Calling `API methods`_ sequentially is cool, but how to react when, for example, a new message arrives? This page deals
with updates and how to handle such events in Pyrogram. Let's have a look at how they work.
Calling :doc:`API methods <invoking>` sequentially is cool, but how to react when, for example, a new message arrives?
This page deals with updates and how to handle such events in Pyrogram. Let's have a look at how they work.
Defining Updates
----------------
@ -10,7 +10,7 @@ Defining Updates
First, let's define what are these updates. As hinted already, updates are simply events that happen in your Telegram
account (incoming messages, new members join, bot button presses, etc...), which are meant to notify you about a new
specific state that has changed. These updates are handled by registering one or more callback functions in your app
using `Handlers <../api/handlers>`_.
using :doc:`Handlers <../api/handlers>`.
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
function will be called back by the framework and its body executed.
@ -18,17 +18,16 @@ function will be called back by the framework and its body executed.
Registering a Handler
---------------------
To explain how handlers work let's have a look at the most used one, the
:obj:`MessageHandler <pyrogram.MessageHandler>`, which will be in charge for handling :obj:`Message <pyrogram.Message>`
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.
To explain how handlers work let's have a look at the most used one, the :class:`~pyrogram.MessageHandler`, which will
be in charge for handling :class:`~pyrogram.Message` 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:
The :meth:`~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
@ -55,24 +54,23 @@ call that function by passing the client instance and the new message instance a
def my_function(client, message):
print(message)
Second one: the :obj:`MessageHandler <pyrogram.MessageHandler>`. This object tells Pyrogram the function we defined
above must only handle updates that are in form of a :obj:`Message <pyrogram.Message>`:
Second one: the :class:`~pyrogram.MessageHandler`. This object tells Pyrogram the function we defined above must only
handle updates that are in form of a :class:`~pyrogram.Message`:
.. code-block:: python
my_handler = MessageHandler(my_function)
Third: the method :meth:`add_handler() <pyrogram.Client.add_handler>`. This method is used to actually register the
handler and let Pyrogram know it needs to be taken into consideration when new updates arrive and the internal
dispatching phase begins.
Third: the method :meth:`~pyrogram.Client.add_handler`. This method is used to actually register the handler and let
Pyrogram know it needs to be taken into consideration when new updates arrive and the internal dispatching phase begins.
.. code-block:: python
app.add_handler(my_handler)
Last one, the :meth:`run() <pyrogram.Client.run>` method. What this does is simply call
:meth:`start() <pyrogram.Client.start>` and a special method :meth:`idle() <pyrogram.Client.idle>` that keeps your main
scripts alive until you press ``CTRL+C``; the client will be automatically stopped after that.
Last one, the :meth:`~pyrogram.Client.run` method. What this does is simply call :meth:`~pyrogram.Client.start` and a
special method :meth:`~pyrogram.Client.idle` that keeps your main scripts alive until you press ``CTRL+C``; the client
will be automatically stopped after that.
.. code-block:: python
@ -82,7 +80,7 @@ Using Decorators
----------------
All of the above will become quite verbose, especially in case you have lots of handlers to register. A much nicer way
to do so is by decorating your callback function with the :meth:`on_message() <pyrogram.Client.on_message>` decorator.
to do so is by decorating your callback function with the :meth:`~pyrogram.Client.on_message` decorator.
.. code-block:: python
@ -108,5 +106,3 @@ to do so is by decorating your callback function with the :meth:`on_message() <p
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, accessed by bracket notation *[0]*.
.. _API methods: invoking

View File

@ -1,8 +1,8 @@
Support Pyrogram
================
Pyrogram is free and open source software, and thus supported by your love! If you like the project and have found it to
be useful, give Pyrogram a `Star on GitHub`_. Your appreciation means a lot and helps staying motivated.
Pyrogram is free and open source software, and thus powered by your love and support! If you like the project and have
found it to be useful, give Pyrogram a `Star on GitHub`_. Your appreciation means a lot and helps staying motivated.
.. raw:: html
@ -12,8 +12,9 @@ be useful, give Pyrogram a `Star on GitHub`_. Your appreciation means a lot and
Donate
------
If you'd also like to donate in order to support Pyrogram -- or any of my `other works`_ -- you can use the PayPal
button below. Thank you.
As a developer, you probably understand that "open source" doesn't mean "free work". A lot of time and resources has
been put into the project and if you'd like to tip me for Pyrogram -- or any of my `other works`_ -- you can use the
PayPal button below. Thank you!
.. image:: https://i.imgur.com/fasFTzK.png
:target: https://paypal.me/delivrance

View File

@ -1,8 +1,9 @@
Advanced Usage
==============
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.
Pyrogram's API, which consists of well documented convenience :doc:`methods <../api/methods>` and facade
:doc:`types <../api/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.
@ -11,7 +12,7 @@ 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>`.
Telegram API, you have to use the raw :mod:`~pyrogram.api.functions` and :mod:`~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
@ -21,24 +22,25 @@ some pitfalls to take into consideration when working with the raw API.
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 (yet much more
powerful).
Nothing stops you from using the raw functions only, but they are rather complex and
:doc:`plenty of them <../api/methods>` are already 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_!
Invoking Functions
^^^^^^^^^^^^^^^^^^
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.
Unlike the :doc:`methods <../api/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.
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.
First of all, both :doc:`raw functions <../telegram/functions/index>` and :doc:`raw types <../telegram/types/index>` 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.
Next, to actually invoke the raw function you have to use the :meth:`~pyrogram.Client.send` method provided by the
Client class and pass the function object you created.
Here's some examples:
@ -101,12 +103,12 @@ 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:
- :obj:`InputPeerUser <../telegram/types/InputPeerUser>` - Users
- :obj:`InputPeerChat <../telegram/types/InputPeerChat>` - Basic Chats
- :obj:`InputPeerChannel <../telegram/types/InputPeerChannel>` - Either Channels or Supergroups
- :class:`~pyrogram.api.types.InputPeerUser` - Users
- :class:`~pyrogram.api.types.InputPeerChat` - Basic Chats
- :class:`~pyrogram.api.types.InputPeerChannel` - Either Channels or Supergroups
But you don't necessarily have to manually instantiate each object because, luckily for you, Pyrogram already provides
:meth:`resolve_peer() <pyrogram.Client.resolve_peer>` as a convenience utility method that returns the correct InputPeer
:meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer
by accepting a peer ID only.
Another thing to take into consideration about chat IDs is the way they are represented: they are all integers and
@ -125,9 +127,4 @@ For example, given the ID *123456789*, here's how Pyrogram can tell entities apa
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.
.. _methods: ../api/methods
.. _types: ../api/types
.. _plenty of them: ../api/methods
.. _raw functions: ../telegram/functions
.. _raw types: ../telegram/types
.. _Community: https://t.me/Pyrogram

View File

@ -3,7 +3,7 @@ Auto Authorization
Manually writing phone number, phone code and password on the terminal every time you want to login can be tedious.
Pyrogram is able to automate both **Log In** and **Sign Up** processes, all you need to do is pass the relevant
parameters when creating a new :class:`Client <pyrogram.Client>`.
parameters when creating a new :class:`~pyrogram.Client`.
.. note:: If you omit any of the optional parameter required for the authorization, Pyrogram will ask you to
manually write it. For instance, if you don't want to set a ``last_name`` when creating a new account you

View File

@ -7,8 +7,7 @@ Inline Bots
-----------
- If a bot accepts inline queries, you can call it by using
:meth:`get_inline_bot_results() <pyrogram.Client.get_inline_bot_results>` to get the list of its inline results
for a query:
:meth:`~pyrogram.Client.get_inline_bot_results` to get the list of its inline results for a query:
.. code-block:: python
@ -24,7 +23,7 @@ Inline Bots
results list.
- After you retrieved the bot results, you can use
:meth:`send_inline_bot_result() <pyrogram.Client.send_inline_bot_result>` to send a chosen result to any chat:
:meth:`~pyrogram.Client.send_inline_bot_result` to send a chosen result to any chat:
.. code-block:: python

View File

@ -4,7 +4,7 @@ Using 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.
Here we'll discuss about :class:`Filters <pyrogram.Filters>`. Filters enable a fine-grain control over what kind of
Here we'll discuss about :class:`~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.
Single Filters
@ -12,7 +12,7 @@ Single Filters
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
- This example will show you how to **only** handle messages containing an :class:`~pyrogram.Audio` object and
ignore any other message. Filters are passed as the first argument of the decorator:
.. code-block:: python
@ -69,7 +69,7 @@ Here are some examples:
Advanced Filters
----------------
Some filters, like :meth:`command() <pyrogram.Filters.command>` or :meth:`regex() <pyrogram.Filters.regex>`
Some filters, like :meth:`~pyrogram.Filters.command` or :meth:`~pyrogram.Filters.regex`
can also accept arguments:
- Message is either a */start* or */help* **command**.
@ -109,18 +109,18 @@ More handlers using different filters can also live together.
Custom Filters
--------------
Pyrogram already provides lots of built-in :class:`Filters <pyrogram.Filters>` to work with, but in case you can't find
Pyrogram already provides lots of built-in :class:`~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 kind of handler,
for example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
for example) you can use :meth:`~pyrogram.Filters.create`.
.. note::
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`
only.
At the moment, the built-in filters are intended to be used with the :class:`~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:
:class:`~pyrogram.CallbackQueryHandler`. Note that callback queries updates are only received by bots; create and
:doc:`authorize your bot <../start/auth>`, 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
@ -137,7 +137,7 @@ keyboard to yourself. This allows you to test your filter by pressing the inline
Basic Filters
^^^^^^^^^^^^^
For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
For this basic filter we will be using only the first two parameters of :meth:`~pyrogram.Filters.create`.
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
@ -175,7 +175,7 @@ Filters with Arguments
^^^^^^^^^^^^^^^^^^^^^^
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>`.
A dynamic filter like this will make use of the third parameter of :meth:`~pyrogram.Filters.create`.
This is how a dynamic custom filter looks like:

View File

@ -1,7 +1,8 @@
More on Updates
===============
Here we'll show some advanced usages when working with `update handlers`_ and `filters`_.
Here we'll show some advanced usages when working with :doc:`update handlers <../start/updates>` and
:doc:`filters <filters>`.
Handler Groups
--------------
@ -44,7 +45,7 @@ Or, if you want ``just_text`` to be fired *before* ``text_or_sticker`` (note ``-
def just_text(client, message):
print("Just Text")
With :meth:`add_handler() <pyrogram.Client.add_handler>` (without decorators) the same can be achieved with:
With :meth:`~pyrogram.Client.add_handler` (without decorators) the same can be achieved with:
.. code-block:: python
@ -217,6 +218,3 @@ The output of both (equivalent) examples will be:
0
1
2
.. _`update handlers`: ../start/updates
.. _`filters`: filters

View File

@ -9,7 +9,8 @@ For Humans - str(obj)
---------------------
If you want a nicely formatted, human readable JSON representation of any object in the API -- namely, any object from
`Pyrogram types`_, `raw functions`_ and `raw types`_ -- you can use use ``str(obj)``.
:doc:`Pyrogram types <../api/types>`, :doc:`raw functions <../telegram/functions/index>` and
:doc:`raw types <../telegram/types/index>` -- you can use use ``str(obj)``.
.. code-block:: python
@ -25,10 +26,6 @@ If you want a nicely formatted, human readable JSON representation of any object
When using ``print()`` you don't actually need to use ``str()`` on the object because it is called automatically, we
have done that above just to show you how to explicitly convert a Pyrogram object to JSON.
.. _Pyrogram types: ../api/types
.. _raw functions: ../telegram/functions
.. _raw types: ../telegram/types
For Machines - repr(obj)
------------------------

View File

@ -5,7 +5,7 @@ As you may probably know, Telegram allows users (and bots) having more than one
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 <../telegram/functions/account/GetAuthorizations.html>`_ with Pyrogram). They
app (or by invoking :class:`~pyrogram.api.functions.account.GetAuthorizations` 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/YaqtMLO.png

View File

@ -65,8 +65,8 @@ after importing your modules, like this:
app.run()
This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
manually ``import``, manually :meth:`add_handler() <pyrogram.Client.add_handler>` and manually instantiate each
:obj:`MessageHandler <pyrogram.MessageHandler>` object because **you can't use those cool decorators** for your
manually ``import``, manually :meth:`~pyrogram.Client.add_handler` and manually instantiate each
:class:`~pyrogram.MessageHandler` object because **you can't use those cool decorators** for your
functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically.
Using Smart Plugins
@ -80,7 +80,7 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight
.. note::
This is the same example application `as shown above <#introduction>`_, written using the Smart Plugin system.
This is the same example application as shown above, written using the Smart Plugin system.
.. code-block:: text
:emphasize-lines: 2, 3
@ -156,7 +156,7 @@ found inside each module will be, instead, loaded in the order they are defined,
.. note::
Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping
filters included a second time will not work. Learn more at `More on Updates <more-on-updates>`_.
filters included a second time will not work. Learn more at :doc:`More on Updates <more-on-updates>`.
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``
@ -288,9 +288,8 @@ also organized in subfolders:
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 plugin at runtime.
In the previous section 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 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
@ -318,7 +317,7 @@ 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
relevant module and call :meth:`~pyrogram.Client.remove_handler` Client's method with your function
name preceded by the star ``*`` operator as argument. Example:
- ``main.py``
@ -343,7 +342,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:`~pyrogram.Client.add_handler` instead. Example:
- ``main.py``

View File

@ -12,7 +12,7 @@ Markdown Style
--------------
To use this mode, pass "markdown" in the *parse_mode* field when using
:obj:`send_message() <pyrogram.Client.send_message>`. Use the following syntax in your message:
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
.. code-block:: text
@ -34,7 +34,7 @@ To use this mode, pass "markdown" in the *parse_mode* field when using
HTML Style
----------
To use this mode, pass "html" in the *parse_mode* field when using :obj:`send_message() <pyrogram.Client.send_message>`.
To use this mode, pass "html" in the *parse_mode* field when using :meth:`~pyrogram.Client.send_message`.
The following tags are currently supported:
.. code-block:: text

View File

@ -24,7 +24,7 @@ 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
__version__ = "0.13.0.async"
__version__ = "0.13.0-asyncio"
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
__copyright__ = "Copyright (C) 2017-2019 Dan <https://github.com/delivrance>"

View File

@ -19,6 +19,7 @@
from .future_salt import FutureSalt
from .future_salts import FutureSalts
from .gzip_packed import GzipPacked
from .list import List
from .message import Message
from .msg_container import MsgContainer
from .object import Object

View File

@ -16,7 +16,6 @@
# 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 datetime import datetime
from io import BytesIO
from .object import Object
@ -30,15 +29,15 @@ class FutureSalt(Object):
QUALNAME = "FutureSalt"
def __init__(self, valid_since: int or datetime, valid_until: int or datetime, salt: int):
def __init__(self, valid_since: int, valid_until: int, salt: int):
self.valid_since = valid_since
self.valid_until = valid_until
self.salt = salt
@staticmethod
def read(b: BytesIO, *args) -> "FutureSalt":
valid_since = datetime.fromtimestamp(Int.read(b))
valid_until = datetime.fromtimestamp(Int.read(b))
valid_since = Int.read(b)
valid_until = Int.read(b)
salt = Long.read(b)
return FutureSalt(valid_since, valid_until, salt)

View File

@ -16,7 +16,6 @@
# 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 datetime import datetime
from io import BytesIO
from . import FutureSalt
@ -31,7 +30,7 @@ class FutureSalts(Object):
QUALNAME = "FutureSalts"
def __init__(self, req_msg_id: int, now: int or datetime, salts: list):
def __init__(self, req_msg_id: int, now: int, salts: list):
self.req_msg_id = req_msg_id
self.now = now
self.salts = salts
@ -39,7 +38,7 @@ class FutureSalts(Object):
@staticmethod
def read(b: BytesIO, *args) -> "FutureSalts":
req_msg_id = Long.read(b)
now = datetime.fromtimestamp(Int.read(b))
now = Int.read(b)
count = Int.read(b)
salts = [FutureSalt.read(b) for _ in range(count)]

28
pyrogram/api/core/list.py Normal file
View File

@ -0,0 +1,28 @@
# 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 .object import Object
class List(list, Object):
__slots__ = []
def __repr__(self):
return "pyrogram.api.core.List([{}])".format(
",".join(Object.__repr__(i) for i in self)
)

View File

@ -17,7 +17,6 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
from datetime import datetime
from io import BytesIO
from json import dumps
@ -36,32 +35,22 @@ class Object:
def write(self, *args) -> bytes:
pass
def __eq__(self, other: "Object") -> bool:
for attr in self.__slots__:
try:
if getattr(self, attr) != getattr(other, attr):
return False
except AttributeError:
return False
@staticmethod
def default(obj: "Object"):
if isinstance(obj, bytes):
return repr(obj)
return True
return OrderedDict(
[("_", obj.QUALNAME)]
+ [
(attr, getattr(obj, attr))
for attr in obj.__slots__
if getattr(obj, attr) is not None
]
)
def __str__(self) -> str:
def default(obj: Object):
try:
return OrderedDict(
[("_", obj.QUALNAME)]
+ [(attr, getattr(obj, attr))
for attr in obj.__slots__
if getattr(obj, attr) is not None]
)
except AttributeError:
if isinstance(obj, datetime):
return obj.strftime("%d-%b-%Y %H:%M:%S")
else:
return repr(obj)
return dumps(self, indent=4, default=default, ensure_ascii=False)
return dumps(self, indent=4, default=Object.default, ensure_ascii=False)
def __repr__(self) -> str:
return "pyrogram.api.{}({})".format(
@ -73,6 +62,16 @@ class Object:
)
)
def __eq__(self, other: "Object") -> bool:
for attr in self.__slots__:
try:
if getattr(self, attr) != getattr(other, attr):
return False
except AttributeError:
return False
return True
def __len__(self) -> int:
return len(self.write())

View File

@ -19,6 +19,7 @@
from io import BytesIO
from . import Int
from ..list import List
from ..object import Object
@ -37,11 +38,11 @@ class Vector(Object):
@staticmethod
def read(b: BytesIO, t: Object = None) -> list:
return [
return List(
t.read(b) if t
else Vector._read(b)
for _ in range(Int.read(b))
]
)
def __new__(cls, value: list, t: Object = None) -> bytes:
return b"".join(

View File

@ -18,7 +18,6 @@
import asyncio
import base64
import binascii
import inspect
import json
import logging
@ -27,7 +26,6 @@ import mimetypes
import os
import re
import shutil
import struct
import tempfile
import time
from configparser import ConfigParser
@ -49,7 +47,7 @@ from pyrogram.errors import (
PhoneNumberUnoccupied, PhoneCodeInvalid, PhoneCodeHashEmpty,
PhoneCodeExpired, PhoneCodeEmpty, SessionPasswordNeeded,
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate, PhoneNumberOccupied,
VolumeLocNotFound, UserMigrate, ChannelPrivate, PhoneNumberOccupied,
PasswordRecoveryNa, PasswordEmpty
)
from pyrogram.session import Auth, Session
@ -320,7 +318,7 @@ class Client(Methods, BaseClient):
await self.get_initial_dialogs()
await self.get_contacts()
else:
await self.send(functions.messages.GetPinnedDialogs())
await self.send(functions.messages.GetPinnedDialogs(folder_id=0))
await self.get_initial_dialogs_chunk()
else:
await self.send(functions.updates.GetState())
@ -430,9 +428,9 @@ class Client(Methods, BaseClient):
def run(self, coroutine=None):
"""Start the Client and automatically idle the main script.
This is a convenience method that literally just calls :meth:`start` and :meth:`idle`. It makes running a client
less verbose, but is not suitable in case you want to run more than one client in a single main script,
since :meth:`idle` will block.
This is a convenience method that literally just calls :meth:`~Client.start` and :meth:`~Client.idle`. It makes
running a client less verbose, but is not suitable in case you want to run more than one client in a single main
script, since :meth:`~Client.idle` will block.
Args:
coroutine: (``Coroutine``, *optional*):
@ -484,7 +482,7 @@ class Client(Methods, BaseClient):
"""Remove a previously-registered update handler.
Make sure to provide the right group that the handler was added in. You can use
the return value of the :meth:`add_handler` method, a tuple of (handler, group), and
the return value of the :meth:`~Client.add_handler` method, a tuple of (handler, group), and
pass it directly.
Parameters:
@ -777,7 +775,9 @@ class Client(Methods, BaseClient):
types.Channel, types.ChannelForbidden
]
]
):
) -> bool:
is_min = False
for entity in entities:
if isinstance(entity, types.User):
user_id = entity.id
@ -785,6 +785,7 @@ class Client(Methods, BaseClient):
access_hash = entity.access_hash
if access_hash is None:
is_min = True
continue
username = entity.username
@ -820,6 +821,7 @@ class Client(Methods, BaseClient):
access_hash = entity.access_hash
if access_hash is None:
is_min = True
continue
username = getattr(entity, "username", None)
@ -834,87 +836,62 @@ class Client(Methods, BaseClient):
if username is not None:
self.peers_by_username[username.lower()] = input_peer
return is_min
async def download_worker(self):
while True:
media = await self.download_queue.get()
packet = await self.download_queue.get()
if media is None:
if packet is None:
break
temp_file_path = ""
final_file_path = ""
try:
media, file_name, done, progress, progress_args, path = media
file_id = media.file_id
size = media.file_size
data, file_name, done, progress, progress_args, path = packet
directory, file_name = os.path.split(file_name)
directory = directory or "downloads"
try:
decoded = utils.decode(file_id)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
media_type = unpacked[0]
dc_id = unpacked[1]
id = unpacked[2]
access_hash = unpacked[3]
volume_id = None
secret = None
local_id = None
media_type_str = Client.MEDIA_TYPE_ID[data.media_type]
if len(decoded) > 24:
volume_id = unpacked[4]
secret = unpacked[5]
local_id = unpacked[6]
if not data.file_name:
guessed_extension = self.guess_extension(data.mime_type)
media_type_str = Client.MEDIA_TYPE_ID.get(media_type, None)
if media_type_str is None:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
file_name = file_name or getattr(media, "file_name", None)
if not file_name:
guessed_extension = self.guess_extension(media.mime_type)
if media_type in (0, 1, 2):
if data.media_type in (0, 1, 2, 14):
extension = ".jpg"
elif media_type == 3:
elif data.media_type == 3:
extension = guessed_extension or ".ogg"
elif media_type in (4, 10, 13):
elif data.media_type in (4, 10, 13):
extension = guessed_extension or ".mp4"
elif media_type == 5:
elif data.media_type == 5:
extension = guessed_extension or ".zip"
elif media_type == 8:
elif data.media_type == 8:
extension = guessed_extension or ".webp"
elif media_type == 9:
elif data.media_type == 9:
extension = guessed_extension or ".mp3"
else:
continue
file_name = "{}_{}_{}{}".format(
media_type_str,
datetime.fromtimestamp(
getattr(media, "date", None) or time.time()
).strftime("%Y-%m-%d_%H-%M-%S"),
datetime.fromtimestamp(data.date or time.time()).strftime("%Y-%m-%d_%H-%M-%S"),
self.rnd_id(),
extension
)
temp_file_path = await self.get_file(
dc_id=dc_id,
id=id,
access_hash=access_hash,
volume_id=volume_id,
local_id=local_id,
secret=secret,
size=size,
media_type=data.media_type,
dc_id=data.dc_id,
file_id=data.file_id,
access_hash=data.access_hash,
thumb_size=data.thumb_size,
peer_id=data.peer_id,
volume_id=data.volume_id,
local_id=data.local_id,
file_size=data.file_size,
is_big=data.is_big,
progress=progress,
progress_args=progress_args
)
@ -949,8 +926,10 @@ class Client(Methods, BaseClient):
try:
if isinstance(updates, (types.Update, types.UpdatesCombined)):
self.fetch_peers(updates.users)
self.fetch_peers(updates.chats)
is_min = self.fetch_peers(updates.users) or self.fetch_peers(updates.chats)
users = {u.id: u for u in updates.users}
chats = {c.id: c for c in updates.chats}
for update in updates.updates:
channel_id = getattr(
@ -967,7 +946,7 @@ class Client(Methods, BaseClient):
if isinstance(update, types.UpdateChannelTooLong):
log.warning(update)
if isinstance(update, types.UpdateNewChannelMessage):
if isinstance(update, types.UpdateNewChannelMessage) and is_min:
message = update.message
if not isinstance(message, types.MessageEmpty):
@ -989,22 +968,10 @@ class Client(Methods, BaseClient):
pass
else:
if not isinstance(diff, types.updates.ChannelDifferenceEmpty):
updates.users += diff.users
updates.chats += diff.chats
users.update({u.id: u for u in diff.users})
chats.update({c.id: c for c in diff.chats})
if channel_id and pts:
if channel_id not in self.channels_pts:
self.channels_pts[channel_id] = []
if pts in self.channels_pts[channel_id]:
continue
self.channels_pts[channel_id].append(pts)
if len(self.channels_pts[channel_id]) > 50:
self.channels_pts[channel_id] = self.channels_pts[channel_id][25:]
self.dispatcher.updates_queue.put_nowait((update, updates.users, updates.chats))
self.dispatcher.updates_queue.put_nowait((update, users, chats))
elif isinstance(updates, (types.UpdateShortMessage, types.UpdateShortChatMessage)):
diff = await self.send(
functions.updates.GetDifference(
@ -1021,13 +988,13 @@ class Client(Methods, BaseClient):
pts=updates.pts,
pts_count=updates.pts_count
),
diff.users,
diff.chats
{u.id: u for u in diff.users},
{c.id: c for c in diff.chats}
))
else:
self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], [], []))
self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], {}, {}))
elif isinstance(updates, types.UpdateShort):
self.dispatcher.updates_queue.put_nowait((updates.update, [], []))
self.dispatcher.updates_queue.put_nowait((updates.update, {}, {}))
elif isinstance(updates, types.UpdatesTooLong):
log.warning(updates)
except Exception as e:
@ -1333,7 +1300,7 @@ class Client(Methods, BaseClient):
return r
async def get_initial_dialogs(self):
await self.send(functions.messages.GetPinnedDialogs())
await self.send(functions.messages.GetPinnedDialogs(folder_id=0))
dialogs = await self.get_initial_dialogs_chunk()
offset_date = utils.get_offset_date(dialogs)
@ -1424,7 +1391,7 @@ class Client(Methods, BaseClient):
file_part: int = 0,
progress: callable = None,
progress_args: tuple = ()
):
):
"""Upload a file onto Telegram servers, without actually sending the message to anyone.
Useful whenever an InputFile type is required.
@ -1575,16 +1542,18 @@ class Client(Methods, BaseClient):
for session in pool:
await session.stop()
async def get_file(self,
async def get_file(self, media_type: int,
dc_id: int,
id: int = None,
access_hash: int = None,
volume_id: int = None,
local_id: int = None,
secret: int = None,
file_id: int,
access_hash: int,
thumb_size: str,
peer_id: int,
volume_id: int,
local_id: int,
file_size: int,
size: int = None,
progress: callable = None,
is_big: bool,
progress: callable,
progress_args: tuple = ()) -> str:
with await self.media_sessions_lock:
session = self.media_sessions.get(dc_id, None)
@ -1626,18 +1595,33 @@ class Client(Methods, BaseClient):
self.media_sessions[dc_id] = session
if volume_id: # Photos are accessed by volume_id, local_id, secret
location = types.InputFileLocation(
if media_type == 1:
location = types.InputPeerPhotoFileLocation(
peer=self.resolve_peer(peer_id),
volume_id=volume_id,
local_id=local_id,
secret=secret,
file_reference=b""
big=is_big or None
)
else: # Any other file can be more easily accessed by id and access_hash
location = types.InputDocumentFileLocation(
id=id,
elif media_type in (0, 2):
location = types.InputPhotoFileLocation(
id=file_id,
access_hash=access_hash,
file_reference=b""
file_reference=b"",
thumb_size=thumb_size
)
elif media_type == 14:
location = types.InputDocumentFileLocation(
id=file_id,
access_hash=access_hash,
file_reference=b"",
thumb_size=thumb_size
)
else:
location = types.InputDocumentFileLocation(
id=file_id,
access_hash=access_hash,
file_reference=b"",
thumb_size=""
)
limit = 1024 * 1024
@ -1668,7 +1652,14 @@ class Client(Methods, BaseClient):
offset += limit
if progress:
await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
await progress(
self,
min(offset, file_size)
if file_size != 0
else offset,
file_size,
*progress_args
)
r = await session.send(
functions.upload.GetFile(
@ -1750,7 +1741,14 @@ class Client(Methods, BaseClient):
offset += limit
if progress:
await progress(self, min(offset, size) if size != 0 else offset, size, *progress_args)
await progress(
self,
min(offset, file_size)
if file_size != 0
else offset,
file_size,
*progress_args
)
if len(chunk) < limit:
break

View File

@ -16,10 +16,11 @@
# 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 os
import asyncio
import os
import platform
import re
from collections import namedtuple
from pyrogram import __version__
from ..style import Markdown, HTML
@ -55,7 +56,7 @@ class BaseClient:
CONFIG_FILE = "./config.ini"
MEDIA_TYPE_ID = {
0: "thumbnail",
0: "photo_thumbnail",
1: "chat_photo",
2: "photo",
3: "voice",
@ -64,7 +65,8 @@ class BaseClient:
8: "sticker",
9: "audio",
10: "animation",
13: "video_note"
13: "video_note",
14: "document_thumbnail"
}
mime_types_to_extensions = {}
@ -81,6 +83,10 @@ class BaseClient:
mime_types_to_extensions[mime_type] = " ".join(extensions)
fields = ("media_type", "dc_id", "file_id", "access_hash", "thumb_size", "peer_id", "volume_id", "local_id",
"is_big", "file_size", "mime_type", "file_name", "date")
FileData = namedtuple("FileData", fields, defaults=(None,) * len(fields))
def __init__(self):
self.is_bot = None
self.dc_id = None
@ -89,7 +95,6 @@ class BaseClient:
self.date = None
self.rnd_id = MsgId
self.channels_pts = {}
self.peers_by_id = {}
self.peers_by_username = {}
@ -152,3 +157,6 @@ class BaseClient:
def guess_extension(self, *args, **kwargs):
pass
def get_profile_photos(self, *args, **kwargs):
pass

View File

@ -124,16 +124,13 @@ class Dispatcher:
async def update_worker(self):
while True:
update = await self.updates_queue.get()
packet = await self.updates_queue.get()
if update is None:
if packet is None:
break
try:
users = {i.id: i for i in update[1]}
chats = {i.id: i for i in update[2]}
update = update[0]
update, users, chats = packet
parser = self.update_parsers.get(type(update), None)
parsed_update, handler_type = (

View File

@ -1853,3 +1853,6 @@ video/x-msvideo avi
video/x-sgi-movie movie
video/x-smv smv
x-conference/x-cooltalk ice
# Telegram animated stickers
application/x-tgsticker tgs

View File

@ -92,7 +92,7 @@ class Syncer:
auth_key=auth_key,
user_id=client.user_id,
date=int(time.time()),
is_bot=client.is_bot,
is_bot=bool(client.is_bot),
peers_by_id={
k: getattr(v, "access_hash", None)
for k, v in client.peers_by_id.copy().items()

View File

@ -17,10 +17,13 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import asyncio
import struct
import sys
from base64 import b64decode, b64encode
from concurrent.futures.thread import ThreadPoolExecutor
from typing import Union
from . import BaseClient
from ...api import types
@ -94,3 +97,53 @@ def get_offset_date(dialogs):
return m.date
else:
return 0
def get_input_media_from_file_id(
file_id_str: str,
expected_media_type: int = None
) -> Union[types.InputMediaPhoto, types.InputMediaDocument]:
try:
decoded = decode(file_id_str)
except Exception:
raise ValueError("Failed to decode file_id: {}".format(file_id_str))
else:
media_type = decoded[0]
if expected_media_type is not None:
if media_type != expected_media_type:
media_type_str = BaseClient.MEDIA_TYPE_ID.get(media_type, None)
expected_media_type_str = BaseClient.MEDIA_TYPE_ID.get(expected_media_type, None)
raise ValueError(
'Expected: "{}", got "{}" file_id instead'.format(expected_media_type_str, media_type_str)
)
if media_type in (0, 1, 14):
raise ValueError("This file_id can only be used for download: {}".format(file_id_str))
if media_type == 2:
unpacked = struct.unpack("<iiqqc", decoded)
dc_id, file_id, access_hash, thumb_size = unpacked[1:]
return types.InputMediaPhoto(
id=types.InputPhoto(
id=file_id,
access_hash=access_hash,
file_reference=b""
)
)
if media_type in (3, 4, 5, 8, 9, 10, 13):
unpacked = struct.unpack("<iiqq", decoded)
dc_id, file_id, access_hash = unpacked[1:]
return types.InputMediaDocument(
id=types.InputDocument(
id=file_id,
access_hash=access_hash,
file_reference=b""
)
)
raise ValueError("Unknown media type: {}".format(file_id_str))

View File

@ -42,7 +42,7 @@ def create(name: str, func: callable, **kwargs) -> type:
**kwargs (``any``, *optional*):
Any keyword argument you would like to pass. Useful for custom filters that accept parameters (e.g.:
:meth:`Filters.command`, :meth:`Filters.regex`).
:meth:`~Filters.command`, :meth:`~Filters.regex`).
"""
# TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only
d = {"__call__": func}
@ -56,7 +56,7 @@ class Filters:
The Filters listed here are intended to be used with the :obj:`MessageHandler` only.
At the moment, if you want to filter updates coming from different `Handlers <Handlers.html>`_ you have to create
your own filters with :meth:`Filters.create` and use them in the same way.
your own filters with :meth:`~Filters.create` and use them in the same way.
"""
create = create
@ -219,7 +219,7 @@ class Filters:
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*
field of the :class:`Message`.
field of the :obj:`Message`.
prefix (``str`` | ``list``, *optional*):
A prefix or a list of prefixes as string the filter should look for.
@ -263,7 +263,7 @@ class Filters:
pattern (``str``):
The RegEx pattern as string, it will be applied to the text of a message. When a pattern matches,
all the `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_
are stored in the *matches* field of the :class:`Message` itself.
are stored in the *matches* field of the :obj:`Message` itself.
flags (``int``, *optional*):
RegEx flags.
@ -339,4 +339,15 @@ class Filters:
and message.from_user.is_self
and not message.outgoing)))
@staticmethod
def callback_data(data: str or bytes):
"""Filter callback queries for their data.
Parameters:
data (``str`` | ``bytes``):
Pass the data you want to filter for.
"""
return create("CallbackData", lambda flt, cb: cb.data == flt.data, data=data)
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))

View File

@ -21,10 +21,10 @@ from .handler import Handler
class CallbackQueryHandler(Handler):
"""The CallbackQuery handler class. Used to handle callback queries coming from inline buttons.
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
It is intended to be used with :meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_callback_query() <pyrogram.Client.on_callback_query>` decorator.
:meth:`~Client.on_callback_query` decorator.
Parameters:
callback (``callable``):

View File

@ -22,10 +22,10 @@ from .handler import Handler
class DeletedMessagesHandler(Handler):
"""The deleted Messages handler class. Used to handle deleted messages coming from any chat
(private, group, channel). It is intended to be used with
:meth:`add_handler() <pyrogram.Client.add_handler>`
:meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_deleted_messages() <pyrogram.Client.on_deleted_messages>` decorator.
:meth:`~Client.on_deleted_messages` decorator.
Parameters:
callback (``callable``):

View File

@ -21,10 +21,10 @@ from .handler import Handler
class DisconnectHandler(Handler):
"""The Disconnect handler class. Used to handle disconnections. It is intended to be used with
:meth:`add_handler() <pyrogram.Client.add_handler>`
:meth:~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_disconnect() <pyrogram.Client.on_disconnect>` decorator.
:meth:`~Client.on_disconnect` decorator.
Parameters:
callback (``callable``):

View File

@ -21,10 +21,10 @@ 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>`
It is intended to be used with :meth:`~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.
:meth:`~Client.on_inline_query` decorator.
Parameters:
callback (``callable``):

View File

@ -21,11 +21,10 @@ from .handler import Handler
class MessageHandler(Handler):
"""The Message handler class. Used to handle text, media and service messages coming from
any chat (private, group, channel). It is intended to be used with
:meth:`add_handler() <pyrogram.Client.add_handler>`
any chat (private, group, channel). It is intended to be used with :meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_message() <pyrogram.Client.on_message>` decorator.
:meth:`~Client.on_message` decorator.
Parameters:
callback (``callable``):

View File

@ -22,25 +22,25 @@ from .handler import Handler
class PollHandler(Handler):
"""The Poll handler class. Used to handle polls updates.
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
It is intended to be used with :meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_poll() <pyrogram.Client.on_poll>` decorator.
:meth:`~Client.on_poll` decorator.
Parameters:
callback (``callable``):
Pass a function that will be called when a new poll update arrives. It takes *(client, poll)*
as positional arguments (look at the section below for a detailed description).
filters (:obj:`Filters <pyrogram.Filters>`):
filters (:obj:`Filters`):
Pass one or more filters to allow only a subset of polls to be passed
in your callback function.
Other parameters:
client (:obj:`Client <pyrogram.Client>`):
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the poll handler.
poll (:obj:`Poll <pyrogram.Poll>`):
poll (:obj:`Poll`):
The received poll.
"""

View File

@ -21,10 +21,10 @@ from .handler import Handler
class RawUpdateHandler(Handler):
"""The Raw Update handler class. Used to handle raw updates. It is intended to be used with
:meth:`add_handler() <pyrogram.Client.add_handler>`
:meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_raw_update() <pyrogram.Client.on_raw_update>` decorator.
:meth:`~Client.on_raw_update` decorator.
Parameters:
callback (``callable``):
@ -33,7 +33,7 @@ class RawUpdateHandler(Handler):
a detailed description).
Other Parameters:
client (:class:`Client`):
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the update handler.
update (``Update``):

View File

@ -21,10 +21,10 @@ from .handler import Handler
class UserStatusHandler(Handler):
"""The UserStatus handler class. Used to handle user status updates (user going online or offline).
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
It is intended to be used with :meth:`~Client.add_handler`
For a nicer way to register this handler, have a look at the
:meth:`on_user_status() <pyrogram.Client.on_user_status>` decorator.
:meth:`~Client.on_user_status` decorator.
Parameters:
callback (``callable``):

View File

@ -35,8 +35,8 @@ class ExportChatInviteLink(BaseClient):
Each administrator in a chat generates their own invite links. Bots can't use invite links generated by
other administrators. If you want your bot to work with invite links, it will need to generate its own link
using this method after this the link will become available to the bot via the :meth:`get_chat` method.
If your bot needs to generate a new invite link replacing its previous one, use this method again.
using this method after this the link will become available to the bot via the :meth:`~Client.get_chat`
method. If your bot needs to generate a new invite link replacing its previous one, use this method again.
Parameters:
chat_id (``int`` | ``str``):

View File

@ -51,7 +51,7 @@ class GetChatMembers(BaseClient):
You can get up to 200 chat members at once.
A chat can be either a basic group, a supergroup or a channel.
You must be admin to retrieve the members list of a channel (also known as "subscribers").
For a more convenient way of getting chat members see :meth:`iter_chat_members`.
For a more convenient way of getting chat members see :meth:`~Client.iter_chat_members`.
Parameters:
chat_id (``int`` | ``str``):

View File

@ -37,7 +37,7 @@ class GetDialogs(BaseClient):
"""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`.
For a more convenient way of getting a user's dialogs see :meth:`~Client.iter_dialogs`.
Parameters:
offset_date (``int``):
@ -62,7 +62,7 @@ class GetDialogs(BaseClient):
while True:
try:
if pinned_only:
r = await self.send(functions.messages.GetPinnedDialogs())
r = await self.send(functions.messages.GetPinnedDialogs(folder_id=0))
else:
r = await self.send(
functions.messages.GetDialogs(

View File

@ -36,7 +36,7 @@ class GetDialogsCount(BaseClient):
"""
if pinned_only:
return len((await self.send(functions.messages.GetPinnedDialogs())).dialogs)
return len((await self.send(functions.messages.GetPinnedDialogs(folder_id=0))).dialogs)
else:
r = await self.send(
functions.messages.GetDialogs(

View File

@ -50,7 +50,7 @@ class IterChatMembers(BaseClient):
) -> Optional[AsyncGenerator["pyrogram.ChatMember", None]]:
"""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
This convenience method does the same as repeatedly calling :meth:`~Client.get_chat_members` in a loop, thus saving you
from the hassle of setting up boilerplate code. It is useful for getting the whole members list of a chat with
a single call.

View File

@ -29,12 +29,13 @@ class IterDialogs(BaseClient):
async def iter_dialogs(
self,
limit: int = 0,
offset_date: int = 0
offset_date: int = None
) -> Optional[AsyncGenerator["pyrogram.Dialog", None]]:
"""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
the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a single call.
This convenience method does the same as repeatedly calling :meth:`~Client.get_dialogs` in a loop, thus saving
you from the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a
single call.
Parameters:
limit (``str``, *optional*):

View File

@ -44,14 +44,14 @@ class SetChatPhoto(BaseClient):
Unique identifier (int) or username (str) of the target chat.
photo (``str``):
New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo.
New chat photo. You can pass a :obj:`Photo` id or a file path to upload a new photo.
Returns:
``bool``: True on success.
Raises:
RPCError: In case of a Telegram RPC error.
``ValueError`` if a chat_id belongs to user.
ValueError: if a chat_id belongs to user.
"""
peer = await self.resolve_peer(chat_id)

View File

@ -30,7 +30,7 @@ class UpdateChatUsername(BaseClient):
) -> bool:
"""Update a channel or a supergroup username.
To update your own username (for users only, not bots) you can use :meth:`update_username`.
To update your own username (for users only, not bots) you can use :meth:`~Client.update_username`.
Parameters:
chat_id (``int`` | ``str``)

View File

@ -32,7 +32,7 @@ class OnCallbackQuery(BaseClient):
) -> callable:
"""Decorator for handling callback queries.
This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`CallbackQueryHandler`.
Parameters:
filters (:obj:`Filters`):

View File

@ -32,7 +32,7 @@ class OnDeletedMessages(BaseClient):
) -> callable:
"""Decorator for handling deleted messages.
This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`DeletedMessagesHandler`.
Parameters:
filters (:obj:`Filters`):

View File

@ -25,7 +25,7 @@ class OnDisconnect(BaseClient):
def on_disconnect(self=None) -> callable:
"""Decorator for handling disconnections.
This does the same thing as :meth:`add_handler` using the :class:`DisconnectHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`DisconnectHandler`.
"""
def decorator(func: callable) -> Handler:

View File

@ -32,7 +32,7 @@ class OnInlineQuery(BaseClient):
) -> callable:
"""Decorator for handling inline queries.
This does the same thing as :meth:`add_handler` using the :class:`InlineQueryHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`InlineQueryHandler`.
Parameters:
filters (:obj:`Filters <pyrogram.Filters>`):

View File

@ -32,7 +32,7 @@ class OnMessage(BaseClient):
) -> callable:
"""Decorator for handling messages.
This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`MessageHandler`.
Parameters:
filters (:obj:`Filters`):

View File

@ -32,10 +32,10 @@ class OnPoll(BaseClient):
) -> callable:
"""Decorator for handling poll updates.
This does the same thing as :meth:`add_handler` using the :class:`PollHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`PollHandler`.
Parameters:
filters (:obj:`Filters <pyrogram.Filters>`):
filters (:obj:`Filters`):
Pass one or more filters to allow only a subset of polls to be passed
in your function.

View File

@ -30,7 +30,7 @@ class OnRawUpdate(BaseClient):
) -> callable:
"""Decorator for handling raw updates.
This does the same thing as :meth:`add_handler` using the :class:`RawUpdateHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`RawUpdateHandler`.
Parameters:
group (``int``, *optional*):

View File

@ -31,7 +31,7 @@ class OnUserStatus(BaseClient):
group: int = 0
) -> callable:
"""Decorator for handling user status updates.
This does the same thing as :meth:`add_handler` using the :class:`UserStatusHandler`.
This does the same thing as :meth:`~Client.add_handler` using the :obj:`UserStatusHandler`.
Parameters:
filters (:obj:`Filters`):

View File

@ -28,6 +28,7 @@ from .get_history_count import GetHistoryCount
from .get_messages import GetMessages
from .iter_history import IterHistory
from .retract_vote import RetractVote
from .send_animated_sticker import SendAnimatedSticker
from .send_animation import SendAnimation
from .send_audio import SendAudio
from .send_cached_media import SendCachedMedia
@ -78,6 +79,7 @@ class Messages(
DownloadMedia,
IterHistory,
SendCachedMedia,
GetHistoryCount
GetHistoryCount,
SendAnimatedSticker
):
pass

View File

@ -17,10 +17,13 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import asyncio
import binascii
import struct
from typing import Union
import pyrogram
from pyrogram.client.ext import BaseClient
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FileIdInvalid
class DownloadMedia(BaseClient):
@ -74,74 +77,98 @@ class DownloadMedia(BaseClient):
Returns:
``str`` | ``None``: On success, the absolute path of the downloaded file is returned, otherwise, in case
the download failed or was deliberately stopped with :meth:`stop_transmission`, None is returned.
the download failed or was deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
``ValueError`` if the message doesn't contain any downloadable media
"""
error_message = "This message doesn't contain any downloadable media"
available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note")
file_size = None
mime_type = None
date = None
if isinstance(message, pyrogram.Message):
if message.photo:
media = pyrogram.Document(
file_id=message.photo.sizes[-1].file_id,
file_size=message.photo.sizes[-1].file_size,
mime_type="",
date=message.photo.date,
client=self
)
elif message.audio:
media = message.audio
elif message.document:
media = message.document
elif message.video:
media = message.video
elif message.voice:
media = message.voice
elif message.video_note:
media = message.video_note
elif message.sticker:
media = message.sticker
elif message.animation:
media = message.animation
for kind in available_media:
media = getattr(message, kind, None)
if media is not None:
break
else:
raise ValueError(error_message)
elif isinstance(message, (
pyrogram.Photo,
pyrogram.PhotoSize,
pyrogram.Audio,
pyrogram.Document,
pyrogram.Video,
pyrogram.Voice,
pyrogram.VideoNote,
pyrogram.Sticker,
pyrogram.Animation
)):
if isinstance(message, pyrogram.Photo):
media = pyrogram.Document(
file_id=message.sizes[-1].file_id,
file_size=message.sizes[-1].file_size,
mime_type="",
date=message.date,
client=self
else:
media = message
if isinstance(media, str):
file_id_str = media
else:
file_id_str = media.file_id
file_name = getattr(media, "file_name", "")
file_size = getattr(media, "file_size", None)
mime_type = getattr(media, "mime_type", None)
date = getattr(media, "date", None)
data = self.FileData(
file_name=file_name,
file_size=file_size,
mime_type=mime_type,
date=date
)
def get_existing_attributes() -> dict:
return dict(filter(lambda x: x[1] is not None, data._asdict().items()))
try:
decoded = utils.decode(file_id_str)
media_type = decoded[0]
if media_type == 1:
unpacked = struct.unpack("<iiqqib", decoded)
dc_id, peer_id, volume_id, local_id, is_big = unpacked[1:]
data = self.FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
peer_id=peer_id,
volume_id=volume_id,
local_id=local_id,
is_big=bool(is_big)
)
elif media_type in (0, 2, 14):
unpacked = struct.unpack("<iiqqc", decoded)
dc_id, file_id, access_hash, thumb_size = unpacked[1:]
data = self.FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
file_id=file_id,
access_hash=access_hash,
thumb_size=thumb_size.decode()
)
elif media_type in (3, 4, 5, 8, 9, 10, 13):
unpacked = struct.unpack("<iiqq", decoded)
dc_id, file_id, access_hash = unpacked[1:]
data = self.FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
file_id=file_id,
access_hash=access_hash
)
else:
media = message
elif isinstance(message, str):
media = pyrogram.Document(
file_id=message,
file_size=0,
mime_type="",
client=self
)
else:
raise ValueError(error_message)
raise ValueError("Unknown media type: {}".format(file_id_str))
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
done = asyncio.Event()
path = [None]
self.download_queue.put_nowait((media, file_name, done, progress, progress_args, path))
self.download_queue.put_nowait((data, file_name, done, progress, progress_args, path))
if block:
await done.wait()

View File

@ -16,14 +16,11 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid
from pyrogram.client.ext import BaseClient, utils
from pyrogram.client.types import (
InputMediaPhoto, InputMediaVideo, InputMediaAudio,
@ -94,28 +91,7 @@ class EditMessageMedia(BaseClient):
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 2:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(media.media, 2)
if isinstance(media, InputMediaVideo):
if os.path.exists(media.media):
@ -153,28 +129,7 @@ class EditMessageMedia(BaseClient):
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 4:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(media.media, 4)
if isinstance(media, InputMediaAudio):
if os.path.exists(media.media):
@ -211,28 +166,7 @@ class EditMessageMedia(BaseClient):
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 9:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(media.media, 9)
if isinstance(media, InputMediaAnimation):
if os.path.exists(media.media):
@ -271,28 +205,7 @@ class EditMessageMedia(BaseClient):
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 10:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(media.media, 10)
if isinstance(media, InputMediaDocument):
if os.path.exists(media.media):
@ -324,28 +237,7 @@ class EditMessageMedia(BaseClient):
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] not in (5, 10):
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(media.media, 5)
r = await self.send(
functions.messages.EditMessage(

View File

@ -41,7 +41,7 @@ class GetHistory(BaseClient):
"""Retrieve a chunk of the history of a chat.
You can get up to 100 messages at once.
For a more convenient way of getting a chat history see :meth:`iter_history`.
For a more convenient way of getting a chat history see :meth:`~Client.iter_history`.
Parameters:
chat_id (``int`` | ``str``):

View File

@ -37,8 +37,9 @@ class IterHistory(BaseClient):
) -> Optional[AsyncGenerator["pyrogram.Message", None]]:
"""Iterate through a chat history sequentially.
This convenience method does the same as repeatedly calling :meth:`get_history` in a loop, thus saving you from
the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a single call.
This convenience method does the same as repeatedly calling :meth:`~Client.get_history` in a loop, thus saving
you from the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a
single call.
Parameters:
chat_id (``int`` | ``str``):

View File

@ -0,0 +1,141 @@
# 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/>.
import os
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendAnimatedSticker(BaseClient):
def send_animated_sticker(
self,
chat_id: Union[int, str],
animated_sticker: str,
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup: Union[
"pyrogram.InlineKeyboardMarkup",
"pyrogram.ReplyKeyboardMarkup",
"pyrogram.ReplyKeyboardRemove",
"pyrogram.ForceReply"
] = None,
progress: callable = None,
progress_args: tuple = ()
) -> Union["pyrogram.Message", None]:
"""Send .tgs animated stickers.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
animated_sticker (``str``):
Animated sticker to send.
Pass a file_id as string to send a animated sticker that exists on the Telegram servers,
pass an HTTP URL as a string for Telegram to get a .webp animated sticker file from the Internet, or
pass a file path as string to upload a new animated sticker that exists on your local machine.
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
reply_to_message_id (``int``, *optional*):
If the message is a reply, ID of the original message.
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
Additional interface options. An object for an inline keyboard, custom reply keyboard,
instructions to remove reply keyboard or to force a reply from the user.
progress (``callable``, *optional*):
Pass a callback function to view the upload progress.
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
below for a detailed description).
progress_args (``tuple``, *optional*):
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass
a chat_id and a message_id in order to edit a message with the updated progress.
Other Parameters:
client (:obj:`Client`):
The Client itself, useful when you want to call other API methods inside the callback function.
current (``int``):
The amount of bytes uploaded so far.
total (``int``):
The size of the file.
*args (``tuple``, *optional*):
Extra custom arguments as defined in the *progress_args* parameter.
You can either keep *\*args* or add every single extra argument in your function signature.
Returns:
:obj:`Message` | ``None``: On success, the sent animated sticker message is returned, otherwise, in case the
upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
"""
file = None
try:
if os.path.exists(animated_sticker):
file = self.save_file(animated_sticker, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=self.guess_mime_type(animated_sticker) or "application/x-tgsticker",
file=file,
attributes=[
types.DocumentAttributeFilename(file_name=os.path.basename(animated_sticker))
]
)
elif animated_sticker.startswith("http"):
media = types.InputMediaDocumentExternal(
url=animated_sticker
)
else:
media = utils.get_input_media_from_file_id(animated_sticker, 5)
while True:
try:
r = self.send(
functions.messages.SendMedia(
peer=self.resolve_peer(chat_id),
media=media,
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),
reply_markup=reply_markup.write() if reply_markup else None,
message=""
)
)
except FilePartMissing as e:
self.save_file(animated_sticker, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
return pyrogram.Message._parse(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
)
except BaseClient.StopTransmission:
return None

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendAnimation(BaseClient):
@ -121,7 +119,7 @@ class SendAnimation(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -153,28 +151,7 @@ class SendAnimation(BaseClient):
url=animation
)
else:
try:
decoded = utils.decode(animation)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 10:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(animation, 10)
while True:
try:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendAudio(BaseClient):
@ -122,7 +120,7 @@ class SendAudio(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -152,28 +150,7 @@ class SendAudio(BaseClient):
url=audio
)
else:
try:
decoded = utils.decode(audio)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 9:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(audio, 9)
while True:
try:

View File

@ -16,13 +16,10 @@
# 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 binascii
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid
from pyrogram.client.ext import BaseClient, utils
@ -84,39 +81,10 @@ class SendCachedMedia(BaseClient):
"""
style = self.html if parse_mode.lower() == "html" else self.markdown
try:
decoded = utils.decode(file_id)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if not media_type:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
if media_type == "photo":
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
else:
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
r = await self.send(
functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id),
media=media,
media=utils.get_input_media_from_file_id(file_id),
silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(),

View File

@ -16,11 +16,11 @@
# 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 json
from typing import Union
from pyrogram.api import functions, types
from pyrogram.client.ext import BaseClient
import json
class ChatAction:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendDocument(BaseClient):
@ -108,7 +106,7 @@ class SendDocument(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -133,28 +131,7 @@ class SendDocument(BaseClient):
url=document
)
else:
try:
decoded = utils.decode(document)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] not in (5, 10):
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(document, 5)
while True:
try:

View File

@ -16,17 +16,15 @@
# 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 binascii
import asyncio
import logging
import os
import struct
from typing import Union, List
import asyncio
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FloodWait
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FloodWait
log = logging.getLogger(__name__)
@ -96,28 +94,7 @@ class SendMediaGroup(BaseClient):
)
)
else:
try:
decoded = utils.decode(i.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 2:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(i.media, 2)
elif isinstance(i, pyrogram.InputMediaVideo):
if os.path.exists(i.media):
while True:
@ -155,28 +132,7 @@ class SendMediaGroup(BaseClient):
)
)
else:
try:
decoded = utils.decode(i.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 4:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(i.media, 4)
multi_media.append(
types.InputSingleMedia(

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendPhoto(BaseClient):
@ -108,7 +106,7 @@ class SendPhoto(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent photo message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -129,29 +127,7 @@ class SendPhoto(BaseClient):
ttl_seconds=ttl_seconds
)
else:
try:
decoded = utils.decode(photo)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 2:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
),
ttl_seconds=ttl_seconds
)
media = utils.get_input_media_from_file_id(photo, 2)
while True:
try:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendSticker(BaseClient):
@ -93,7 +91,7 @@ class SendSticker(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
"""
@ -114,28 +112,7 @@ class SendSticker(BaseClient):
url=sticker
)
else:
try:
decoded = utils.decode(sticker)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 8:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(sticker, 8)
while True:
try:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendVideo(BaseClient):
@ -125,7 +123,7 @@ class SendVideo(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent video message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -156,28 +154,7 @@ class SendVideo(BaseClient):
url=video
)
else:
try:
decoded = utils.decode(video)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 4:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(video, 4)
while True:
try:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendVideoNote(BaseClient):
@ -108,7 +106,7 @@ class SendVideoNote(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the
pload is deliberately stopped with :meth:`stop_transmission`, None is returned.
pload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -133,28 +131,7 @@ class SendVideoNote(BaseClient):
]
)
else:
try:
decoded = utils.decode(video_note)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 13:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(video_note, 13)
while True:
try:

View File

@ -16,15 +16,13 @@
# 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 binascii
import os
import struct
from typing import Union
import pyrogram
from pyrogram.api import functions, types
from pyrogram.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
from pyrogram.errors import FilePartMissing
class SendVoice(BaseClient):
@ -106,7 +104,7 @@ class SendVoice(BaseClient):
Returns:
:obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload
is deliberately stopped with :meth:`stop_transmission`, None is returned.
is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned.
Raises:
RPCError: In case of a Telegram RPC error.
@ -132,28 +130,7 @@ class SendVoice(BaseClient):
url=voice
)
else:
try:
decoded = utils.decode(voice)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 3:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3],
file_reference=b""
)
)
media = utils.get_input_media_from_file_id(voice, 3)
while True:
try:

View File

@ -16,22 +16,26 @@
# 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 .delete_user_profile_photos import DeleteUserProfilePhotos
from .delete_profile_photos import DeleteProfilePhotos
from .get_me import GetMe
from .get_user_profile_photos import GetUserProfilePhotos
from .get_user_profile_photos_count import GetUserProfilePhotosCount
from .get_profile_photos import GetProfilePhotos
from .get_profile_photos_count import GetProfilePhotosCount
from .get_user_dc import GetUserDC
from .get_users import GetUsers
from .set_user_profile_photo import SetUserProfilePhoto
from .iter_profile_photos import IterProfilePhotos
from .set_profile_photo import SetProfilePhoto
from .update_username import UpdateUsername
class Users(
GetUserProfilePhotos,
SetUserProfilePhoto,
DeleteUserProfilePhotos,
GetProfilePhotos,
SetProfilePhoto,
DeleteProfilePhotos,
GetUsers,
GetMe,
UpdateUsername,
GetUserProfilePhotosCount
GetProfilePhotosCount,
GetUserDC,
IterProfilePhotos
):
pass

View File

@ -24,8 +24,8 @@ from pyrogram.api import functions, types
from ...ext import BaseClient
class DeleteUserProfilePhotos(BaseClient):
async def delete_user_profile_photos(
class DeleteProfilePhotos(BaseClient):
async def delete_profile_photos(
self,
id: Union[str, List[str]]
) -> bool:

View File

@ -0,0 +1,92 @@
# 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
import pyrogram
from pyrogram.api import functions, types
from ...ext import BaseClient
class GetProfilePhotos(BaseClient):
async def get_profile_photos(
self,
chat_id: Union[int, str],
offset: int = 0,
limit: int = 100
) -> "pyrogram.Photos":
"""Get a list of profile pictures for a user or a chat.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
offset (``int``, *optional*):
Sequential number of the first photo to be returned.
By default, all photos are returned.
limit (``int``, *optional*):
Limits the number of photos to be retrieved.
Values between 1100 are accepted. Defaults to 100.
Returns:
:obj:`Photos`: On success, an object containing a list of the profile photos is returned.
Raises:
RPCError: In case of a Telegram RPC error.
"""
peer_id = await self.resolve_peer(chat_id)
if isinstance(peer_id, types.InputPeerUser):
return pyrogram.Photos._parse(
self,
await self.send(
functions.photos.GetUserPhotos(
user_id=peer_id,
offset=offset,
max_id=0,
limit=limit
)
)
)
else:
new_chat_photos = pyrogram.Messages._parse(
self,
await self.send(
functions.messages.Search(
peer=peer_id,
q="",
filter=types.InputMessagesFilterChatPhotos(),
min_date=0,
max_date=0,
offset_id=0,
add_offset=offset,
limit=limit,
max_id=0,
min_id=0,
hash=0
)
)
)
return pyrogram.Photos(
total_count=new_chat_photos.total_count,
photos=[m.new_chat_photo for m in new_chat_photos.messages][:limit]
)

View File

@ -18,16 +18,15 @@
from typing import Union
from pyrogram.api import functions, types
from ...ext import BaseClient
class GetUserProfilePhotosCount(BaseClient):
async def get_user_profile_photos_count(self, user_id: Union[int, str]) -> int:
class GetProfilePhotosCount(BaseClient):
async def get_profile_photos_count(self, chat_id: Union[int, str]) -> int:
"""Get the total count of profile pictures for a user.
Parameters:
user_id (``int`` | ``str``):
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
@ -39,16 +38,4 @@ class GetUserProfilePhotosCount(BaseClient):
RPCError: In case of a Telegram RPC error.
"""
r = await self.send(
functions.photos.GetUserPhotos(
user_id=await self.resolve_peer(user_id),
offset=0,
max_id=0,
limit=1
)
)
if isinstance(r, types.photos.Photos):
return len(r.photos)
else:
return r.count
return await self.get_profile_photos(chat_id, limit=1).total_count

View File

@ -18,19 +18,13 @@
from typing import Union
import pyrogram
from pyrogram.api import functions
from pyrogram.api import functions, types
from ...ext import BaseClient
class GetUserProfilePhotos(BaseClient):
async def get_user_profile_photos(
self,
user_id: Union[int, str],
offset: int = 0,
limit: int = 100
) -> "pyrogram.UserProfilePhotos":
"""Get a list of profile pictures for a user.
class GetUserDC(BaseClient):
async def get_user_dc(self, user_id: Union[int, str]) -> Union[int, None]:
"""Get the assigned data center (DC) of a user.
Parameters:
user_id (``int`` | ``str``):
@ -38,28 +32,20 @@ class GetUserProfilePhotos(BaseClient):
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
offset (``int``, *optional*):
Sequential number of the first photo to be returned.
By default, all photos are returned.
limit (``int``, *optional*):
Limits the number of photos to be retrieved.
Values between 1100 are accepted. Defaults to 100.
Returns:
:obj:`UserProfilePhotos`: On success, an object containing a list of the profile photos is returned.
``int`` | ``None``: The DC identifier as integer, or None in case it wasn't possible to get it.
Raises:
RPCError: In case of a Telegram RPC error.
"""
return pyrogram.UserProfilePhotos._parse(
self,
await self.send(
functions.photos.GetUserPhotos(
user_id=await self.resolve_peer(user_id),
offset=offset,
max_id=0,
limit=limit
)
)
)
r = await self.send(functions.users.GetUsers(id=[await self.resolve_peer(user_id)]))
if r:
r = r[0]
if r.photo:
if isinstance(r.photo, types.UserProfilePhoto):
return r.photo.dc_id
return None

View File

@ -0,0 +1,82 @@
# 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, Generator
from async_generator import async_generator, yield_
import pyrogram
from ...ext import BaseClient
class IterProfilePhotos(BaseClient):
@async_generator
async def iter_profile_photos(
self,
chat_id: Union[int, str],
offset: int = 0,
limit: int = 0,
) -> Generator["pyrogram.Photo", None, None]:
"""Iterate through a chat or a user profile photos sequentially.
This convenience method does the same as repeatedly calling :meth:`~Client.get_profile_photos` in a loop, thus
saving you from the hassle of setting up boilerplate code. It is useful for getting all the profile photos with
a single call.
Parameters:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
limit (``int``, *optional*):
Limits the number of profile photos to be retrieved.
By default, no limit is applied and all profile photos are returned.
offset (``int``, *optional*):
Sequential number of the first profile photo to be returned.
Returns:
``Generator``: A generator yielding :obj:`Photo` objects.
Raises:
RPCError: In case of a Telegram RPC error.
"""
current = 0
total = limit or (1 << 31)
limit = min(100, total)
while True:
photos = self.get_profile_photos(
chat_id=chat_id,
offset=offset,
limit=limit
).photos
if not photos:
return
offset += len(photos)
for photo in photos:
await yield_(photo)
current += 1
if current >= total:
return

View File

@ -20,8 +20,8 @@ from pyrogram.api import functions
from ...ext import BaseClient
class SetUserProfilePhoto(BaseClient):
async def set_user_profile_photo(
class SetProfilePhoto(BaseClient):
async def set_profile_photo(
self,
photo: str
) -> bool:

View File

@ -31,7 +31,7 @@ class UpdateUsername(BaseClient):
This method only works for users, not bots. Bot usernames must be changed via Bot Support or by recreating
them from scratch using BotFather. To update a channel or supergroup username you can use
:meth:`update_chat_username`.
:meth:`~Client.update_chat_username`.
Parameters:
username (``str`` | ``None``):

View File

@ -92,7 +92,7 @@ class InlineQuery(PyrogramType, Update):
switch_pm_text: str = "",
switch_pm_parameter: str = ""
):
"""Bound method *answer* of :obj:`InlineQuery <pyrogram.InlineQuery>`.
"""Bound method *answer* of :obj:`InlineQuery`.
Use this method as a shortcut for:
@ -109,7 +109,7 @@ class InlineQuery(PyrogramType, Update):
inline_query.answer([...])
Parameters:
results (List of :obj:`InlineQueryResult <pyrogram.InlineQueryResult>`):
results (List of :obj:`InlineQueryResult`):
A list of results for the inline query.
cache_time (``int``, *optional*):

View File

@ -34,10 +34,10 @@ class InlineQueryResultArticle(InlineQueryResult):
title (``str``):
Title for the result.
input_message_content (:obj:`InputMessageContent <pyrogram.InputMessageContent>`):
input_message_content (:obj:`InputMessageContent`):
Content of the message to be sent.
reply_markup (:obj:`InlineKeyboardMarkup <pyrogram.InlineKeyboardMarkup>`, *optional*):
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
Inline keyboard attached to the message.
url (``str``, *optional*):

View File

@ -50,10 +50,10 @@ class InlineQueryResultAudio(PyrogramType):
audio_duration (``int`` ``32-bit``, optional):
Audio duration in seconds.
reply_markup (:obj:`InlineKeyboardMarkup <pyrogram.types.InlineKeyboardMarkup>`, optional):
reply_markup (:obj:`InlineKeyboardMarkup`, optional):
Inline keyboard attached to the message.
input_message_content (:obj:`InputMessageContent <pyrogram.types.InputMessageContent>`, optional):
input_message_content (:obj:`InputMessageContent`, optional):
Content of the message to be sent instead of the audio.
"""

View File

@ -47,10 +47,10 @@ class InlineQueryResultCachedDocument(PyrogramType):
parse_mode (``str``, optional):
Send Markdown or HTML, if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in the media caption.
reply_markup (:obj:`InlineKeyboardMarkup <pyrogram.types.InlineKeyboardMarkup>`, optional):
reply_markup (:obj:`InlineKeyboardMarkup`, optional):
Inline keyboard attached to the message.
input_message_content (:obj:`InputMessageContent <pyrogram.types.InputMessageContent>`, optional):
input_message_content (:obj:`InputMessageContent`, optional):
Content of the message to be sent instead of the file.
"""

Some files were not shown because too many files have changed in this diff Show More