PEP 846 – Docstrings for Type Aliases
The evolution of Python’s typing system has reached a new milestone with the introduction of PEP 846, a Standards Track proposal that seeks to formalize and implement runtime docstrings for type aliases. Authored by Bartosz Sławecki and sponsored by Jelle Zijlstra, this proposal aims to bridge a significant gap in Python’s self-documenting capabilities by allowing the type statement—introduced in Python 3.12 via PEP 695—to support and preserve string literals as documentation. By integrating these docstrings into the Abstract Syntax Tree (AST) and exposing them through standard introspection tools like help() and pydoc, PEP 846 promises to enhance the maintainability and readability of complex Python codebases.
The Shift Toward First-Class Type Aliases
To understand the necessity of PEP 846, one must look at the trajectory of Python’s typing history. For years, type aliases were created through simple assignments, such as Vector = list[float]. While functional, these assignments were ambiguous to both the interpreter and static analysis tools, as there was no clear distinction between a standard variable assignment and a dedicated type alias.
The landscape changed with PEP 695 in Python 3.12, which introduced the type statement: type Vector = list[float]. This syntax created a dedicated TypeAliasType object at runtime. However, despite being a first-class object, these aliases lacked a native mechanism for documentation. Unlike classes and functions, which have long supported docstrings immediately following their headers, type aliases remained "silent" at runtime. If a developer wanted to explain the purpose of a specific alias, they had to rely on comments or external documentation tools that parsed the source code directly. PEP 846 addresses this by treating type aliases with the same level of architectural respect as functions and classes.
Technical Specifications and Implementation
The core of PEP 846 is the proposal to preserve a string literal that immediately follows a type statement. Under the new rules, if the next logical line after a type alias declaration is a string constant, that string is captured as the alias object’s __doc__ attribute.
From a technical standpoint, this requires a modification to the Python grammar and the ast (Abstract Syntax Tree) module. The ast.TypeAlias node will be updated to include an optional doc field. When the Python parser encounters a string following a type statement, it will no longer treat it as a separate expression statement but will instead fold it into the TypeAlias node itself. This ensures that the documentation is inextricably linked to the alias from the moment of parsing.
The proposal also outlines specific rules for "docstring placement." To qualify as a docstring, the string must be an expression statement consisting of a string literal. It can be a single string, parenthesized strings, or adjacent literals that the parser combines. However, f-strings, bytes literals, and complex expressions (like "part1" + "part2") are excluded to maintain consistency with how function and class docstrings are handled. Furthermore, the rule respects Python’s indentation blocks; a docstring must reside in the same block as the alias it describes.
Chronology of Development and Tooling Adoption
The movement toward formalizing alias documentation did not happen in a vacuum. It was preceded by a growing trend among third-party development tools to support this exact pattern.
- Late 2023: Pyright, the static type checker developed by Microsoft, began supporting docstrings following type statements. This allowed developers using VS Code and other IDEs to see documentation in hover-over tooltips, even though the Python runtime itself remained unaware of the strings.
- Late 2023: Pylint, a widely used static analysis tool, updated its logic to recognize these strings as documentation rather than "pointless" expression statements.
- Early 2025: Sphinx, the industry standard for Python documentation, introduced the
autotypedirective, enabling the automatic extraction of alias docstrings for generated HTML and PDF manuals. - September 2026: PEP 846 is formally drafted and submitted for discussion on the Python Discourse forums, targeting a full implementation in Python 3.16.
This timeline illustrates a "bottom-up" approach to language evolution, where the community and tool authors established a de facto standard that the core language is now looking to codify.
Enhancing Runtime Introspection and User Experience
One of the primary benefits of PEP 846 is the improvement of the help() function. Currently, calling help(MyAlias) in a REPL (Read-Eval-Print Loop) environment returns generic information about the TypeAliasType class rather than the specific purpose of MyAlias. This can be frustrating for developers exploring unfamiliar libraries.
Under PEP 846, the pydoc module will be updated to recognize type aliases specifically. When a user requests help on an alias, the output will display the alias’s name, its definition (e.g., type Timeout = float | None), and its associated docstring. This brings a level of parity to the developer experience that was previously reserved for more complex objects.
Furthermore, the proposal includes updates to the typing.TypeAliasType constructor. It will gain a keyword-only doc parameter, allowing programmatically created aliases to carry documentation. This is particularly useful for framework authors who generate types dynamically based on schemas or database models.
Impact on Optimization and Performance
A critical aspect of any Python enhancement is its impact on performance and the -OO (optimization) flag. Python has a long-standing behavior where docstrings are stripped when the interpreter is run with high optimization levels to save memory. PEP 846 maintains this consistency.
At optimization level 2, the doc field in the AST will be cleared, and the __doc__ attribute of the alias at runtime will be None. This ensures that PEP 846 does not introduce unexpected memory overhead for production environments that prioritize footprint over introspection. For standard development and testing environments (optimization levels 0 and 1), the docstrings remain fully accessible.
Broader Implications for the Python Ecosystem
The implications of PEP 846 extend beyond simple documentation. By making documentation accessible at runtime, the proposal opens the door for third-party frameworks to utilize this metadata.
Frameworks like Pydantic, which heavily leverage Python’s typing system for data validation and serialization, could potentially use these docstrings to generate more descriptive error messages or more comprehensive API documentation (such as OpenAPI/Swagger schemas). For instance, an alias type UserID = int could include a docstring explaining that the ID must be a positive integer, and a framework could theoretically extract that string to inform an end-user of a REST API.
Additionally, the doctest module will be updated to discover and execute tests embedded within type alias docstrings. This encourages a "test-driven" approach to type definitions, where developers can provide examples of valid and invalid values directly within the documentation of the type itself.
Reactions and Community Consensus
The initial feedback from the Python steering committee and the broader community has been largely positive. Jelle Zijlstra, a prominent contributor to Python’s typing module, has lent his support as the PEP’s sponsor. Guido van Rossum, the creator of Python, also contributed to the discussion by suggesting that the parser—rather than a secondary post-processing step—should be responsible for recognizing the docstrings.
The consensus is that PEP 846 represents the "final polish" on the work started by PEP 695. While the type statement provided the syntax, PEP 846 provides the context. The primary concern raised during discussions involved backward compatibility for tools that parse Python source code. Since the proposal changes the AST structure (moving a string from an Expr node into a field of the TypeAlias node), authors of linters and refactoring tools will need to update their logic for Python 3.16. However, the author argues that the long-term benefits of a cleaner, more integrated AST outweigh the temporary inconvenience of tool updates.
Conclusion and Future Outlook
As Python continues to grow in complexity and usage across data science, web development, and systems programming, the clarity of its typing system becomes paramount. PEP 846 is a proactive step toward ensuring that as the language becomes more "typed," it does not become less "readable."
By formalizing docstrings for type aliases, Python 3.16 will offer developers a more cohesive and professional toolkit for defining domain-specific types. Whether it is a simple Timeout alias or a complex generic ListOrSet[T], the ability to attach human-readable explanations directly to the code ensures that the intent of the programmer is preserved from the source file to the runtime environment. As the proposal moves through the discussion phase toward potential acceptance, it stands as a testament to Python’s commitment to developer ergonomics and the "Zen" of explicit over implicit.