1414
1515"""Tests for Template class."""
1616
17- import shutil
1817from typing import Any , Optional
1918from uuid import uuid4
2019
2928from rewrite .python .template .engine import TemplateEngine
3029from rewrite .python .template .replacement import maybe_parenthesize
3130from rewrite .python .visitor import PythonVisitor
32- from rewrite .test import RecipeSpec , python , pyproject , uv
31+ from rewrite .test import RecipeSpec , python
3332from rewrite .visitor import Cursor
3433
3534
@@ -660,37 +659,36 @@ def test_builder_with_dependencies(self):
660659 assert tmpl ._options .dependencies == (("requests" , "2.31.0" ),)
661660
662661
663- @pytest .mark .skipif (not shutil .which ("uv" ), reason = "uv not installed" )
664662class TestTypeAttributedPatternMatching :
665663 """Integration tests for pattern matching with type attribution.
666664
667- These tests verify that uv() + pyproject() + pattern(dependencies=...)
668- produce type-attributed ASTs that the 3-layer comparator can use for
669- FQN-based semantic matching.
665+ These tests use stdlib ``json.dumps`` (no external dependencies) to verify
666+ that type-attributed ASTs enable FQN-based semantic matching in the 3-layer
667+ comparator. ``ty`` consistently resolves ``json.dumps`` to
668+ ``declaring_fqn=json`` regardless of import style.
670669 """
671670
672671 def test_fqn_match_different_import_styles (self ):
673672 """Pattern matches code that uses a different import style via FQN.
674673
675- Code uses ``from six import ensure_str; ensure_str (x)`` (bare name).
676- Pattern uses ``six.ensure_str ({val})`` (qualified name).
674+ Code uses ``from json import dumps; dumps (x)`` (bare name).
675+ Pattern uses ``json.dumps ({val})`` (qualified name).
677676 Without type attribution, these would NOT structurally match because
678- the select (None vs Identifier("six ")) differs. With type attribution,
679- Layer 2 FQN matching detects both resolve to ``six.ensure_str `` and
677+ the select (None vs Identifier("json ")) differs. With type attribution,
678+ Layer 2 FQN matching detects both resolve to ``json.dumps `` and
680679 skips the select comparison.
681680 """
682681 val = capture ('val' )
683682 pat = pattern (
684- f"six.ensure_str({ val } )" ,
685- imports = ["import six" ],
686- dependencies = {"six" : "1.17.0" },
683+ f"json.dumps({ val } )" ,
684+ context = ["import json" ],
687685 )
688686 tmpl = template (f"str({ val } )" )
689687
690- class ReplaceSixEnsureStr (Recipe ):
688+ class ReplaceJsonDumps (Recipe ):
691689 @property
692690 def name (self ):
693- return "test.ReplaceSixEnsureStr "
691+ return "test.ReplaceJsonDumps "
694692
695693 @property
696694 def display_name (self ):
@@ -710,53 +708,41 @@ def visit_method_invocation(self, method, p):
710708 return method
711709 return Visitor ()
712710
713- spec = RecipeSpec (recipe = ReplaceSixEnsureStr ())
711+ spec = RecipeSpec (recipe = ReplaceJsonDumps ())
714712 spec .rewrite_run (
715- * uv (
716- pyproject (
717- """
718- [project]
719- name = "test"
720- version = "0.0.0"
721- requires-python = ">=3.10"
722- dependencies = ["six==1.17.0"]
723- """
724- ),
725- python (
726- """
727- from six import ensure_str
728- x = ensure_str("hello")
729- """ ,
730- """
731- from six import ensure_str
732- x = str("hello")
733- """ ,
734- ),
735- )
713+ python (
714+ """
715+ from json import dumps
716+ x = dumps({"key": "value"})
717+ """ ,
718+ """
719+ from json import dumps
720+ x = str({"key": "value"})
721+ """ ,
722+ ),
736723 )
737724
738725 def test_fqn_match_with_aliased_import (self ):
739726 """Pattern matches code that uses an aliased import via FQN.
740727
741- Code uses ``import six as s; s.ensure_str (x)`` (aliased select ``s ``).
742- Pattern uses ``six.ensure_str ({val})`` (canonical select ``six ``).
743- Without type attribution, ``Identifier("s ")`` != ``Identifier("six ")``
728+ Code uses ``import json as j; j.dumps (x)`` (aliased select ``j ``).
729+ Pattern uses ``json.dumps ({val})`` (canonical select ``json ``).
730+ Without type attribution, ``Identifier("j ")`` != ``Identifier("json ")``
744731 so the structural comparison would fail. With type attribution,
745- Layer 2 FQN matching detects both resolve to ``six.ensure_str ``
732+ Layer 2 FQN matching detects both resolve to ``json.dumps ``
746733 and skips the select comparison entirely.
747734 """
748735 val = capture ('val' )
749736 pat = pattern (
750- f"six.ensure_str({ val } )" ,
751- imports = ["import six" ],
752- dependencies = {"six" : "1.17.0" },
737+ f"json.dumps({ val } )" ,
738+ context = ["import json" ],
753739 )
754740 tmpl = template (f"str({ val } )" )
755741
756- class ReplaceSixEnsureStr (Recipe ):
742+ class ReplaceJsonDumps (Recipe ):
757743 @property
758744 def name (self ):
759- return "test.ReplaceSixEnsureStr "
745+ return "test.ReplaceJsonDumps "
760746
761747 @property
762748 def display_name (self ):
@@ -776,27 +762,16 @@ def visit_method_invocation(self, method, p):
776762 return method
777763 return Visitor ()
778764
779- spec = RecipeSpec (recipe = ReplaceSixEnsureStr ())
765+ spec = RecipeSpec (recipe = ReplaceJsonDumps ())
780766 spec .rewrite_run (
781- * uv (
782- pyproject (
783- """
784- [project]
785- name = "test"
786- version = "0.0.0"
787- requires-python = ">=3.10"
788- dependencies = ["six==1.17.0"]
789- """
790- ),
791- python (
792- """
793- import six as s
794- x = s.ensure_str("hello")
795- """ ,
796- """
797- import six as s
798- x = str("hello")
799- """ ,
800- ),
801- )
767+ python (
768+ """
769+ import json as j
770+ x = j.dumps({"key": "value"})
771+ """ ,
772+ """
773+ import json as j
774+ x = str({"key": "value"})
775+ """ ,
776+ ),
802777 )
0 commit comments