Skip to content

Generate tree-structured raw MTProto documentation with examples#115

Merged
5hojib merged 1 commit intobetafrom
tree-structured-raw-docs-8149885366910417951
Mar 2, 2026
Merged

Generate tree-structured raw MTProto documentation with examples#115
5hojib merged 1 commit intobetafrom
tree-structured-raw-docs-8149885366910417951

Conversation

@5hojib
Copy link
Member

@5hojib 5hojib commented Mar 2, 2026

I have implemented a new documentation generation system for the raw MTProto API.

Key features:

  1. Recursive Parameter Tree: Every function and type page now features a visual tree representing the structure of parameters. Types are clickable and link directly to their own documentation pages.
  2. TL Schema Signature: The official TL schema line is now included and formatted for readability.
  3. Working Code Examples: Every function page includes a practical, asynchronous await app.invoke(...) example. Nested types are inlined, and common fields like peer and random_id are populated with realistic placeholders.
  4. Pruning for Readability: While top-level optional parameters are always included (set to None if not critical), deeply nested optional parameters are pruned to keep examples concise and useful.

Changes were made to:

  • compiler/docs/tl_generator.py (New): Core logic for parsing TL files and generating trees/examples.
  • compiler/docs/compiler.py: Integration with the documentation build process.
  • compiler/docs/template/page.txt: Updated template for Sphinx RST pages.

PR created automatically by Jules for task 8149885366910417951 started by @5hojib

Summary by Sourcery

Integrate a TL-based documentation generator to enrich raw MTProto API reference pages with schema signatures, parameter trees, and example code.

New Features:

  • Add a TLDocGenerator utility to parse TL schema files and expose combinator metadata for documentation.
  • Generate tree-structured parameter overviews, TL schema signatures, and runnable example snippets for raw MTProto functions and types in the docs.

Enhancements:

  • Wire the new TL documentation generator into the raw API docs build pipeline and source TL schema from canonical .tl files.

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.
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Mar 2, 2026

Reviewer's Guide

Implements a TL-based documentation generator for raw MTProto types and functions, wiring it into the docs compiler so each generated page includes a TL schema signature, a recursive parameter tree, and realistic code examples based on parsed TL combinators.

Sequence diagram for docs compiler using TLDocGenerator in generate_raw

sequenceDiagram
    participant Start as start
    participant TLGen as TLDocGenerator
    participant Compiler as compiler.generate_raw
    participant Build as build_inner
    participant Template as Sphinx_template

    Start->>TLGen: TLDocGenerator(tl_paths)
    activate TLGen
    TLGen-->>Start: instance
    deactivate TLGen

    Start->>Compiler: generate_raw(TYPES_PATH, TYPES_BASE, tl_gen)
    activate Compiler
    loop walk raw entities
        Compiler->>Build: build(path, level)
        activate Build
        Build->>TLGen: get_tl_signature(full_name)
        TLGen-->>Build: tl_signature
        Build->>TLGen: generate_tree(full_name)
        TLGen-->>Build: parameter_tree
        Build->>TLGen: generate_example(full_name, minimal)
        TLGen-->>Build: example_code
        Build->>Template: render page with tl_signature, parameter_tree, example_code
        Template-->>Build: rst_page
        Build-->>Compiler: write file
        deactivate Build
    end
    deactivate Compiler

    Start->>Compiler: generate_raw(FUNCTIONS_PATH, FUNCTIONS_BASE, tl_gen)
    Start->>Compiler: generate_raw(BASE_PATH, BASE_BASE, tl_gen)
Loading

Class diagram for TLDocGenerator and related TL documentation types

classDiagram
    class Argument {
        +str name
        +str type
    }

    class Combinator {
        +str section
        +str qualname
        +str id
        +List~Argument~ args
        +str qualtype
        +str full_line
    }

    class TLDocGenerator {
        -Dict~str, Combinator~ name_to_comb
        -Dict~str, List~str~~ base_to_constructors
        -List~Combinator~ combinators
        +TLDocGenerator(tl_files)
        +get_tl_signature(name) str
        +get_full_class_path(name) str
        +get_type_link(t) str
        +generate_tree(name) str
        +generate_example(name, minimal) str
        -_parse_tl(tl_files) List~Combinator~
        -_generate_tree_recursive(name, depth, prefix, visited, is_vector_item, is_base) List~str~
        -get_default_value(arg_name, arg_type, depth, visited, minimal) str
    }

    class CORE_TYPES

    Argument <|-- Combinator
    Combinator "*" --> "*" Argument : uses
    TLDocGenerator "1" --> "*" Combinator : parses and indexes
    TLDocGenerator "1" --> "*" Argument : reads argument metadata
    TLDocGenerator ..> CORE_TYPES : references
Loading

File-Level Changes

Change Details Files
Integrate TL-driven metadata into raw docs generation pipeline
  • Update generate_raw to accept a TLDocGenerator instance and pass TL-derived signature, parameter tree, and example code into the page template context
  • Instantiate TLDocGenerator from a fixed list of TL schema files in start() and reuse it across all raw-doc generations
compiler/docs/compiler.py
Introduce TLDocGenerator to parse TL schema and derive documentation artifacts
  • Parse TL schema files into Combinator/Argument structures while tracking sections (types/functions), base types, and constructors, normalizing names to camel case and handling reserved argument names
  • Expose helpers to format the original TL signature for display, map type names to Sphinx links, and resolve full class paths for types, functions, and base classes
  • Recursively build an ASCII-style tree of parameters and nested types, including special handling for base types, vectors, and cycle/expansion limits for readability
  • Generate default example values for TL arguments (with pruning of deep optional fields) and use them to construct code-block examples for both function invocations and type constructors
compiler/docs/tl_generator.py
Extend page template to consume TL-generated documentation elements
  • Modify the Sphinx RST page template to render the TL schema signature, parameter tree, and code examples provided by TLDocGenerator for each raw type/function
compiler/docs/template/page.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, 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 significantly enhances the raw MTProto API documentation by introducing a new generation system. The primary goal is to make the documentation more comprehensive and user-friendly by providing structured parameter trees, direct TL schema signatures, and executable code examples. This change improves the clarity and utility of the API documentation for developers.

Highlights

  • Recursive Parameter Tree: Implemented a visual tree representation for function and type parameters, with clickable links to their respective documentation pages.
  • TL Schema Signature Inclusion: Added the official TL schema line, formatted for improved readability, to documentation pages.
  • Working Code Examples: Integrated practical, asynchronous await app.invoke(...) examples for each function, including inlined nested types and realistic placeholders for common fields.
  • Intelligent Example Pruning: Introduced logic to prune deeply nested optional parameters in examples, ensuring conciseness while retaining essential top-level optional parameters.
  • New TL Documentation Generator: A new Python module tl_generator.py was added to handle the parsing of TL files and the generation of signatures, parameter trees, and code examples.
Changelog
  • compiler/docs/compiler.py
    • Imported the new TLDocGenerator class.
    • Modified the generate_raw function signature to accept an instance of TLDocGenerator.
    • Updated the render_template call to include tl_signature, parameter_tree, and example_code generated by the TLDocGenerator.
    • Instantiated TLDocGenerator with relevant TL schema paths and passed it to generate_raw calls.
  • compiler/docs/template/page.txt
    • Added new sections to the documentation page template for 'TL Schema', 'Parameter Tree', and 'Example' code blocks.
  • compiler/docs/tl_generator.py
    • Added a new file containing the TLDocGenerator class and helper functions.
    • Implemented logic to parse TL schema files and extract combinator information.
    • Provided methods to retrieve formatted TL signatures for given names.
    • Developed a recursive method to generate a tree-structured representation of parameters for types and functions.
    • Created a function to generate working Python code examples for API calls, including default value generation and optional parameter pruning.
Activity
  • PR created automatically by Jules for task 8149885366910417951, started by @5hojib.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In generate_example, the call to get_default_value passes minimal as the fourth positional argument, which is actually visited; this means minimal is never honored and visited is misused—switch this to a keyword argument (minimal=minimal) to fix the behavior.
  • The visited parameter in get_default_value is never updated with the current type, so it does not actually prevent recursive cycles; either incorporate the current arg_type into visited or drop the parameter to avoid confusion.
  • Several recursion/depth thresholds and pruning rules (e.g., depth > 6, specific arg-name whitelists, special base-type limits) are hard-coded throughout TLDocGenerator; consider extracting these into named constants or configuration structures to make the behavior easier to tune and reason about.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `generate_example`, the call to `get_default_value` passes `minimal` as the fourth positional argument, which is actually `visited`; this means `minimal` is never honored and `visited` is misused—switch this to a keyword argument (`minimal=minimal`) to fix the behavior.
