Skip to content

fix: ast.NameConstant missing fields #14353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

hunterhogan
Copy link
Contributor

(.venv) C:\apps\astToolkit>py
Python 3.13.5 (tags/v3.13.5:6cb20a2, Jun 11 2025, 16:15:46) [MSC v.1943 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> ast.Str._fields
<stdin>-1:1: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead
('s',)
>>> ast.Bytes._fields
<stdin>-2:1: DeprecationWarning: ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead
('s',)
>>> ast.Num._fields  
<stdin>-3:1: DeprecationWarning: ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead
('n',)
>>> ast.NameConstant._fields
<stdin>-4:1: DeprecationWarning: ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead
('value', 'kind')

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@hunterhogan
Copy link
Contributor Author

Is there something to change?

Copy link
Contributor

github-actions bot commented Jul 9, 2025

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@brianschubert
Copy link
Member

brianschubert commented Jul 9, 2025

I think it's not fully clear what the purpose of this change is per #14353 (comment)

It may help if you could share an example of some code that currently doesn't pass type checking but which would after making this change.

@hunterhogan
Copy link
Contributor Author

I think it's not fully clear what the purpose of this change is per #14353 (comment)

It may help if you could share an example of some code that currently doesn't pass type checking but which would after making this change.

I'm not sure I understand what information you need, even though your request is clear and specific. Or perhaps, I don't know enough to create a simpler example based on my actual problem, which is a complex piece of code.

In my inexpert opinion, the purpose is to keep typeshed as the SSOT for type information, which requires accuracy for the sake of accuracy.

Excerpt from astToolFactory

def _get_astModule_astStub() -> ast.Module:
	ImaSearchContext: typeshed_client.SearchContext = typeshed_client.get_search_context(typeshed=pathRoot_typeshed)
	return parsePathFilename2astModule(raiseIfNone(typeshed_client.get_stub_file("ast", search_context=ImaSearchContext)))

...

    dictionaryClassDef: dict[str, ast.ClassDef] = makeDictionaryClassDef(_get_astModule_astStub())

...

        def get_type_ast_expr(dddataframeee: pandas.DataFrame) -> tuple[pandas.Series, pandas.Series]:
            attribute: str = cast("str", dddataframeee["attribute"])
            if attribute == 'n':
                # TODO remove when `ast.Num` is updated
                attribute = 'value'
            getAnnotation = NodeTourist[ast.AnnAssign, ast.expr](
                findThis = Be.AnnAssign.targetIs(IfThis.isNameIdentifier(attribute))
                , doThat = Then.extractIt(DOT.annotation))

            ClassDefIdentifier: str = cast("str", dddataframeee["ClassDefIdentifier"])
            if ClassDefIdentifier == 'NameConstant':
                ClassDefIdentifier = 'Constant'

            type_ast_expr: ast.expr = raiseIfNone(getAnnotation.captureLastMatch(dictionaryClassDef[ClassDefIdentifier]))

            NodeChanger(findThis=Be.Subscript.valueIs(IfThis.isNameIdentifier("Literal")), doThat=Then.replaceWith(Make.Name("bool"))
                ).visit(type_ast_expr)

            dddataframeee["type_ast_expr"] = NodeChanger[ast.Name, ast.expr](
                findThis=lambda node: Be.Name(node) and isinstance(eval(node.id), type) and issubclass(eval(node.id), ast.AST)  # noqa: S307
                , doThat=lambda node: Make.Attribute(Make.Name("ast"), eval(node.id).__name__)  # noqa: S307
            ).visit(type_ast_expr)
            dddataframeee["attributeType"] = ast.unparse(cast("ast.AST", dddataframeee["type_ast_expr"]))

            return dddataframeee["type_ast_expr"], dddataframeee["attributeType"]

For each subclass (ClassDefIdentifier), I get the "attribute" names from the interpreter using ._fields. Then I use the code above to get the type of each field from typeshed. Because ast.Num.NameConstant is not defined in typeshed, I have inserted the if statement. In contrast, I don't have to worry about ast.Bytes or ast.Str. ast.Num.n is the only other class or attribute in ast.AST that isn't defined in typeshed. #14355

Oh, wait, was. I need to update that code.

I will continue trying to think of a way to create a simpler example. Sorry.

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.

2 participants