Skip to content

Commit 2b8691d

Browse files
authored
Add tests for Literal types with incremental and fine-grained mode (#6075)
This pull request adds a variety of tests for Literal types and incremental and fine-grained mode. Most of the tests are relatively simple: the most complex ones focus on testing chained references to literal types and various shenanigans with str/unicode/bytes. It also removes one assert from the `visit_raw_literal` function in astmerge's TypeReplaceVisitor: it turned out it'll sometimes visit unanalyzed types.
1 parent 25b83ea commit 2b8691d

File tree

7 files changed

+611
-2
lines changed

7 files changed

+611
-2
lines changed

mypy/server/astmerge.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,12 @@ def replace_statements(self, nodes: List[Statement]) -> List[Statement]:
328328

329329

330330
class TypeReplaceVisitor(SyntheticTypeVisitor[None]):
331-
"""Similar to NodeReplaceVisitor, but for type objects."""
331+
"""Similar to NodeReplaceVisitor, but for type objects.
332+
333+
Note: this visitor may sometimes visit unanalyzed types
334+
such as 'UnboundType' and 'RawLiteralType' For example, see
335+
NodeReplaceVisitor.process_base_func.
336+
"""
332337

333338
def __init__(self, replacements: Dict[SymbolNode, SymbolNode]) -> None:
334339
self.replacements = replacements
@@ -393,7 +398,7 @@ def visit_typeddict_type(self, typ: TypedDictType) -> None:
393398
typ.fallback.accept(self)
394399

395400
def visit_raw_literal_type(self, t: RawLiteralType) -> None:
396-
assert False, "Unexpected RawLiteralType after semantic analysis phase"
401+
pass
397402

398403
def visit_literal_type(self, typ: LiteralType) -> None:
399404
typ.fallback.accept(self)

mypy/test/testmerge.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
'contextlib',
3939
'sys',
4040
'mypy_extensions',
41+
'typing_extensions',
4142
'enum',
4243
)
4344

test-data/unit/check-incremental.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4890,3 +4890,17 @@ python_version=3.6
48904890
[out]
48914891
[out2]
48924892
tmp/a.py:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")
4893+
4894+
[case testLiteralIncrementalTurningIntoLiteral]
4895+
import mod
4896+
reveal_type(mod.a)
4897+
[file mod.py]
4898+
from typing_extensions import Literal
4899+
a = 1
4900+
[file mod.py.2]
4901+
from typing_extensions import Literal
4902+
a: Literal[2] = 2
4903+
[out]
4904+
main:2: error: Revealed type is 'builtins.int'
4905+
[out2]
4906+
main:2: error: Revealed type is 'Literal[2]'

test-data/unit/deps-expressions.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,19 @@ def g() -> None:
448448
[out]
449449
<m.f1> -> m.g
450450
<m.f2> -> m.g
451+
452+
[case testLiteralDepsExpr]
453+
from typing_extensions import Literal
454+
455+
Alias = Literal[1]
456+
457+
a: Alias
458+
b = a
459+
def f(x: Alias) -> None: pass
460+
def g() -> Literal[1]:
461+
return b
462+
[out]
463+
<m.Alias> -> m, m.f
464+
<m.a> -> m
465+
<m.b> -> m, m.g
466+
<typing_extensions.Literal> -> m

test-data/unit/diff.test

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,3 +1109,302 @@ plugins=<ROOT>/test-data/unit/plugins/dyn_class.py
11091109
[out]
11101110
__main__.Diff
11111111
__main__.Diff.x
1112+
1113+
[case testLiteralTriggersVar]
1114+
from typing_extensions import Literal
1115+
1116+
x: Literal[1] = 1
1117+
y = 1
1118+
z: Literal[1] = 1
1119+
same: Literal[1] = 1
1120+
class C:
1121+
x_class: Literal[1] = 1
1122+
y_class = 1
1123+
z_class: Literal[1] = 1
1124+
same_class: Literal[1] = 1
1125+
def __init__(self) -> None:
1126+
self.x_instance: Literal[1] = 1
1127+
self.y_instance = 1
1128+
self.z_instance: Literal[1] = 1
1129+
self.same_instance: Literal[1] = 1
1130+
1131+
[file next.py]
1132+
from typing_extensions import Literal
1133+
1134+
x = 1
1135+
y: Literal[1] = 1
1136+
z: Literal[2] = 2
1137+
same: Literal[1] = 1
1138+
class C:
1139+
x_class = 1
1140+
y_class: Literal[1] = 1
1141+
z_class: Literal[2] = 2
1142+
same_class: Literal[1] = 1
1143+
def __init__(self) -> None:
1144+
self.x_instance = 1
1145+
self.y_instance: Literal[1] = 1
1146+
self.z_instance: Literal[2] = 2
1147+
self.same_instance: Literal[1] = 1
1148+
[out]
1149+
__main__.C.x_class
1150+
__main__.C.x_instance
1151+
__main__.C.y_class
1152+
__main__.C.y_instance
1153+
__main__.C.z_class
1154+
__main__.C.z_instance
1155+
__main__.x
1156+
__main__.y
1157+
__main__.z
1158+
1159+
[case testLiteralTriggersFunctions]
1160+
from typing_extensions import Literal
1161+
1162+
def function_1() -> int: pass
1163+
def function_2() -> Literal[1]: pass
1164+
def function_3() -> Literal[1]: pass
1165+
1166+
def function_4(x: int) -> None: pass
1167+
def function_5(x: Literal[1]) -> None: pass
1168+
def function_6(x: Literal[1]) -> None: pass
1169+
1170+
def function_same_1() -> Literal[1]: pass
1171+
def function_same_2(x: Literal[1]) -> None: pass
1172+
1173+
class C:
1174+
def method_1(self) -> int: pass
1175+
def method_2(self) -> Literal[1]: pass
1176+
def method_3(self) -> Literal[1]: pass
1177+
1178+
def method_4(self, x: int) -> None: pass
1179+
def method_5(self, x: Literal[1]) -> None: pass
1180+
def method_6(self, x: Literal[1]) -> None: pass
1181+
1182+
def method_same_1(self) -> Literal[1]: pass
1183+
def method_same_2(self, x: Literal[1]) -> None: pass
1184+
1185+
@classmethod
1186+
def classmethod_1(cls) -> int: pass
1187+
@classmethod
1188+
def classmethod_2(cls) -> Literal[1]: pass
1189+
@classmethod
1190+
def classmethod_3(cls) -> Literal[1]: pass
1191+
1192+
@classmethod
1193+
def classmethod_4(cls, x: int) -> None: pass
1194+
@classmethod
1195+
def classmethod_5(cls, x: Literal[1]) -> None: pass
1196+
@classmethod
1197+
def classmethod_6(cls, x: Literal[1]) -> None: pass
1198+
1199+
@classmethod
1200+
def classmethod_same_1(cls) -> Literal[1]: pass
1201+
@classmethod
1202+
def classmethod_same_2(cls, x: Literal[1]) -> None: pass
1203+
1204+
@staticmethod
1205+
def staticmethod_1() -> int: pass
1206+
@staticmethod
1207+
def staticmethod_2() -> Literal[1]: pass
1208+
@staticmethod
1209+
def staticmethod_3() -> Literal[1]: pass
1210+
1211+
@staticmethod
1212+
def staticmethod_4(x: int) -> None: pass
1213+
@staticmethod
1214+
def staticmethod_5(x: Literal[1]) -> None: pass
1215+
@staticmethod
1216+
def staticmethod_6(x: Literal[1]) -> None: pass
1217+
1218+
@staticmethod
1219+
def staticmethod_same_1() -> Literal[1]: pass
1220+
@staticmethod
1221+
def staticmethod_same_2(x: Literal[1]) -> None: pass
1222+
1223+
[file next.py]
1224+
from typing_extensions import Literal
1225+
1226+
def function_1() -> Literal[1]: pass
1227+
def function_2() -> int: pass
1228+
def function_3() -> Literal[2]: pass
1229+
1230+
def function_4(x: Literal[1]) -> None: pass
1231+
def function_5(x: int) -> None: pass
1232+
def function_6(x: Literal[2]) -> None: pass
1233+
1234+
def function_same_1() -> Literal[1]: pass
1235+
def function_same_2(x: Literal[1]) -> None: pass
1236+
1237+
class C:
1238+
def method_1(self) -> Literal[1]: pass
1239+
def method_2(self) -> int: pass
1240+
def method_3(self) -> Literal[2]: pass
1241+
1242+
def method_4(self, x: Literal[1]) -> None: pass
1243+
def method_5(self, x: int) -> None: pass
1244+
def method_6(self, x: Literal[2]) -> None: pass
1245+
1246+
def method_same_1(self) -> Literal[1]: pass
1247+
def method_same_2(self, x: Literal[1]) -> None: pass
1248+
1249+
@classmethod
1250+
def classmethod_1(cls) -> Literal[1]: pass
1251+
@classmethod
1252+
def classmethod_2(cls) -> int: pass
1253+
@classmethod
1254+
def classmethod_3(cls) -> Literal[2]: pass
1255+
1256+
@classmethod
1257+
def classmethod_4(cls, x: Literal[1]) -> None: pass
1258+
@classmethod
1259+
def classmethod_5(cls, x: int) -> None: pass
1260+
@classmethod
1261+
def classmethod_6(cls, x: Literal[2]) -> None: pass
1262+
1263+
@classmethod
1264+
def classmethod_same_1(cls) -> Literal[1]: pass
1265+
@classmethod
1266+
def classmethod_same_2(cls, x: Literal[1]) -> None: pass
1267+
1268+
@staticmethod
1269+
def staticmethod_1() -> Literal[1]: pass
1270+
@staticmethod
1271+
def staticmethod_2() -> int: pass
1272+
@staticmethod
1273+
def staticmethod_3() -> Literal[2]: pass
1274+
1275+
@staticmethod
1276+
def staticmethod_4(x: Literal[1]) -> None: pass
1277+
@staticmethod
1278+
def staticmethod_5(x: int) -> None: pass
1279+
@staticmethod
1280+
def staticmethod_6(x: Literal[2]) -> None: pass
1281+
1282+
@staticmethod
1283+
def staticmethod_same_1() -> Literal[1]: pass
1284+
@staticmethod
1285+
def staticmethod_same_2(x: Literal[1]) -> None: pass
1286+
[builtins fixtures/classmethod.pyi]
1287+
[out]
1288+
__main__.C.classmethod_1
1289+
__main__.C.classmethod_2
1290+
__main__.C.classmethod_3
1291+
__main__.C.classmethod_4
1292+
__main__.C.classmethod_5
1293+
__main__.C.classmethod_6
1294+
__main__.C.method_1
1295+
__main__.C.method_2
1296+
__main__.C.method_3
1297+
__main__.C.method_4
1298+
__main__.C.method_5
1299+
__main__.C.method_6
1300+
__main__.C.staticmethod_1
1301+
__main__.C.staticmethod_2
1302+
__main__.C.staticmethod_3
1303+
__main__.C.staticmethod_4
1304+
__main__.C.staticmethod_5
1305+
__main__.C.staticmethod_6
1306+
__main__.function_1
1307+
__main__.function_2
1308+
__main__.function_3
1309+
__main__.function_4
1310+
__main__.function_5
1311+
__main__.function_6
1312+
1313+
[case testLiteralTriggersProperty]
1314+
from typing_extensions import Literal
1315+
1316+
class C:
1317+
@property
1318+
def p1(self) -> Literal[1]: pass
1319+
1320+
@property
1321+
def p2(self) -> int: pass
1322+
1323+
@property
1324+
def same(self) -> Literal[1]: pass
1325+
1326+
[file next.py]
1327+
from typing_extensions import Literal
1328+
1329+
class C:
1330+
@property
1331+
def p1(self) -> int: pass
1332+
1333+
@property
1334+
def p2(self) -> Literal[1]: pass
1335+
1336+
@property
1337+
def same(self) -> Literal[1]: pass
1338+
[builtins fixtures/property.pyi]
1339+
[out]
1340+
__main__.C.p1
1341+
__main__.C.p2
1342+
1343+
[case testLiteralsTriggersOverload]
1344+
from typing import overload
1345+
from typing_extensions import Literal
1346+
1347+
@overload
1348+
def func(x: str) -> str: ...
1349+
@overload
1350+
def func(x: Literal[1]) -> int: ...
1351+
def func(x):
1352+
pass
1353+
1354+
@overload
1355+
def func_same(x: str) -> str: ...
1356+
@overload
1357+
def func_same(x: Literal[1]) -> int: ...
1358+
def func_same(x):
1359+
pass
1360+
1361+
class C:
1362+
@overload
1363+
def method(self, x: str) -> str: ...
1364+
@overload
1365+
def method(self, x: Literal[1]) -> int: ...
1366+
def method(self, x):
1367+
pass
1368+
1369+
@overload
1370+
def method_same(self, x: str) -> str: ...
1371+
@overload
1372+
def method_same(self, x: Literal[1]) -> int: ...
1373+
def method_same(self, x):
1374+
pass
1375+
1376+
[file next.py]
1377+
from typing import overload
1378+
from typing_extensions import Literal
1379+
1380+
@overload
1381+
def func(x: str) -> str: ...
1382+
@overload
1383+
def func(x: Literal[2]) -> int: ...
1384+
def func(x):
1385+
pass
1386+
1387+
@overload
1388+
def func_same(x: str) -> str: ...
1389+
@overload
1390+
def func_same(x: Literal[1]) -> int: ...
1391+
def func_same(x):
1392+
pass
1393+
1394+
class C:
1395+
@overload
1396+
def method(self, x: str) -> str: ...
1397+
@overload
1398+
def method(self, x: Literal[2]) -> int: ...
1399+
def method(self, x):
1400+
pass
1401+
1402+
@overload
1403+
def method_same(self, x: str) -> str: ...
1404+
@overload
1405+
def method_same(self, x: Literal[1]) -> int: ...
1406+
def method_same(self, x):
1407+
pass
1408+
[out]
1409+
__main__.C.method
1410+
__main__.func

0 commit comments

Comments
 (0)