- The `visited` parameter in `get_default_value` is never updated with the current type, so it does not actually prevent recursive cycles; either incorporate the current `arg_type` into `visited` or drop the parameter to avoid confusion.
- Several recursion/depth thresholds and pruning rules (e.g., depth > 6, specific arg-name whitelists, special base-type limits) are hard-coded throughout `TLDocGenerator`; consider extracting these into named constants or configuration structures to make the behavior easier to tune and reason about.

## Individual Comments

### Comment 1
<location path="compiler/docs/tl_generator.py" line_range="168-177" />
<code_context>
+            val = self.get_default_value(arg_name, inner, depth + 1, visited.copy(), minimal=minimal)
+            indent = "    " * (depth + 1)
+            item_indent = "    " * (depth + 2)
+            if inner not in CORE_TYPES:
+                return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
+            return f"[{val}]"
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The f-string constructing the Vector default value is invalid due to a backslash in the expression.

In `get_default_value`, this return statement:

```python
return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
```
will raise a `SyntaxError`, because f-string expressions cannot contain backslashes inside the string literal argument to `replace`. Compute the replaced value first, then use it in the f-string, e.g.:

```python
indented_val = val.replace("\n", "\n" + "    ")
return f"[\n{item_indent}{indented_val}\n{indent}]"
```
</issue_to_address>

### Comment 2
<location path="compiler/docs/tl_generator.py" line_range="155" />
<code_context>
+        if name in ["InputPeerSelf", "InputPeerEmpty", "InputPeerChat", "InputUserSelf", "InputUserEmpty"] and depth > 2:
+            return []
+
+        filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
+        for i, arg in enumerate(filtered_args):
+            is_last = (i == len(filtered_args) - 1)
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting shared argument filtering, prefix construction, and vector default-value logic into small helper methods to reduce duplication and clarify control flow without changing behaviour.

You can cut a noticeable amount of complexity and duplication with a few small extractions, without changing behavior.

### 1. Extract common argument filtering

The `flags`-filtering logic is duplicated in `_generate_tree_recursive` and `generate_example`. Centralising it reduces risk if the rule changes:

```python
def _filtered_args(self, c: Combinator) -> List[Argument]:
    return [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
```

Use it in both places:

```python
# _generate_tree_recursive
- filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
+ filtered_args = self._filtered_args(c)
```

```python
# generate_example
- filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
+ filtered_args = self._filtered_args(c)
```

### 2. Extract prefix / indentation logic for tree rendering

The `"    "` vs `"│   "` logic is repeated and slightly obscures the high‑level flow. A tiny helper makes this clearer and less error‑prone:

```python
def _child_prefix(self, prefix: str, is_last: bool) -> str:
    return prefix + ("    " if is_last else "")
```

Then update the recursive calls and lines:

```python
# in _generate_tree_recursive

- res.append(f"| {prefix}{'└── ' if is_last else '├── '}{self.get_type_link(constr)}")
+ branch = "└── " if is_last else "├── "
+ res.append(f"| {prefix}{branch}{self.get_type_link(constr)}")

- res.extend(self._generate_tree_recursive(constr, depth + 1, prefix + ("    " if is_last else ""), new_visited, is_base=False))
+ res.extend(self._generate_tree_recursive(constr, depth + 1, self._child_prefix(prefix, is_last), new_visited, is_base=False))

# same pattern for other recursive calls:
- prefix + ("    " if is_last else "")
+ self._child_prefix(prefix, is_last)
```

This keeps the behaviour identical but makes the tree logic easier to scan.

### 3. Isolate vector default-value handling

`get_default_value` is doing several jobs; a minimal step is to pull vector-specific logic into a helper, shrinking the main function and making the recursion policy clearer:

```python
def _default_for_vector(self, arg_name: str, arg_type: str, depth: int, visited, minimal: bool) -> str:
    inner = arg_type[7:-1]
    val = self.get_default_value(arg_name, inner, depth + 1, visited.copy(), minimal=minimal)
    indent = "    " * (depth + 1)
    item_indent = "    " * (depth + 2)
    if inner not in CORE_TYPES:
        return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
    return f"[{val}]"
```

Then in `get_default_value`:

```python
- if arg_type.startswith("Vector<"):
-     inner = arg_type[7:-1]
-     val = self.get_default_value(arg_name, inner, depth + 1, visited.copy(), minimal=minimal)
-     indent = "    " * (depth + 1)
-     item_indent = "    " * (depth + 2)
-     if inner not in CORE_TYPES:
-         return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
-     return f"[{val}]"
+ if arg_type.startswith("Vector<"):
+     return self._default_for_vector(arg_name, arg_type, depth, visited, minimal)
```

This is a small change, but it makes `get_default_value`’s main flow less tangled and opens the door to further splitting (e.g. `_default_for_scalar`, `_default_for_constructor`) later without altering behaviour now.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +168 to +177
if inner not in CORE_TYPES:
res.extend(self._generate_tree_recursive(inner, depth + 1, prefix + (" " if is_last else "│ "), new_visited, is_vector_item=True))
elif arg_type not in CORE_TYPES:
# If the type is a base type, we want to show its constructors
is_arg_base = arg_type in self.base_to_constructors
res.extend(self._generate_tree_recursive(arg_type, depth + 1, prefix + (" " if is_last else "│ "), new_visited, is_base=is_arg_base))

return res

def get_default_value(self, arg_name, arg_type, depth=0, visited=None, minimal=False):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The f-string constructing the Vector default value is invalid due to a backslash in the expression.

In get_default_value, this return statement:

return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"

will raise a SyntaxError, because f-string expressions cannot contain backslashes inside the string literal argument to replace. Compute the replaced value first, then use it in the f-string, e.g.:

indented_val = val.replace("\n", "\n" + "    ")
return f"[\n{item_indent}{indented_val}\n{indent}]"

if name in ["InputPeerSelf", "InputPeerEmpty", "InputPeerChat", "InputUserSelf", "InputUserEmpty"] and depth > 2:
return []

filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting shared argument filtering, prefix construction, and vector default-value logic into small helper methods to reduce duplication and clarify control flow without changing behaviour.

You can cut a noticeable amount of complexity and duplication with a few small extractions, without changing behavior.

1. Extract common argument filtering

The flags-filtering logic is duplicated in _generate_tree_recursive and generate_example. Centralising it reduces risk if the rule changes:

def _filtered_args(self, c: Combinator) -> List[Argument]:
    return [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]

Use it in both places:

# _generate_tree_recursive
- filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
+ filtered_args = self._filtered_args(c)
# generate_example
- filtered_args = [a for a in c.args if not (a.name.startswith("flags") and a.type == "#")]
+ filtered_args = self._filtered_args(c)

2. Extract prefix / indentation logic for tree rendering

The " " vs "│ " logic is repeated and slightly obscures the high‑level flow. A tiny helper makes this clearer and less error‑prone:

def _child_prefix(self, prefix: str, is_last: bool) -> str:
    return prefix + ("    " if is_last else "│   ")

Then update the recursive calls and lines:

# in _generate_tree_recursive

- res.append(f"| {prefix}{'└── ' if is_last else '├── '}{self.get_type_link(constr)}")
+ branch = "└── " if is_last else "├── "
+ res.append(f"| {prefix}{branch}{self.get_type_link(constr)}")

- res.extend(self._generate_tree_recursive(constr, depth + 1, prefix + ("    " if is_last else "│   "), new_visited, is_base=False))
+ res.extend(self._generate_tree_recursive(constr, depth + 1, self._child_prefix(prefix, is_last), new_visited, is_base=False))

# same pattern for other recursive calls:
- prefix + ("    " if is_last else "│   ")
+ self._child_prefix(prefix, is_last)

This keeps the behaviour identical but makes the tree logic easier to scan.

3. Isolate vector default-value handling

get_default_value is doing several jobs; a minimal step is to pull vector-specific logic into a helper, shrinking the main function and making the recursion policy clearer:

def _default_for_vector(self, arg_name: str, arg_type: str, depth: int, visited, minimal: bool) -> str:
    inner = arg_type[7:-1]
    val = self.get_default_value(arg_name, inner, depth + 1, visited.copy(), minimal=minimal)
    indent = "    " * (depth + 1)
    item_indent = "    " * (depth + 2)
    if inner not in CORE_TYPES:
        return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
    return f"[{val}]"

