python / python/mypy

`SymbolTableNode.kind` is incorrect for `from <module> import <name>` imports in a function body

Offen
#18,616 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug Report, Expected Behaviour, & Actual Behaviour

I'm writing a mypy plugin which needs to distinguish between the origin of variables (whether they're from the global scope or local scope). When analysing names from ImportFrom nodes, the kind value appears to be incorrect:

# module.py
import typing as t

TypeT = t.TypeVar("TypeT", bound=type[object])

def reveal_name_expr_kinds(Class: TypeT, /) -> TypeT:
    return Class

@reveal_name_expr_kinds
class A:
    def method(self, /) -> None:
        import os
        from os import chdir, path

        x = 1

        # Correct behaviour
        os  # N: Revealed kind is "Ldef"
        x  # N: Revealed kind is "Ldef"

        # Correct behaviour
        t  # N: Revealed kind is "Gdef"
        TypeT  # N: Revealed kind is "Gdef"

        # Incorrect behaviour (expected both of these to be "Ldef")
        chdir  # N: Revealed kind is "Gdef"
        path  # N: Revealed kind is "Gdef"

Potential fix

I believe the issue is here: https://github.com/python/mypy/blob/e9a813c32637e0c9eb1c6cff6426dab504d9656d/mypy/semanal.py#L2853

Changing it to the following seems to fix the problem:

                 node = module.names.get(id)
+                if node is not None:
+                    node = SymbolTableNode(self.current_symbol_kind(), node.node)

However, It's not obvious how to write a test for this. I'm looking at https://github.com/python/mypy/blob/master/test-data/unit/semanal-symtable.test but the tests here rely on str()ingifying a mypy.nodes.SymbolTable object, which is an attribute of mypy.nodes.MypyFile and mypy.nodes.TypeInfo; there is no equivalent attribute in mypy.nodes.FuncDef (function body symbol tables only temporarily exist at https://github.com/python/mypy/blob/e9a813c32637e0c9eb1c6cff6426dab504d9656d/mypy/semanal.py#L444-L446).

Is there is an obvious way to test the local definition kinds directly (that is, without employing a mypy plugin into the tests)?

To Reproduce

Along with module.py above, put the following files in any directory, navigate inside the directory, and just run mypy in the command line:

# mypy.ini
[mypy]
plugins = plugin.py
files = module.py
# plugin.py
from __future__ import annotations

import typing as t

import mypy.nodes
import mypy.plugin
import mypy.server.subexpr

if t.TYPE_CHECKING:
    import collections.abc as cx

STR_REVEAL_KINDS_DECO_NAME: t.Final = "reveal_name_expr_kinds"

def plugin(version: str) -> type[mypy.plugin.Plugin]:
    return SymbolKindRevealer

class SymbolKindRevealer(mypy.plugin.Plugin):
    def get_class_decorator_hook_2(
        self, fullname: str
    ) -> cx.Callable[[mypy.plugin.ClassDefContext], bool] | None:
        if fullname.endswith(f".{STR_REVEAL_KINDS_DECO_NAME}"):
            return _reveal_symbol_kinds

def _reveal_symbol_kinds(ctx: mypy.plugin.ClassDefContext, /) -> bool:
    expr_finder: t.Final = mypy.server.subexpr.SubexpressionFinder()
    for cls_stmt in ctx.cls.defs.body:
        if isinstance(cls_stmt, mypy.nodes.FuncDef):
            for func_stmt in cls_stmt.body.body:
                func_stmt.accept(expr_finder)
    for expr in expr_finder.expressions:
        if isinstance(expr, mypy.nodes.NameExpr) and (expr.kind is not None):
            ctx.api.msg.note(
                f'Revealed kind is "{mypy.nodes.node_kinds[expr.kind]}"', expr
            )
    return True

Your Environment

  • Mypy version used: 1.15
  • Python version used: 3.9

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne in mypy/semanal.py bei der Behandlung von ImportFrom in Zeile 2853 und vergleiche sie mit der gemeldeten Konstruktion von SymbolTableNode. Prüfe test-data/unit/semanal-symtable.test und test/testsemanal.py und verwende dann die bereitgestellte Plugin-Reproduktion, um zu bestätigen, dass Imports im Funktionskörper Ldef melden, und bestimme, wie sich dieses Verhalten in Tests abdecken lässt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
compilers, devtools
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.