Skip to content
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

✨ Implement MyPyVisitor #51

Merged
merged 6 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions bump_pydantic/codemods/add_default_none.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
from libcst.codemod import CodemodContext, VisitorBasedCodemodCommand
from libcst.metadata import FullyQualifiedNameProvider, QualifiedName

from bump_pydantic.codemods.class_def_visitor import ClassDefVisitor
from bump_pydantic.markers.find_base_model import CONTEXT_KEY as BASE_MODEL_CONTEXT_KEY
from bump_pydantic.markers.find_base_model import find_base_model
from bump_pydantic.codemods.mypy_visitor import CONTEXT_KEY


class AddDefaultNoneCommand(VisitorBasedCodemodCommand):
Expand Down Expand Up @@ -51,7 +49,7 @@ def visit_ClassDef(self, node: cst.ClassDef) -> None:
return None

fqn: QualifiedName = next(iter(fqn_set)) # type: ignore
if fqn.name in self.context.scratch[BASE_MODEL_CONTEXT_KEY]:
if self.context.scratch[CONTEXT_KEY].get(fqn.name, False):
self.inside_base_model = True

def leave_ClassDef(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.ClassDef:
Expand Down Expand Up @@ -94,7 +92,6 @@ def leave_AnnAssign(self, original_node: cst.AnnAssign, updated_node: cst.AnnAss
from tempfile import TemporaryDirectory

from libcst.metadata import FullRepoManager
from rich.pretty import pprint

with TemporaryDirectory(dir=os.getcwd()) as tmpdir:
package_dir = f"{tmpdir}/package"
Expand Down Expand Up @@ -123,11 +120,8 @@ class Bar(Foo):
wrapper = mrg.get_metadata_wrapper_for_path(module)
context = CodemodContext(wrapper=wrapper)

command = ClassDefVisitor(context=context)
mod = wrapper.visit(command)

find_base_model(scratch=context.scratch)
pprint(context.scratch)
# classes = run_mypy_visitor(context=context)
# mod = wrapper.visit(command)

command = AddDefaultNoneCommand(context=context) # type: ignore[assignment]
mod = wrapper.visit(command)
Expand Down
73 changes: 0 additions & 73 deletions bump_pydantic/codemods/class_def_visitor.py

This file was deleted.

52 changes: 52 additions & 0 deletions bump_pydantic/codemods/mypy_visitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from __future__ import annotations

import sys
from argparse import ArgumentParser

from mypy.build import build
from mypy.main import process_options
from mypy.nodes import ClassDef
from mypy.traverser import TraverserVisitor

CONTEXT_KEY = "mypy_visitor"


class MyPyVisitor(TraverserVisitor):
def __init__(self) -> None:
super().__init__()
self.classes: dict[str, bool] = {}

def visit_class_def(self, o: ClassDef) -> None:
super().visit_class_def(o)
self.classes[o.fullname] = o.info.has_base("pydantic.main.BaseModel")


def run_mypy_visitor(arg_files: list[str]) -> dict[str, bool]:
files, opt = process_options(arg_files, stdout=sys.stdout, stderr=sys.stderr)

opt.export_types = True
opt.incremental = True
opt.fine_grained_incremental = True
opt.cache_fine_grained = True
opt.allow_redefinition = True
opt.local_partial_types = True

result = build(files, opt, stdout=sys.stdout, stderr=sys.stderr)

visitor = MyPyVisitor()
classes: dict[str, bool] = {}

for file in files:
tree = result.graph[file.module].tree
if tree:
tree.accept(visitor=visitor)
classes.update(visitor.classes)
return classes


if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("files", nargs="+")
args = parser.parse_args()

run_mypy_visitor(args.files)
Loading