Then in get_default_value:

- if arg_type.startswith("Vector<"):
-     inner = arg_type[7:-1]
-     val = self.get_default_value(arg_name, inner, depth + 1, visited.copy(), minimal=minimal)
-     indent = "    " * (depth + 1)
-     item_indent = "    " * (depth + 2)
-     if inner not in CORE_TYPES:
-         return f"[\n{item_indent}{val.replace('\n', '\n' + '    ')}\n{indent}]"
-     return f"[{val}]"
+ if arg_type.startswith("Vector<"):
+     return self._default_for_vector(arg_name, arg_type, depth, visited, minimal)

This is a small change, but it makes get_default_value’s main flow less tangled and opens the door to further splitting (e.g. _default_for_scalar, _default_for_constructor) later without altering behaviour now.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new documentation generation system for the raw MTProto API, which is a great enhancement. The new tl_generator.py file contains the core logic for parsing TL schema files and generating parameter trees and code examples.

My review focuses on the new tl_generator.py file, where I've identified a few areas for improvement regarding maintainability and robustness. Specifically, I've suggested:

  • Using more robust parsing for TL files.
  • Refactoring hardcoded values into constants for better readability and easier maintenance.
  • Removing an unused parameter to improve code clarity.

These changes should make the new documentation generator more robust and easier to maintain in the long run. The overall implementation is well-done.


if combinator_match := COMBINATOR_RE.match(line):
qualname, cid, qualtype = combinator_match.groups()
parts = line.split(" ")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using line.split(' ') can be fragile if there are multiple spaces between parts of the TL definition, as it can produce empty strings in the parts list. It's more robust to use line.split() (with no arguments), which handles any amount of whitespace as a delimiter and discards empty strings.

Suggested change
parts = line.split(" ")
parts = line.split()

Comment on lines +66 to +67
if arg_name == "self": arg_name = "is_self"
if arg_name == "from": arg_name = "from_peer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better maintainability and extensibility, consider using a dictionary for mapping reserved keywords instead of multiple if statements. This makes it easier to add more reserved keywords in the future.

You can define a RESERVED_KEYWORD_MAP constant at the module level:

RESERVED_KEYWORD_MAP = {
    "self": "is_self",
    "from": "from_peer",
}
Suggested change
if arg_name == "self": arg_name = "is_self"
if arg_name == "from": arg_name = "from_peer"
arg_name = RESERVED_KEYWORD_MAP.get(arg_name, arg_name)


if is_base and name in self.base_to_constructors:
constrs = self.base_to_constructors[name]
limit_expansion = name in ["InputPeer", "InputUser", "InputChannel", "InputFile", "InputMedia", "MessageEntity"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability and readability, consider moving this hardcoded list of types to a module-level constant (as a set for efficient lookups). This makes it easier to manage the list of types for which tree expansion should be limited.

For example, you could define at the top of the file:

LIMITED_EXPANSION_TYPES = {
    "InputPeer", "InputUser", "InputChannel", "InputFile", "InputMedia", "MessageEntity"
}

And then use it here.

Suggested change
limit_expansion = name in ["InputPeer", "InputUser", "InputChannel", "InputFile", "InputMedia", "MessageEntity"]
limit_expansion = name in LIMITED_EXPANSION_TYPES

Comment on lines +177 to +178
def get_default_value(self, arg_name, arg_type, depth=0, visited=None, minimal=False):
if visited is None: visited = set()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The visited parameter in get_default_value seems to be intended for cycle detection but is currently unused. The set is initialized but never populated or checked. Recursion is instead prevented by a hard depth limit (depth > 6).

To improve clarity and remove dead code, I suggest removing the visited parameter from this method's signature and from its recursive call sites (lines 208 and 232).

Suggested change
def get_default_value(self, arg_name, arg_type, depth=0, visited=None, minimal=False):
if visited is None: visited = set()
def get_default_value(self, arg_name, arg_type, depth=0, minimal=False):

@5hojib 5hojib merged commit f7333e2 into beta Mar 2, 2026
1 check passed
@5hojib 5hojib deleted the tree-structured-raw-docs-8149885366910417951 branch March 4, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant