# Pyrogram - Telegram MTProto API Client Library for Python # Copyright (C) 2017-present Dan # # 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 . import ast import os import re import shutil HOME = "compiler/docs" DESTINATION = "docs/source/telegram" PYROGRAM_API_DEST = "docs/source/api" FUNCTIONS_PATH = "pyrogram/raw/functions" TYPES_PATH = "pyrogram/raw/types" BASE_PATH = "pyrogram/raw/base" FUNCTIONS_BASE = "functions" TYPES_BASE = "types" BASE_BASE = "base" 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): all_entities = {} def build(path, level=0): last = path.split("/")[-1] for i in os.listdir(path): try: if not i.startswith("__"): build("/".join([path, i]), level=level + 1) except NotADirectoryError: with open(path + "/" + i, encoding="utf-8") as f: p = ast.parse(f.read()) for node in ast.walk(p): if isinstance(node, ast.ClassDef): name = node.name break else: continue full_path = os.path.basename(path) + "/" + snek(name).replace("_", "-") + ".rst" if level: full_path = base + "/" + full_path namespace = path.split("/")[-1] if namespace in ["base", "types", "functions"]: namespace = "" full_name = f"{(namespace + '.') if namespace else ''}{name}" os.makedirs(os.path.dirname(DESTINATION + "/" + full_path), exist_ok=True) with open(DESTINATION + "/" + full_path, "w", encoding="utf-8") as f: f.write( page_template.format( title=full_name, title_markup="=" * len(full_name), full_class_path="pyrogram.raw.{}".format( ".".join(full_path.split("/")[:-1]) + "." + name ) ) ) if last not in all_entities: all_entities[last] = [] all_entities[last].append(name) build(source_path) for k, v in sorted(all_entities.items()): v = sorted(v) entities = [] for i in v: entities.append(f'{i} <{snek(i).replace("_", "-")}>') if k != base: inner_path = base + "/" + k + "/index" + ".rst" module = "pyrogram.raw.{}.{}".format(base, k) else: for i in sorted(list(all_entities), reverse=True): if i != base: entities.insert(0, "{0}/index".format(i)) inner_path = base + "/index" + ".rst" module = "pyrogram.raw.{}".format(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( title=k.title(), title_markup="=" * len(k), module=module, entities="\n ".join(entities) ) ) f.write("\n") def pyrogram_api(): def get_title_list(s: str) -> list: return [i.strip() for i in [j.strip() for j in s.split("\n") if j] if i] # Methods categories = dict( utilities=""" Utilities start stop run restart add_handler remove_handler stop_transmission export_session_string set_parse_mode """, messages=""" Messages send_message forward_messages copy_message copy_media_group 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_reaction edit_message_text edit_message_caption edit_message_media edit_message_reply_markup edit_inline_text edit_inline_caption edit_inline_media edit_inline_reply_markup send_chat_action delete_messages get_messages get_media_group get_chat_history get_chat_history_count read_chat_history send_poll vote_poll stop_poll retract_vote send_dice search_messages search_messages_count search_global search_global_count download_media stream_media get_discussion_message get_discussion_replies get_discussion_replies_count get_custom_emoji_stickers """, chats=""" Chats join_chat leave_chat ban_chat_member unban_chat_member restrict_chat_member promote_chat_member set_administrator_title set_chat_photo delete_chat_photo set_chat_title set_chat_description set_chat_permissions pin_chat_message unpin_chat_message unpin_all_chat_messages get_chat get_chat_member get_chat_members get_chat_members_count get_dialogs get_dialogs_count set_chat_username get_nearby_chats archive_chats unarchive_chats add_chat_members create_channel create_group create_supergroup delete_channel delete_supergroup delete_user_history set_slow_mode mark_chat_unread get_chat_event_log get_chat_online_count get_send_as_chats set_send_as_chat set_chat_protected_content close_forum_topic create_forum_topic delete_forum_topic edit_forum_topic get_forum_topics get_forum_topics_by_id update_color update_chat_notifications toggle_forum_topics delete_folder export_folder_link get_folders update_folder get_similar_channels """, users=""" Users get_me get_users get_chat_photos get_chat_photos_count set_profile_photo delete_profile_photos set_username update_profile block_user unblock_user get_common_chats get_default_emoji_statuses set_emoji_status """, invite_links=""" Invite Links get_chat_invite_link export_chat_invite_link create_chat_invite_link edit_chat_invite_link revoke_chat_invite_link delete_chat_invite_link get_chat_invite_link_joiners get_chat_invite_link_joiners_count get_chat_admin_invite_links get_chat_admin_invite_links_count get_chat_admins_with_invite_links get_chat_join_requests delete_chat_admin_invite_links approve_chat_join_request approve_all_chat_join_requests decline_chat_join_request decline_all_chat_join_requests """, contacts=""" Contacts add_contact delete_contacts import_contacts get_contacts get_contacts_count """, password=""" Password enable_cloud_password change_cloud_password remove_cloud_password """, bots=""" Bots get_inline_bot_results send_inline_bot_result answer_callback_query answer_inline_query request_callback_answer send_game set_game_score get_game_high_scores set_bot_commands get_bot_commands delete_bot_commands set_bot_default_privileges get_bot_default_privileges set_chat_menu_button get_chat_menu_button answer_web_app_query """, authorization=""" Authorization connect disconnect initialize terminate send_code resend_code sign_in sign_in_bot sign_up get_password_hint check_password send_recovery_code recover_password accept_terms_of_service log_out """, advanced=""" Advanced invoke resolve_peer save_file """, stories=""" Stories delete_stories edit_story export_story_link get_all_stories get_stories_archive increment_story_views read_stories send_story pin_stories hide_stories can_send_story get_pinned_stories copy_story forward_story """, premium=""" Premium apply_boost get_boosts get_boosts_status """ ) root = PYROGRAM_API_DEST + "/methods" shutil.rmtree(root, ignore_errors=True) os.mkdir(root) with open(HOME + "/template/methods.rst") as f: template = f.read() with open(root + "/index.rst", "w") as f: fmt_keys = {} for k, v in categories.items(): name, *methods = get_title_list(v) fmt_keys.update({k: "\n ".join("{0} <{0}>".format(m) for m in methods)}) for method in methods: with open(root + "/{}.rst".format(method), "w") as f2: title = "{}()".format(method) f2.write(title + "\n" + "=" * len(title) + "\n\n") f2.write(".. automethod:: pyrogram.Client.{}()".format(method)) functions = ["idle", "compose"] for func in functions: with open(root + "/{}.rst".format(func), "w") as f2: title = "{}()".format(func) f2.write(title + "\n" + "=" * len(title) + "\n\n") f2.write(".. autofunction:: pyrogram.{}()".format(func)) f.write(template.format(**fmt_keys)) # Types categories = dict( users_chats=""" Users & Chats User Chat ChatPreview ChatPhoto ChatMember ChatPermissions ChatPrivileges ChatInviteLink ChatAdminWithInviteLinks ChatEvent ChatEventFilter ChatMemberUpdated ChatJoinRequest ChatJoiner Dialog Restriction EmojiStatus Folder ChatColor """, messages_media=""" Messages & Media Message MessageEntity Photo Thumbnail Audio Document Animation Video Voice VideoNote Contact Location Venue Sticker Game WebPage Poll PollOption Dice Reaction VideoChatScheduled VideoChatStarted VideoChatEnded VideoChatMembersInvited WebAppData MessageReactions ChatReactions Story StoryViews MyBoost BoostsStatus Giveaway GiftCode """, bot_keyboards=""" Bot keyboards ReplyKeyboardMarkup KeyboardButton ReplyKeyboardRemove InlineKeyboardMarkup InlineKeyboardButton LoginUrl ForceReply CallbackQuery GameHighScore CallbackGame WebAppInfo MenuButton MenuButtonCommands MenuButtonWebApp MenuButtonDefault SentWebAppMessage ForumTopic RequestChannelInfo RequestChatInfo RequestUserInfo RequestPollInfo """, bot_commands=""" Bot commands BotCommand BotCommandScope BotCommandScopeDefault BotCommandScopeAllPrivateChats BotCommandScopeAllGroupChats BotCommandScopeAllChatAdministrators BotCommandScopeChat BotCommandScopeChatAdministrators BotCommandScopeChatMember """, input_media=""" Input Media InputMedia InputMediaPhoto InputMediaVideo InputMediaAudio InputMediaAnimation InputMediaDocument InputPhoneContact """, inline_mode=""" Inline Mode InlineQuery InlineQueryResult InlineQueryResultCachedAudio InlineQueryResultCachedDocument InlineQueryResultCachedAnimation InlineQueryResultCachedPhoto InlineQueryResultCachedSticker InlineQueryResultCachedVideo InlineQueryResultCachedVoice InlineQueryResultArticle InlineQueryResultAudio InlineQueryResultContact InlineQueryResultDocument InlineQueryResultAnimation InlineQueryResultLocation InlineQueryResultPhoto InlineQueryResultVenue InlineQueryResultVideo InlineQueryResultVoice ChosenInlineResult """, input_message_content=""" InputMessageContent InputMessageContent InputTextMessageContent """, authorization=""" Authorization SentCode TermsOfService """ ) root = PYROGRAM_API_DEST + "/types" shutil.rmtree(root, ignore_errors=True) os.mkdir(root) with open(HOME + "/template/types.rst") as f: template = f.read() with open(root + "/index.rst", "w") as f: fmt_keys = {} for k, v in categories.items(): name, *types = get_title_list(v) fmt_keys.update({k: "\n ".join(types)}) # noinspection PyShadowingBuiltins for type in types: with open(root + "/{}.rst".format(type), "w") as f2: title = "{}".format(type) f2.write(title + "\n" + "=" * len(title) + "\n\n") f2.write(".. autoclass:: pyrogram.types.{}()\n".format(type)) f.write(template.format(**fmt_keys)) # Bound Methods categories = dict( message=""" Message Message.click Message.delete Message.download Message.forward Message.copy Message.pin Message.unpin Message.edit Message.edit_text Message.edit_caption Message.edit_media Message.edit_reply_markup Message.reply Message.reply_text Message.reply_animation Message.reply_audio Message.reply_cached_media Message.reply_chat_action Message.reply_contact Message.reply_document Message.reply_game Message.reply_inline_bot_result Message.reply_location Message.reply_media_group Message.reply_photo Message.reply_poll Message.reply_sticker Message.reply_venue Message.reply_video Message.reply_video_note Message.reply_voice Message.get_media_group Message.react """, chat=""" Chat Chat.archive Chat.unarchive Chat.set_title Chat.set_description Chat.set_photo Chat.ban_member Chat.unban_member Chat.restrict_member Chat.promote_member Chat.get_member Chat.get_members Chat.add_members Chat.join Chat.leave Chat.mark_unread Chat.set_protected_content Chat.unpin_all_messages Chat.mute Chat.unmute """, user=""" User User.archive User.unarchive User.block User.unblock """, callback_query=""" Callback Query CallbackQuery.answer CallbackQuery.edit_message_text CallbackQuery.edit_message_caption CallbackQuery.edit_message_media CallbackQuery.edit_message_reply_markup """, inline_query=""" InlineQuery InlineQuery.answer """, chat_join_request=""" ChatJoinRequest ChatJoinRequest.approve ChatJoinRequest.decline """, story=""" Story Story.reply_text Story.reply_animation Story.reply_audio Story.reply_cached_media Story.reply_media_group Story.reply_photo Story.reply_sticker Story.reply_video Story.reply_video_note Story.reply_voice Story.delete Story.edit Story.edit_caption Story.edit_privacy Story.export_link Story.react Story.copy Story.forward Story.read """, folder=""" Folder Folder.delete Folder.update Folder.include_chat Folder.exclude_chat Folder.pin_chat Folder.remove_chat Folder.export_link """ ) root = PYROGRAM_API_DEST + "/bound-methods" shutil.rmtree(root, ignore_errors=True) os.mkdir(root) with open(HOME + "/template/bound-methods.rst") as f: template = f.read() with open(root + "/index.rst", "w") as f: fmt_keys = {} for k, v in categories.items(): name, *bound_methods = get_title_list(v) fmt_keys.update({"{}_hlist".format(k): "\n ".join("- :meth:`~{}`".format(bm) for bm in bound_methods)}) fmt_keys.update( {"{}_toctree".format(k): "\n ".join("{} <{}>".format(bm.split(".")[1], bm) for bm in bound_methods)}) # noinspection PyShadowingBuiltins for bm in bound_methods: with open(root + "/{}.rst".format(bm), "w") as f2: title = "{}()".format(bm) f2.write(title + "\n" + "=" * len(title) + "\n\n") f2.write(".. automethod:: pyrogram.types.{}()".format(bm)) f.write(template.format(**fmt_keys)) 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() with open(HOME + "/template/toctree.txt", encoding="utf-8") as f: toctree = f.read() generate(TYPES_PATH, TYPES_BASE) generate(FUNCTIONS_PATH, FUNCTIONS_BASE) generate(BASE_PATH, BASE_BASE) pyrogram_api() if "__main__" == __name__: FUNCTIONS_PATH = "../../pyrogram/raw/functions" TYPES_PATH = "../../pyrogram/raw/types" BASE_PATH = "../../pyrogram/raw/base" HOME = "." DESTINATION = "../../docs/source/telegram" PYROGRAM_API_DEST = "../../docs/source/api" start()