Conversation
#115) This change introduces a new documentation generator for raw MTProto functions and types. It adds: - A visual, recursive parameter tree showing nesting depth. - TL schema signatures for every function and type. - Fully inlined, working asynchronous code examples using `app.invoke`. - Clickable type references in the parameter tree using Sphinx `:obj:` directives. The `compiler/docs/compiler.py` has been updated to integrate these new sections into the generated RST files.
Signed-off-by: 5hojib <yesiamshojib@gmail.com>
This change introduces the `send_message_draft` method to the `Messages` class, allowing bots to stream partial messages to users for an AI-like typing experience. - Updated `ChatAction` enum to include `MESSAGE_DRAFT`. - Added `send_message_draft` method in `pyrogram/methods/messages/send_message_draft.py`. - Correctly mapped the method to MTProto `messages.SetTyping` with `SendMessageTextDraftAction`. - Exported the new method in `pyrogram/methods/messages/__init__.py`. - Generated documentation for the new method.
Signed-off-by: 5hojib <yesiamshojib@gmail.com>
* fix: handle exit code 2 in fetch_mtproto workflow The 'Check for API schema updates' script returns exit code 2 when no updates are detected. GitHub Actions runs bash with 'set -e' by default, causing the step to fail immediately before the exit code can be checked. This change wraps the script execution with 'set +e' and 'set -e' to capture the exit code and handle it according to the intended logic. * fix: handle exit code 2 in fetch_mtproto workflow The 'Check for API schema updates' script returns exit code 2 when no updates are detected. GitHub Actions runs bash with 'set -e' by default, causing the step to fail immediately before the exit code can be checked. This change wraps the script execution with 'set +e' and 'set -e' to capture the exit code and handle it according to the intended logic, ensuring subsequent steps are skipped if no updates are found.
Signed-off-by: 5hojib <yesiamshojib@gmail.com>
Reviewer's GuideAdds a TL schema–driven documentation generator for raw API entities, wires it into the docs build, and introduces a new send_message_draft client method and corresponding enum/chat action wiring, along with a CI robustness tweak for the MTProto schema check. Sequence diagram for the send_message_draft invocation flowsequenceDiagram
actor BotDeveloper
participant Client as Client
participant Utils as UtilsModule
participant Raw as RawAPI
participant Telegram as TelegramServer
BotDeveloper->>Client: send_message_draft(chat_id, draft_id, text, ...)
Client->>Utils: parse_text_entities(client, text, parse_mode, entities)
Utils-->>Client: parsed_text
Client->>Client: resolve_peer(chat_id)
Client->>Raw: build SetTyping(peer, SendMessageTextDraftAction, top_msg_id)
alt business_connection_id is provided
Client->>Raw: InvokeWithBusinessConnection(connection_id, SetTyping(...))
else no business_connection_id
Client->>Raw: invoke(SetTyping(...))
end
Raw->>Telegram: send RPC
Telegram-->>Raw: bool success
Raw-->>Client: bool success
Client-->>BotDeveloper: bool
Class diagram for TLDocGenerator and compiler docs integrationclassDiagram
class TLDocGenerator {
- dict name_to_comb
- dict base_to_constructors
- list~Combinator~ combinators
+ TLDocGenerator(tl_files list~Path~)
- _parse_tl(tl_files list~Path~) list~Combinator~
+ get_tl_signature(name str) str
+ get_full_class_path(name str) str
+ get_type_link(t str) str
+ generate_tree(name str) str
- _generate_tree_recursive(name str, depth int, prefix str, visited set~str~, is_vector_item bool, is_base bool) list~str~
+ get_default_value(arg_name str, arg_type str, depth int, visited set, minimal bool)
+ generate_example(name str, minimal bool) str
}
class Argument {
+ name str
+ type str
}
class Combinator {
+ section str
+ qualname str
+ id str
+ args list~Argument~
+ qualtype str
+ full_line str
}
class CompilerDocsModule {
+ generate_raw(source_path, base, tl_gen TLDocGenerator) None
+ start() None
}
TLDocGenerator *-- Combinator : parses
Combinator *-- Argument : has
CompilerDocsModule ..> TLDocGenerator : uses
Class diagram for SendMessageDraft client method and related raw typesclassDiagram
class Client {
+ invoke(query) any
+ resolve_peer(chat_id) any
+ send_message_draft(chat_id int|str, draft_id int, text str, parse_mode ParseMode, entities list~MessageEntity~, message_thread_id int, business_connection_id str) bool
}
class SendMessageDraft {
+ send_message_draft(chat_id int|str, draft_id int, text str, parse_mode ParseMode, entities list~MessageEntity~, message_thread_id int, business_connection_id str) bool
}
class UtilsModule {
+ parse_text_entities(client Client, text str, parse_mode ParseMode, entities list~MessageEntity~) dict
+ get_input_peer(peer) any
}
class RawFunctionsMessagesSetTyping {
+ peer any
+ action RawTypesSendMessageTextDraftAction
+ top_msg_id int
}
class RawTypesSendMessageTextDraftAction {
+ random_id int
+ text RawTypesTextWithEntities
}
class RawTypesTextWithEntities {
+ text str
+ entities list
}
class RawFunctionsInvokeWithBusinessConnection {
+ connection_id str
+ query RawFunctionsMessagesSetTyping
}
class ChatActionEnum {
MESSAGE_DRAFT
}
Client <|.. SendMessageDraft : mixin
SendMessageDraft ..> UtilsModule : uses
SendMessageDraft ..> RawFunctionsMessagesSetTyping : builds
SendMessageDraft ..> RawTypesSendMessageTextDraftAction : builds
SendMessageDraft ..> RawTypesTextWithEntities : builds
SendMessageDraft ..> RawFunctionsInvokeWithBusinessConnection : optionally_wraps
ChatActionEnum ..> RawTypesSendMessageTextDraftAction : maps_to
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new capability for streaming drafted text messages, enhancing the interactive experience for users. Concurrently, it significantly upgrades the project's documentation infrastructure by integrating an automated TL Schema and example code generator. This ensures that the API reference is more comprehensive and easier to understand, reflecting the underlying Telegram Type Language definitions directly. These changes improve both user-facing features and developer experience. Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
TLDocGenerator.generate_example,get_default_valueis called asself.get_default_value(arg.name, arg.type, 0, minimal=minimal), which passesminimalas thevisitedpositional argument instead of theminimalkeyword – this will break the intended behavior and should be switched to explicit keyword arguments (e.g.depth=0, minimal=minimal). - In
SendMessageDraft.send_message_draft, thecastcall uses a string literal (cast("str", ...)); for correct typing, pass the actual type object instead (e.g.cast(str, ...)).
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `TLDocGenerator.generate_example`, `get_default_value` is called as `self.get_default_value(arg.name, arg.type, 0, minimal=minimal)`, which passes `minimal` as the `visited` positional argument instead of the `minimal` keyword – this will break the intended behavior and should be switched to explicit keyword arguments (e.g. `depth=0, minimal=minimal`).
- In `SendMessageDraft.send_message_draft`, the `cast` call uses a string literal (`cast("str", ...)`); for correct typing, pass the actual type object instead (e.g. `cast(str, ...)`).
## Individual Comments
### Comment 1
<location path="compiler/docs/tl_generator.py" line_range="278-287" />
<code_context>
+ def get_default_value(
</code_context>
<issue_to_address>
**suggestion:** The `visited` parameter in `get_default_value` is unused but still propagated, which makes the recursion control logic misleading.
You’re passing `visited.copy()` on each recursive call, but never using it inside the function, so it gives the impression that cycle detection exists when it doesn’t. Please either remove `visited` from the signature and call sites, or implement proper use of it (e.g., early-return when `arg_type` is already in `visited`) so the recursion and depth/optional handling remain clear for future maintainers.
Suggested implementation:
```python
def get_default_value(
self, arg_name, arg_type, depth=0, minimal=False
):
```
To fully implement the suggestion, you should also:
1. Update all call sites of `get_default_value` in `compiler/docs/tl_generator.py` (and any other files, if applicable) to remove the `visited` argument. For example, change:
- `self.get_default_value(arg_name, arg_type, depth + 1, visited.copy(), minimal=minimal)`
- `self.get_default_value(arg_name, arg_type, depth, visited=visited, minimal=minimal)`
to:
- `self.get_default_value(arg_name, arg_type, depth + 1, minimal=minimal)`
- `self.get_default_value(arg_name, arg_type, depth, minimal=minimal)`
2. Remove any `visited`-related logic in those call sites (e.g., construction of a `visited` set solely for passing into this function), since it will no longer be part of the recursion control.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| def get_default_value( | ||
| self, arg_name, arg_type, depth=0, visited=None, minimal=False | ||
| ): | ||
| if visited is None: | ||
| visited = set() | ||
| is_optional = "?" in arg_type | ||
| if is_optional: | ||
| arg_type = arg_type.split("?")[1] | ||
|
|
||
| if minimal and is_optional: |
There was a problem hiding this comment.
suggestion: The visited parameter in get_default_value is unused but still propagated, which makes the recursion control logic misleading.
You’re passing visited.copy() on each recursive call, but never using it inside the function, so it gives the impression that cycle detection exists when it doesn’t. Please either remove visited from the signature and call sites, or implement proper use of it (e.g., early-return when arg_type is already in visited) so the recursion and depth/optional handling remain clear for future maintainers.
Suggested implementation:
def get_default_value(
self, arg_name, arg_type, depth=0, minimal=False
):To fully implement the suggestion, you should also:
- Update all call sites of
get_default_valueincompiler/docs/tl_generator.py(and any other files, if applicable) to remove thevisitedargument. For example, change:self.get_default_value(arg_name, arg_type, depth + 1, visited.copy(), minimal=minimal)self.get_default_value(arg_name, arg_type, depth, visited=visited, minimal=minimal)
to:self.get_default_value(arg_name, arg_type, depth + 1, minimal=minimal)self.get_default_value(arg_name, arg_type, depth, minimal=minimal)
- Remove any
visited-related logic in those call sites (e.g., construction of avisitedset solely for passing into this function), since it will no longer be part of the recursion control.
There was a problem hiding this comment.
Code Review
This pull request introduces a significant enhancement to the documentation generation by parsing TL schema files to include signatures, parameter trees, and examples. It also adds a new send_message_draft method. The implementation of the TL documentation generator is well-structured, but I've found a couple of areas for improvement regarding robustness and correctness of the generated examples. Additionally, I've suggested adding input validation to the new send_message_draft method to improve developer experience.
|
|
||
|
|
||
| def camel(s: str): | ||
| return "".join(i[0].upper() + i[1:] for i in s.split("_")) |
There was a problem hiding this comment.
The current implementation of camel can fail with an IndexError if the input string contains consecutive underscores (e.g., foo__bar) because s.split('_') would produce empty strings. A more robust implementation would be to use capitalize() which handles empty strings gracefully.
| return "".join(i[0].upper() + i[1:] for i in s.split("_")) | |
| return "".join(i.capitalize() for i in s.split("_")) |
| return "await app.resolve_channel(chat_id)" | ||
|
|
||
| if depth > 6: | ||
| return "None" if is_optional else "None" |
There was a problem hiding this comment.
When the recursion depth limit is reached for a non-optional parameter, this function returns "None". This can be misleading in the generated example code, as None is likely an invalid value for a required parameter. It would be more informative to indicate that a complex object needs to be constructed.
| return "None" if is_optional else "None" | |
| return "None" if is_optional else f"{arg_type}(...)" |
| async def send_message_draft( | ||
| self: pyrogram.Client, | ||
| chat_id: int | str, | ||
| draft_id: int, |
There was a problem hiding this comment.
Summary by Sourcery
Integrate TL schema–driven documentation generation for raw API objects and add support for streaming drafted text messages.
New Features:
Enhancements:
CI: