Skip to content

ast.alias._attributes in Python 3.9 and "stdlib/ast.pyi" don't match #14102

@hunterhogan

Description

@hunterhogan

I'm 51% sure this belongs in typeshed, 49% sure this belongs in cpython, and 106.88% surely confused.

The 3.9 interpreter says ast.alias._attributes = (), however, the stub says **kwargs: Unpack[_Attributes], therefore, at the very least, there is conflicting information.

typeshed/stdlib/ast.pyi

Lines 1431 to 1444 in a7ae4ec

class alias(AST):
lineno: int
col_offset: int
end_lineno: int | None
end_col_offset: int | None
if sys.version_info >= (3, 10):
__match_args__ = ("name", "asname")
name: str
asname: str | None
def __init__(self, name: str, asname: str | None = None, **kwargs: Unpack[_Attributes]) -> None: ...
if sys.version_info >= (3, 14):
def __replace__(self, *, name: str = ..., asname: str | None = ..., **kwargs: Unpack[_Attributes]) -> Self: ...

Evidence the stub file should change I am confused about what should change

I checked whether ast.alias.lineno exists in Python 3.9.

Python 3.9

(.309) C:\clones\typeshed>py
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> source = 'from pathlib import Path'
>>> astModule = ast.parse(source)
>>> for node in ast.walk(astModule):
...     if isinstance(node, ast.alias):
...         print(node.lineno)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
AttributeError: 'alias' object has no attribute 'lineno'

Python 3.12

I compared to Python 3.12 just to make sure.

(.venv) C:\clones\typeshed>py
Python 3.12.10 (tags/v3.12.10:0cc8128, Apr  8 2025, 12:21:36) [MSC v.1943 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> source = 'from pathlib import Path'
>>> astModule = ast.parse(source)
>>> for node in ast.walk(astModule):
...     if isinstance(node, ast.alias):
...         print(node.lineno)
... 
1

Obviously, the stub file is off

I compared the actual interpreter behaviors to the stub file, so the situation is clear, right?

But, just to be thorough...

Just in case, I wrote some code to look at the "_attributes" from a few different angles. I thought it would reinforce what I had found. Instead, I am unsure which source is reporting inaccurate information, and I don't know what one should investigate next.

import ast
import sys

print(f"\n{sys.version = }")

print(f"\n{ast.alias._attributes = }")

print(f'\n{(source := """from pathlib import Path""") = }')
astModule = ast.parse(source)
for node in ast.walk(astModule):
    if isinstance(node, ast.alias):
        try:
            print(node.lineno)
        except AttributeError as ERRORmessage:
            print(ERRORmessage)
        try:
            print(node.col_offset)
        except AttributeError as ERRORmessage:
            print(ERRORmessage)
        try:
            print(node.end_lineno)
        except AttributeError as ERRORmessage:
            print(ERRORmessage)
        try:
            print(node.end_col_offset)
        except AttributeError as ERRORmessage:
            print(ERRORmessage)
        try:
            print(ast.unparse(ast.Module([node], type_ignores=[])))
        except AttributeError as ERRORmessage:
            print(ERRORmessage)

print(f"\n{(ast_alias := ast.alias(name='Donald_Glover', asname='Childish_Gambino', lineno=0, col_offset=0, end_lineno=None, end_col_offset=None, OVER=9000)) = }")
node = ast_alias
if isinstance(node, ast.alias):
    try:
        print(node.lineno)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.col_offset)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.end_lineno)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.end_col_offset)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.OVER)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(ast.unparse(ast.Module([node], type_ignores=[])))
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
else:
    print(type(node))

print(f"\n{(ast_alias := ast.alias(name='Temujin', asname='Genghis_Khan')) = }")
node = ast_alias
if isinstance(node, ast.alias):
    try:
        print(node.lineno)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.col_offset)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.end_lineno)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.end_col_offset)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(node.OVER)
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
    try:
        print(ast.unparse(ast.Module([node], type_ignores=[])))
    except AttributeError as ERRORmessage:
        print(ERRORmessage)
else:
    print(type(node))

The full output

(.309) C:\clones\typeshed>alias309.py

sys.version = '3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)]'

ast.alias._attributes = ()

(source := """from pathlib import Path""") = 'from pathlib import Path'
'alias' object has no attribute 'lineno'
'alias' object has no attribute 'col_offset'
'alias' object has no attribute 'end_lineno'
'alias' object has no attribute 'end_col_offset'
Path

(ast_alias := ast.alias(name='Donald_Glover', asname='Childish_Gambino', lineno=0, col_offset=0, end_lineno=None, end_col_offset=None, OVER=9000)) = <ast.alias object at 0x000002A40DF58D90>
0
0
None
None
9000
Donald_Glover as Childish_Gambino

(ast_alias := ast.alias(name='Temujin', asname='Genghis_Khan')) = <ast.alias object at 0x000002A40DF58D00>
'alias' object has no attribute 'lineno'
'alias' object has no attribute 'col_offset'
'alias' object has no attribute 'end_lineno'
'alias' object has no attribute 'end_col_offset'
'alias' object has no attribute 'OVER'
Temujin as Genghis_Khan

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions