Repository: quora/pyanalyze
Pull request #823 (2024-10-11 01:32:51)

Modernize representation of types


Patch:
diff --git a/pyanalyze/value.py b/pyanalyze/value.py
index 58a7690..91cbbdb 100644
--- a/pyanalyze/value.py
+++ b/pyanalyze/value.py
@@ -1923,7 +1923,7 @@ class SubclassValue(Value):
             return AnyValue(AnySource.inference)
 
     def __str__(self) -> str:
-        return f"Type[{self.typ}]"
+        return f"type[{self.typ}]"
 
     @classmethod
     def make(cls, origin: Value, *, exactly: bool = False) -> Value:
@@ -2087,15 +2087,13 @@ class MultiValuedValue(Value):
             body = ", ".join(repr(val.val) for val in literals)
             return f"Literal[{body}]"
         else:
-            if not literals and has_none and len(others) == 1:
-                return f"Optional[{others[0]}]"
             elements = [str(val) for val in others]
             if literals:
                 body = ", ".join(repr(val.val) for val in literals)
                 elements.append(f"Literal[{body}]")
             if has_none:
                 elements.append("None")
-            return f"Union[{', '.join(elements)}]"
+            return " | ".join(elements)
 
     def walk_values(self) -> Iterable["Value"]:
         yield self
@@ -2233,10 +2231,10 @@ class TypeVarValue(Value):
 
     def __str__(self) -> str:
         if self.bound is not None:
-            return f"{self.typevar} <: {self.bound}"
+            return f"{self.typevar}: {self.bound}"
         elif self.constraints:
             constraints = ", ".join(map(str, self.constraints))
-            return f"{self.typevar} in ({constraints})"
+            return f"{self.typevar}: ({constraints})"
         return str(self.typevar)
 
 


Test patch:
diff --git a/pyanalyze/test_value.py b/pyanalyze/test_value.py
index 42aa4a7..b47b5cf 100644
--- a/pyanalyze/test_value.py
+++ b/pyanalyze/test_value.py
@@ -204,7 +204,7 @@ def test_subclass_value() -> None:
     assert_can_assign(val, TypedValue(type))
     assert_cannot_assign(val, SubclassValue(TypedValue(str)))
     val = SubclassValue(TypedValue(str))
-    assert "Type[str]" == str(val)
+    assert str(val) == "type[str]"
     assert TypedValue(str) == val.typ
     assert val.is_type(str)
     assert not val.is_type(int)
@@ -288,7 +288,7 @@ def test_multi_valued_value() -> None:
         [TypedValue(int), KnownValue(None), TypedValue(str)]
     ) == val | TypedValue(str)
 
-    assert "Optional[int]" == str(val)
+    assert str(val) == "int | None"
     assert_can_assign(val, KnownValue(1))
     assert_can_assign(val, KnownValue(None))
     assert_cannot_assign(val, KnownValue(""))
@@ -299,20 +299,23 @@ def test_multi_valued_value() -> None:
         val, AnyValue(AnySource.marker) | TypedValue(int) | KnownValue(None)
     )
 
-    assert "Literal[1, 2]" == str(KnownValue(1) | KnownValue(2))
-    assert "Literal[1, 2, None]" == str(
-        KnownValue(1) | KnownValue(2) | KnownValue(None)
+    assert str(KnownValue(1) | KnownValue(2)) == "Literal[1, 2]"
+    assert (
+        str(KnownValue(1) | KnownValue(2) | KnownValue(None)) == "Literal[1, 2, None]"
     )
-    assert "Union[int, str]" == str(TypedValue(int) | TypedValue(str))
-    assert "Union[int, str, None]" == str(
-        TypedValue(int) | TypedValue(str) | KnownValue(None)
+    assert str(TypedValue(int) | TypedValue(str)) == "int | str"
+    assert (
+        str(TypedValue(int) | TypedValue(str) | KnownValue(None)) == "int | str | None"
     )
-    assert "Union[int, str, Literal[1, 2], None]" == str(
-        TypedValue(int)
-        | TypedValue(str)
-        | KnownValue(None)
-        | KnownValue(1)
-        | KnownValue(2)
+    assert (
+        str(
+            TypedValue(int)
+            | TypedValue(str)
+            | KnownValue(None)
+            | KnownValue(1)
+            | KnownValue(2)
+        )
+        == "int | str | Literal[1, 2] | None"
     )