8000 Fail-fast on missing builtins (#14550) · python/mypy@f31d162 · GitHub
[go: up one dir, main page]

Skip to content

Commit f31d162

Browse files
authored
Fail-fast on missing builtins (#14550)
As discussed in #14547, some mypy features were degrading rather than failing-fast when certain built-in types (list, dict) were not present in the test environment. - The degraded state (e.g. lack of `__annotations__`) didn't make the culprit (sparse fixture) obvious, making tests harder to debug. - Having the code work around quirks of the testing environment ("sparse fixtures") is an anti-pattern.
1 parent 8e9f89a commit f31d162

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+131
-82
lines changed

mypy/messages.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,6 @@
122122
# test-data/unit/fixtures/) that provides the definition. This is used for
123123
# generating better error messages when running mypy tests only.
124124
SUGGESTED_TEST_FIXTURES: Final = {
125-
"builtins.list": "list.pyi",
126-
"builtins.dict": "dict.pyi",
127125
"builtins.set": "set.pyi",
128126
"builtins.tuple": "tuple.pyi",
129127
"builtins.bool": "bool.pyi",

mypy/semanal.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -625,23 +625,23 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None:
625625
continue
626626
# Need to construct the type ourselves, to avoid issues with __builtins__.list
627627
# not being subscriptable or typing.List not getting bound
628-
sym = self.lookup_qualified("__builtins__.list", Context())
629-
if not sym:
630-
continue
631-
node = sym.node
632-
if not isinstance(node, TypeInfo):
633-
self.defer(node)
628+
inst = self.named_type_or_none("builtins.list", [str_type])
629+
if inst is None:
630+
assert not self.final_iteration, "Cannot find builtins.list to add __path__"
631+
self.defer()
634632
return
635-
typ = Instance(node, [str_type])
633+
typ = inst
636634
elif name == "__annotations__":
637-
sym = self.lookup_qualified("__builtins__.dict", Context(), suppress_errors=True)
638-
if not sym:
639-
continue
640-
node = sym.node
641-
if not isinstance(node, TypeInfo):
642-
self.defer(node)
635+
inst = self.named_type_or_none(
636+
"builtins.dict", [str_type, AnyType(TypeOfAny.special_form)]
637+
)
638+
if inst is None:
639+
assert (
640+
not self.final_iteration
641+
), "Cannot find builtins.dict to add __annotations__"
642+
self.defer()
643643
return
644-
typ = Instance(node, [str_type, AnyType(TypeOfAny.special_form)])
644+
typ = inst
645645
else:
646646
assert t is not None, f"type should be specified for {name}"
647647
typ = UnboundType(t)

mypy/semanal_namedtuple.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,9 @@ def build_namedtuple_typeinfo(
481481
strtype = self.api.named_type("builtins.str")
482482
implicit_any = AnyType(TypeOfAny.special_form)
483483
basetuple_type = self.api.named_type("builtins.tuple", [implicit_any])
484-
dictype = self.api.named_type_or_none(
485-
"builtins.dict", [strtype, implicit_any]
486-
) or self.api.named_type("builtins.object")
484+
dictype = self.api.named_type("builtins.dict", [strtype, implicit_any])
487485
# Actual signature should return OrderedDict[str, Union[types]]
488-
ordereddictype = self.api.named_type_or_none(
489-
"builtins.dict", [strtype, implicit_any]
490-
) or self.api.named_type("builtins.object")
486+
ordereddictype = self.api.named_type("builtins.dict", [strtype, implicit_any])
491487
fallback = self.api.named_type("builtins.tuple", [implicit_any])
492488
# Note: actual signature should accept an invariant version of Iterable[UnionType[types]].
493489
# but it can't be expressed. 'new' and 'len' should be callable types.

test-data/unit/check-dynamic-typing.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class int: pass
147147
class type: pass
148148
class function: pass
149149
class str: pass
150+
class dict: pass
150151

151152
[case testBinaryOperationsWithDynamicAsRightOperand]
152153
from typing import Any
@@ -219,6 +220,7 @@ class int: pass
219220
class type: pass
220221
class function: pass
221222
class str: pass
223+
class dict: pass
222224

223225
[case testDynamicWithUnaryExpressions]
224226
from typing import Any

test-data/unit/check-generics.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,7 @@ class type: pass
13311331
class tuple: pass
13321332
class function: pass
13331333
class str: pass
1334+
class dict: pass
13341335

13351336
[case testMultipleAssignmentWithIterable]
13361337
from typing import Iterable, TypeVar

test-data/unit/check-incomplete-fixture.test

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ import m
1212
m.x # E: "object" has no attribute "x"
1313
[file m.py]
1414

15-
[case testDictMissingFromStubs]
16-
from typing import Dict
17-
def f(x: Dict[int]) -> None: pass
18-
[out]
19-
main:1: error: Module "typing" has no attribute "Dict"
20-
main:1: note: Maybe your test fixture does not define "builtins.dict"?
21-
main:1: note: Consider adding [builtins fixtures/dict.pyi] to your test description
22-
2315
[case testSetMissingFromStubs]
2416
from typing import Set
2517
def f(x: Set[int]) -> None: pass

test-data/unit/check-tuples.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ class str: pass
774774
class bool: pass
775775
class type: pass
776776
class function: pass
777+
class dict: pass
777778

778779

779780
-- For loop over tuple

test-data/unit/cmdline.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,8 @@ a.py:2: note: By default the bodies of untyped functions are not checked, consid
15161516
class object: pass
15171517
class str(object): pass
15181518
class int(object): pass
1519+
class list: pass
1520+
class dict: pass
15191521
[file dir/stdlib/sys.pyi]
15201522
[file dir/stdlib/types.pyi]
15211523
[file dir/stdlib/typing.pyi]

test-data/unit/fine-grained.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,8 +1809,8 @@ def f() -> Iterator[None]:
18091809
[typing fixtures/typing-medium.pyi]
18101810
[builtins fixtures/list.pyi]
18111811
[triggered]
1812-
2: <b>, __main__
1813-
3: <b>, __main__, a
1812+
2: <b>, <b[wildcard]>, __main__
1813+
3: <b>, <b[wildcard]>, __main__, a
18141814
[out]
18151815
main:2: note: Revealed type is "contextlib.GeneratorContextManager[None]"
18161816
==

test-data/unit/fixtures/__init_subclass__.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ class int: pass
1111
class bool: pass
1212
class str: pass
1313
class function: pass
14+
class dict: pass

test-data/unit/fixtures/__new__.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ class int: pass
1616
class bool: pass
1717
class str: pass
1818
class function: pass
19+
class dict: pass

test-data/unit/fixtures/alias.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ class str: pass
1212
class function: pass
1313

1414
bytes = str
15+
16+
class dict: pass

test-data/unit/fixtures/any.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ class int: pass
66
class str: pass
77

88
def any(i: Iterable[T]) -> bool: pass
9+
10+
class dict: pass

test-data/unit/fixtures/attr.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ class complex:
2525
class str: pass
2626
class ellipsis: pass
2727
class tuple: pass
28+
class list: pass
29+
class dict: pass

test-data/unit/fixtures/bool.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ class str: pass
1717
class ellipsis: pass
1818
class list(Generic[T]): pass
1919
class property: pass
20+
class dict: pass

test-data/unit/fixtures/callable.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ class str:
2828
def __eq__(self, other: 'str') -> bool: pass
2929
class ellipsis: pass
3030
class list: ...
31+
class dict: pass

test-data/unit/fixtures/classmethod.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ class bool: pass
2626
class ellipsis: pass
2727

2828
class tuple(typing.Generic[_T]): pass
29+
30+
class list: pass
31+
class dict: pass

test-data/unit/fixtures/complex.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ class int: pass
1010
class float: pass
1111
class complex: pass
1212
class str: pass
13+
class dict: pass

test-data/unit/fixtures/complex_tuple.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ class float: pass
1313
class complex: pass
1414
class str: pass
1515
class ellipsis: pass
16+
class dict: pass

test-data/unit/fixtures/divmod.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ class ellipsis: pass
1919

2020
_N = TypeVar('_N', int, float)
2121
def divmod(_x: _N, _y: _N) -> Tuple[_N, _N]: ...
22+
23+
class dict: pass

test-data/unit/fixtures/exception.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class object:
88
class type: pass
99
class tuple(Generic[T]):
1010
def __ge__(self, other: object) -> bool: ...
11+
class list: pass
12+
class dict: pass
1113
class function: pass
1214
class int: pass
1315
class str: pass

test-data/unit/fixtures/f_str 4380 ing.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ class str:
3434
def format(self, *args) -> str: pass
3535
def join(self, l: List[str]) -> str: pass
3636

37+
38+
class dict: pass

test-data/unit/fixtures/fine_grained.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ class tuple(Generic[T]): pass
2727
class function: pass
2828
class ellipsis: pass
2929
class list(Generic[T]): pass
30+
class dict: pass

test-data/unit/fixtures/float.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ class float:
3434
def __int__(self) -> int: ...
3535
def __mul__(self, x: float) -> float: ...
3636
def __rmul__(self, x: float) -> float: ...
37+
38+
class dict: pass

test-data/unit/fixtures/for.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ class str: pass # for convenience
1818

1919
class list(Iterable[t], Generic[t]):
2020
def __iter__(self) -> Iterator[t]: pass
21+
class dict: pass

test-data/unit/fixtures/function.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ class type: pass
55
class function: pass
66
class int: pass
77
class str: pass
8+
class dict: pass

test-data/unit/fixtures/isinstance.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ class str:
2525
class ellipsis: pass
2626

2727
NotImplemented = cast(Any, None)
28+
29+
class dict: pass

test-data/unit/fixtures/isinstance_python3_10.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ class str:
2727
class ellipsis: pass
2828

2929
NotImplemented = cast(Any, None)
30+
31+
class dict: pass

test-data/unit/fixtures/list.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ class str:
3636
class bool(int): pass
3737

3838
property = object() # Dummy definition.
39+
40+
class dict: pass

test-data/unit/fixtures/module_all.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ class list(Generic[_T], Sequence[_T]):
1616
def __add__(self, rhs: Sequence[_T]) -> list[_T]: pass
1717
class tuple(Generic[_T]): pass
1818
class ellipsis: pass
19+
class dict: pass

test-data/unit/fixtures/notimplemented.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ class bool: pass
1111
class int: pass
1212
class str: pass
1313
NotImplemented = cast(Any, None)
14+
class dict: pass

test-data/unit/fixtures/object_hashable.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ class float: ...
77
class str: ...
88
class ellipsis: ...
99
class tuple: ...
10+
class dict: pass

test-data/unit/fixtures/ops.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,5 @@ def __print(a1: object = None, a2: object = None, a3: object = None,
7272
a4: object = None) -> None: pass
7373

7474
class ellipsis: pass
75+
76+
class dict: pass

test-data/unit/fixtures/property.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class function: pass
1313
property = object() # Dummy definition
1414
class classmethod: pass
1515

16+
class list: pass
1617
class dict: pass
1718
class int: pass
1819
class str: pass

test-data/unit/fixtures/set.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ class set(Iterable[T], Generic[T]):
2525
def add(self, x: T) -> None: pass
2626
def discard(self, x: T) -> None: pass
2727
def update(self, x: Set[T]) -> None: pass
28+
29+
class dict: pass

test-data/unit/fixtures/slice.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ class str: pass
1414

1515
class slice: pass
1616
class ellipsis: pass
17+
class dict: pass

test-data/unit/fixtures/staticmethod.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ class int:
1818
class str: pass
1919
class bytes: pass
2020
class ellipsis: pass
21+
class dict: pass

test-data/unit/fixtures/transform.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ def __print(a1=None, a2=None, a3=None, a4=None):
2828
# Do not use *args since this would require list and break many test
2929
# cases.
3030
pass
31+
32+
class dict: pass

test-data/unit/fixtures/tuple-simple.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ class function: pass
1818
# We need int for indexing tuples.
1919
class int: pass
2020
class str: pass # For convenience
21+
class dict: pass

test-data/unit/fixtures/tuple.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ def isinstance(x: object, t: type) -> bool: pass
5151
def sum(iterable: Iterable[T], start: Optional[T] = None) -> T: pass
5252

5353
class BaseException: pass
54+
55+
class dict: pass

test-data/unit/fixtures/union.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ class tuple(Generic[T]): pass
1515
# We need int for indexing tuples.
1616
class int: pass
1717
class str: pass # For convenience
18+
class dict: pass

test-data/unit/lib-stub/builtins.pyi

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ class function:
2121
__name__: str
2222
class ellipsis: pass
2323

24-
from typing import Generic, Sequence, TypeVar
24+
from typing import Generic, Iterator, Sequence, TypeVar
2525
_T = TypeVar('_T')
26-
class list(Generic[_T], Sequence[_T]): pass
26+
class list(Generic[_T], Sequence[_T]):
27+
def __contains__(self, item: object) -> bool: pass
28+
def __getitem__(self, key: int) -> _T: pass
29+
def __iter__(self) -> Iterator[_T]: pass
30+
31+
class dict: pass
2732

2833
# Definition of None is implicit

0 commit comments

Comments
 (0)
0