# Pyrogram - Telegram MTProto API Client Library for Python # Copyright (C) 2017-2021 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 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=name, title_markup="=" * len(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(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 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_history get_history_count read_history iter_history send_poll vote_poll stop_poll retract_vote send_dice search_messages search_global download_media get_discussion_message """, 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 iter_chat_members get_dialogs iter_dialogs get_dialogs_count update_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 """, users=""" Users get_me get_users get_profile_photos get_profile_photos_count iter_profile_photos set_profile_photo delete_profile_photos update_username update_profile block_user unblock_user get_common_chats """, 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_members get_chat_invite_link_members_count get_chat_admin_invite_links get_chat_admin_invite_links_count get_chat_admins_with_invite_links delete_chat_admin_invite_links approve_chat_join_request decline_chat_join_request """, 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 """, 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 send resolve_peer save_file """ ) 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"] 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 ChatInviteLink ChatAdminWithInviteLinks ChatEvent ChatEventFilter ChatMemberUpdated Dialog Restriction """, messages_media=""" Messages & Media Message MessageEntity Photo Thumbnail Audio Document Animation Video Voice VideoNote Contact Location Venue Sticker Game WebPage Poll PollOption Dice VoiceChatScheduled VoiceChatStarted VoiceChatEnded VoiceChatMembersInvited """, bots_keyboard=""" Bots & Keyboards ReplyKeyboardMarkup KeyboardButton ReplyKeyboardRemove InlineKeyboardMarkup InlineKeyboardButton LoginUrl ForceReply CallbackQuery GameHighScore CallbackGame BotCommand """, input_media=""" Input Media InputMedia InputMediaPhoto InputMediaVideo InputMediaAudio InputMediaAnimation InputMediaDocument InputPhoneContact """, inline_mode=""" Inline Mode InlineQuery InlineQueryResult InlineQueryResultArticle InlineQueryResultPhoto InlineQueryResultAnimation 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 """, 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.iter_members Chat.add_members Chat.join Chat.leave Chat.mark_unread Chat.set_protected_content """, 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 """ ) 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()