Skip to content

Commit e875d15

Browse files
committed
Merge remote-tracking branch 'upstream/master' into try-native-parser
2 parents e5fca3e + f91a89f commit e875d15

67 files changed

Lines changed: 2214 additions & 223 deletions

Some content is hidden

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

mypy-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ mypy_extensions>=1.0.0
66
pathspec>=1.0.0
77
tomli>=1.1.0; python_version<'3.11'
88
librt>=0.9.0; platform_python_implementation != 'PyPy'
9-
ast-serialize>=0.2.0,<1.0.0
9+
ast-serialize>=0.2.2,<1.0.0

mypy/binder.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from collections import defaultdict
44
from collections.abc import Iterator
55
from contextlib import contextmanager
6-
from typing import Literal, NamedTuple, TypeAlias as _TypeAlias
6+
from typing import Final, Literal, TypeAlias as _TypeAlias
77

88
from mypy.erasetype import remove_instance_last_known_values
99
from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash, subkeys
@@ -42,9 +42,10 @@
4242
BindableExpression: _TypeAlias = IndexExpr | MemberExpr | NameExpr
4343

4444

45-
class CurrentType(NamedTuple):
46-
type: Type
47-
from_assignment: bool
45+
class CurrentType:
46+
def __init__(self, type: Type, from_assignment: bool) -> None:
47+
self.type: Final = type
48+
self.from_assignment: Final = from_assignment
4849

4950

5051
class Frame:

mypy/build.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -913,20 +913,20 @@ def __init__(
913913
continue
914914
path = self.find_module_cache.find_module(module, fast_path=True)
915915
if not isinstance(path, str):
916-
raise CompileError(
917-
[f"Failed to find builtin module {module}, perhaps typeshed is broken?"]
916+
build_error(
917+
f'Failed to find builtin module "{module}", perhaps typeshed is broken?'
918918
)
919919
if is_typeshed_file(options.abs_custom_typeshed_dir, path) or is_stub_package_file(
920920
path
921921
):
922922
continue
923923

924-
raise CompileError(
925-
[
926-
f'mypy: "{os.path.relpath(path)}" shadows library module "{module}"',
927-
f'note: A user-defined top-level module with name "{module}" is not supported',
928-
]
924+
self.errors.set_file(path, module, options)
925+
self.error(None, f'This file shadows library module "{module}"', blocker=True)
926+
self.note(
927+
None, f'A user-defined top-level module with name "{module}" is not supported'
929928
)
929+
self.errors.raise_error()
930930

931931
if metastore is None:
932932
metastore = create_metastore(options, parallel_worker=parallel_worker)
@@ -1255,7 +1255,19 @@ def all_imported_modules_in_file(self, file: MypyFile) -> list[tuple[int, str, i
12551255
return res
12561256

12571257
def is_module(self, id: str) -> bool:
1258-
"""Is there a file in the file system corresponding to module id?"""
1258+
"""Does the given fullname refer to a module?
1259+
1260+
Note: this does not always verify that the module exists and relies on
1261+
previously executed logic in find_module_and_diagnose().
1262+
"""
1263+
if id in self.modules:
1264+
# Micro-optimization, if we already found it, it is definitely a module.
1265+
return True
1266+
if id in self.source_set.source_modules:
1267+
# Special case: if a module is passed on command line, we accept it even
1268+
# if we would not resolve it using regular mechanisms. This makes behavior
1269+
# consistent in cases like `mypy foo-stubs`, where stubs are not installed.
1270+
return True
12591271
return find_module_simple(id, self) is not None
12601272

12611273
def parse_file(
@@ -3149,7 +3161,7 @@ def get_source(self) -> str:
31493161
assert ioerr.errno is not None
31503162
raise CompileError(
31513163
[
3152-
"mypy: error: cannot read file '{}': {}".format(
3164+
"mypy: error: Cannot read file '{}': {}".format(
31533165
self.path.replace(os.getcwd() + os.sep, ""),
31543166
os.strerror(ioerr.errno),
31553167
)
@@ -3158,9 +3170,9 @@ def get_source(self) -> str:
31583170
) from ioerr
31593171
except (UnicodeDecodeError, DecodeError) as decodeerr:
31603172
if self.path.endswith(".pyd"):
3161-
err = f"{self.path}: error: stubgen does not support .pyd files"
3173+
err = f"{self.path}: error: Stubgen does not support .pyd files"
31623174
else:
3163-
err = f"{self.path}: error: cannot decode file: {str(decodeerr)}"
3175+
err = f"{self.path}: error: Cannot decode file: {str(decodeerr)}"
31643176
raise CompileError([err], module_with_blocker=self.id) from decodeerr
31653177
elif self.path and self.manager.fscache.isdir(self.path):
31663178
source = ""
@@ -3782,7 +3794,7 @@ def find_module_and_diagnose(
37823794
# If we can't find a root source it's always fatal.
37833795
# TODO: This might hide non-fatal errors from
37843796
# root sources processed earlier.
3785-
raise CompileError([f"mypy: can't find module '{id}'"])
3797+
raise CompileError([f'mypy: error: Cannot find module "{id}"'])
37863798
else:
37873799
raise ModuleNotFound
37883800

@@ -3911,7 +3923,7 @@ def module_not_found(
39113923
)
39123924
if target == "builtins":
39133925
manager.error(
3914-
line, "Cannot find 'builtins' module. Typeshed appears broken!", blocker=True
3926+
line, 'Cannot find "builtins" module. Typeshed appears broken!', blocker=True
39153927
)
39163928
errors.raise_error()
39173929
else:

mypy/build_worker/worker.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import platform
2424
import sys
2525
import time
26-
from typing import NamedTuple
26+
from typing import Final
2727

2828
from librt.internal import ReadBuffer, read_tag
2929

@@ -65,12 +65,20 @@
6565
CONNECTION_NAME = "build_worker"
6666

6767

68-
class ServerContext(NamedTuple):
69-
options: Options
70-
disable_error_code: list[str]
71-
enable_error_code: list[str]
72-
errors: Errors
73-
fscache: FileSystemCache
68+
class ServerContext:
69+
def __init__(
70+
self,
71+
options: Options,
72+
disable_error_code: list[str],
73+
enable_error_code: list[str],
74+
errors: Errors,
75+
fscache: FileSystemCache,
76+
) -> None:
77+
self.options: Final = options
78+
self.disable_error_code: Final = disable_error_code
79+
self.enable_error_code: Final = enable_error_code
80+
self.errors: Final = errors
81+
self.fscache: Final = fscache
7482

7583

7684
def main(argv: list[str]) -> None:

mypy/checker.py

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,11 @@ class FineGrainedDeferredNode(NamedTuple):
353353
# Keeps track of partial types in a single scope. In fine-grained incremental
354354
# mode partial types initially defined at the top level cannot be completed in
355355
# a function, and we use the 'is_function' attribute to enforce this.
356-
class PartialTypeScope(NamedTuple):
357-
map: dict[Var, Context]
358-
is_function: bool
359-
is_local: bool
356+
class PartialTypeScope:
357+
def __init__(self, map: dict[Var, Context], is_function: bool, is_local: bool) -> None:
358+
self.map: Final = map
359+
self.is_function: Final = is_function
360+
self.is_local: Final = is_local
360361

361362

362363
class LocalTypeMap:
@@ -1617,14 +1618,14 @@ def check_func_def(
16171618
else:
16181619
msg = message_registry.MISSING_RETURN_STATEMENT
16191620
if body_is_trivial:
1620-
msg = msg._replace(code=codes.EMPTY_BODY)
1621+
msg = ErrorMessage(msg.value, code=codes.EMPTY_BODY)
16211622
self.fail(msg, defn)
16221623
if may_be_abstract:
16231624
self.note(message_registry.EMPTY_BODY_ABSTRACT, defn)
16241625
else:
16251626
msg = message_registry.INCOMPATIBLE_RETURN_VALUE_TYPE
16261627
if body_is_trivial:
1627-
msg = msg._replace(code=codes.EMPTY_BODY)
1628+
msg = ErrorMessage(msg.value, code=codes.EMPTY_BODY)
16281629
# similar to code in check_return_stmt
16291630
if (
16301631
not self.check_subtype(
@@ -7208,14 +7209,23 @@ def replay_lookup(new_parent_type: ProperType) -> Type | None:
72087209
if int_literals is not None:
72097210

72107211
def replay_lookup(new_parent_type: ProperType) -> Type | None:
7211-
if not isinstance(new_parent_type, TupleType):
7212-
return None
7213-
try:
7214-
assert int_literals is not None
7215-
member_types = [new_parent_type.items[key] for key in int_literals]
7216-
except IndexError:
7217-
return None
7218-
return make_simplified_union(member_types)
7212+
if isinstance(new_parent_type, TupleType):
7213+
try:
7214+
assert int_literals is not None
7215+
member_types = [
7216+
new_parent_type.items[key] for key in int_literals
7217+
]
7218+
except IndexError:
7219+
return None
7220+
return make_simplified_union(member_types)
7221+
if (
7222+
isinstance(new_parent_type, Instance)
7223+
and new_parent_type.type.fullname
7224+
in ("builtins.list", "builtins.tuple")
7225+
and new_parent_type.args
7226+
):
7227+
return new_parent_type.args[0]
7228+
return None
72197229

72207230
else:
72217231
return output
@@ -7874,7 +7884,7 @@ def enter_partial_types(
78747884
self.options.check_untyped_defs and self.dynamic_funcs and self.dynamic_funcs[-1]
78757885
)
78767886

7877-
partial_types, _, _ = self.partial_types.pop()
7887+
partial_types = self.partial_types.pop().map
78787888
if not self.current_node_deferred:
78797889
for var, context in partial_types.items():
78807890
if isinstance(var.type, PartialType) and var.type.type is None and not permissive:
@@ -8914,24 +8924,9 @@ def reduce_and_conditional_type_maps(ms: list[TypeMap], *, use_meet: bool) -> Ty
89148924
return result
89158925

89168926

8917-
BUILTINS_CUSTOM_EQ_CHECKS: Final = {
8918-
"builtins.frozenset",
8919-
"_collections_abc.dict_keys",
8920-
"_collections_abc.dict_items",
8921-
}
8922-
8923-
89248927
def has_custom_eq_checks(t: Type) -> bool:
8925-
return (
8926-
custom_special_method(t, "__eq__", check_all=False)
8927-
or custom_special_method(t, "__ne__", check_all=False)
8928-
# custom_special_method has special casing for builtins.* and typing.* that make the
8929-
# above always return False. Some builtin collections still have equality behavior that
8930-
# crosses nominal type boundaries and isn't captured by VALUE_EQUALITY_TYPE_DOMAINS.
8931-
or (
8932-
isinstance(pt := get_proper_type(t), Instance)
8933-
and pt.type.fullname in BUILTINS_CUSTOM_EQ_CHECKS
8934-
)
8928+
return custom_special_method(t, "__eq__", check_all=False) or custom_special_method(
8929+
t, "__ne__", check_all=False
89358930
)
89368931

89378932

@@ -9721,6 +9716,8 @@ def visit_starred_pattern(self, p: StarredPattern) -> None:
97219716
"builtins.bytes": "builtins.bytes",
97229717
"builtins.bytearray": "builtins.bytes",
97239718
"builtins.memoryview": "builtins.bytes",
9719+
"typing.Mapping": "typing.Mapping",
9720+
"typing.AbstractSet": "typing.AbstractSet",
97249721
}
97259722

97269723
VALUE_EQUALITY_DOMAINS: Final = {**OPEN_VALUE_EQUALITY_DOMAINS, **CLOSED_VALUE_EQUALITY_DOMAINS}

mypy/checker_shared.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from abc import abstractmethod
66
from collections.abc import Iterator, Sequence, Set as AbstractSet
77
from contextlib import contextmanager
8-
from typing import NamedTuple, overload
8+
from typing import Final, overload
99

1010
from mypy_extensions import trait
1111

@@ -42,9 +42,10 @@
4242

4343
# An object that represents either a precise type or a type with an upper bound;
4444
# it is important for correct type inference with isinstance.
45-
class TypeRange(NamedTuple):
46-
item: Type
47-
is_upper_bound: bool # False => precise type
45+
class TypeRange:
46+
def __init__(self, item: Type, is_upper_bound: bool) -> None:
47+
self.item: Final = item
48+
self.is_upper_bound: Final = is_upper_bound # False => precise type
4849

4950

5051
@trait

mypy/infer.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
from collections.abc import Sequence
6-
from typing import NamedTuple
6+
from typing import Final
77

88
from mypy.constraints import (
99
SUBTYPE_OF,
@@ -16,7 +16,7 @@
1616
from mypy.types import CallableType, Instance, Type, TypeVarLikeType
1717

1818

19-
class ArgumentInferContext(NamedTuple):
19+
class ArgumentInferContext:
2020
"""Type argument inference context.
2121
2222
We need this because we pass around ``Mapping`` and ``Iterable`` types.
@@ -26,8 +26,9 @@ class ArgumentInferContext(NamedTuple):
2626
https://github.com/python/mypy/issues/11144
2727
"""
2828

29-
mapping_type: Instance
30-
iterable_type: Instance
29+
def __init__(self, mapping_type: Instance, iterable_type: Instance) -> None:
30+
self.mapping_type: Final = mapping_type
31+
self.iterable_type: Final = iterable_type
3132

3233

3334
def infer_function_type_arguments(

mypy/main.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,14 @@ def main(
101101
# Supporting both parsers would be really tricky, so just support the new one.
102102
options.native_parser = True
103103
if options.cache_dir == os.devnull:
104-
fail("error: cache must be enabled in parallel mode", stderr, options)
104+
fail("error: Cache must be enabled in parallel mode", stderr, options)
105+
if options.report_dirs:
106+
fail(
107+
"error: Reports are not supported in parallel mode yet\n"
108+
"note: Use -n0 to disable parallel checking",
109+
stderr,
110+
options,
111+
)
105112

106113
if options.allow_redefinition and not options.local_partial_types:
107114
fail(
@@ -1577,7 +1584,8 @@ def set_strict_flags() -> None:
15771584
reason = cache.find_module(p)
15781585
if reason is ModuleNotFoundReason.FOUND_WITHOUT_TYPE_HINTS:
15791586
fail(
1580-
f"Package '{p}' cannot be type checked due to missing py.typed marker. See https://mypy.readthedocs.io/en/stable/installed_packages.html for more details",
1587+
f"Package '{p}' cannot be type checked due to missing py.typed marker.\n"
1588+
"See https://mypy.readthedocs.io/en/stable/installed_packages.html for more details",
15811589
stderr,
15821590
options,
15831591
)
@@ -1698,7 +1706,7 @@ def read_types_packages_to_install(cache_dir: str, after_run: bool) -> list[str]
16981706
if not after_run:
16991707
sys.stderr.write(
17001708
"error: Can't determine which types to install with no files to check "
1701-
+ "(and no cache from previous mypy run)\n"
1709+
"(and no cache from previous mypy run)\n"
17021710
)
17031711
else:
17041712
sys.stderr.write(

mypy/meet.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
173173
return declared.copy_modified(
174174
upper_bound=narrow_declared_type(declared.upper_bound, original_narrowed)
175175
)
176+
elif (
177+
isinstance(narrowed, TypeVarType)
178+
and not has_type_vars(original_declared)
179+
and is_subtype(original_declared, narrowed.upper_bound)
180+
):
181+
# This branch is a mirror image of the above one.
182+
return narrowed.copy_modified(
183+
upper_bound=narrow_declared_type(original_declared, narrowed.upper_bound)
184+
)
176185
elif not is_overlapping_types(declared, narrowed):
177186
if state.strict_optional:
178187
return UninhabitedType()

mypy/message_registry.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88

99
from __future__ import annotations
1010

11-
from typing import Final, NamedTuple
11+
from typing import Final
1212

1313
from mypy import errorcodes as codes
1414
from mypy.errorcodes import ErrorCode
1515

1616

17-
class ErrorMessage(NamedTuple):
18-
value: str
19-
code: ErrorCode | None = None
17+
class ErrorMessage:
18+
def __init__(self, value: str, code: ErrorCode | None = None) -> None:
19+
self.value: Final = value
20+
self.code: Final = code
2021

2122
def format(self, *args: object, **kwargs: object) -> ErrorMessage:
2223
return ErrorMessage(self.value.format(*args, **kwargs), code=self.code)

0 commit comments

Comments
 (0)