Skip to content

Commit 1b1c43a

Browse files
committed
fixes from merge
1 parent 3cf9713 commit 1b1c43a

33 files changed

+1703
-893
lines changed

.mypy/baseline.json

Lines changed: 1457 additions & 795 deletions
Large diffs are not rendered by default.

mypy/binder.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from collections import defaultdict
44
from contextlib import contextmanager
5-
from typing import DefaultDict, Iterator, List, Optional, Tuple, Union, cast
5+
from typing import DefaultDict, Iterator, List, Optional, Tuple, Union, cast, Iterable, Container
66
from typing_extensions import TypeAlias as _TypeAlias
77

88
from mypy.erasetype import remove_instance_last_known_values
@@ -121,6 +121,18 @@ def __init__(self) -> None:
121121
self.try_frames: set[int] = set()
122122
self.break_frames: list[int] = []
123123
self.continue_frames: list[int] = []
124+
self.artificial_values: set[Key]
125+
self._collect_artificial_keys = False
126+
127+
@contextmanager
128+
def collect_artificial_keys(self):
129+
collect_artificial_keys = self._collect_artificial_keys
130+
self._collect_artificial_keys = True
131+
self.artificial_values = set()
132+
try:
133+
yield
134+
finally:
135+
self._collect_artificial_keys = collect_artificial_keys
124136

125137
def _get_id(self) -> int:
126138
self.next_id += 1
@@ -142,6 +154,8 @@ def push_frame(self, conditional_frame: bool = False) -> Frame:
142154
return f
143155

144156
def _put(self, key: Key, type: Type, index: int = -1) -> None:
157+
if self._collect_artificial_keys:
158+
self.artificial_values.add(key)
145159
self.frames[index].types[key] = type
146160

147161
def _get(self, key: Key, index: int = -1) -> Type | None:
@@ -203,7 +217,8 @@ def update_from_options(self, frames: list[Frame]) -> bool:
203217
options are the same.
204218
"""
205219

206-
frames = [f for f in frames if f.unreachable == 0]
220+
artificial = any([f.unreachable == 2 for f in frames])
221+
frames = [f for f in frames if not f.unreachable]
207222
changed = False
208223
keys = {key for f in frames for key in f.types}
209224

@@ -246,7 +261,10 @@ def update_from_options(self, frames: list[Frame]) -> bool:
246261
if simplified == self.declarations[key]:
247262
type = simplified
248263
if current_value is None or not is_same_type(type, current_value):
249-
self._put(key, type)
264+
if not (artificial and key in self.artificial_values):
265+
# if any frames were artificially unreachable,
266+
# we don't want to narrow any types
267+
self._put(key, type)
250268
changed = True
251269

252270
self.frames[-1].unreachable = not frames
@@ -396,7 +414,7 @@ def allow_jump(self, index: int) -> None:
396414
for f in self.frames[index + 1 :]:
397415
frame.types.update(f.types)
398416
if f.unreachable:
399-
frame.unreachable = True
417+
frame.unreachable = f.unreachable
400418
self.options_on_return[index].append(frame)
401419

402420
def handle_break(self) -> None:

mypy/checker.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7414,8 +7414,9 @@ def push_type_map(self, type_map: TypeMap) -> None:
74147414
if type_map is None:
74157415
self.binder.unreachable()
74167416
else:
7417-
for expr, type in type_map.items():
7418-
self.binder.put(expr, type)
7417+
with self.binder.collect_artificial_keys():
7418+
for expr, type in type_map.items():
7419+
self.binder.put(expr, type)
74197420

74207421
def infer_issubclass_maps(self, node: CallExpr, expr: Expression) -> tuple[TypeMap, TypeMap]:
74217422
"""Infer type restrictions for an expression in issubclass call."""

mypy/constraints.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,9 +349,15 @@ def _infer_constraints(
349349
# T :> U2", but they are not equivalent to the constraint solver,
350350
# which never introduces new Union types (it uses join() instead).
351351
if isinstance(template, TypeVarType):
352-
return _infer_constraints(template.upper_bound, actual, direction, skip_neg_op) + [
353-
Constraint(template, direction, actual)
354-
]
352+
if not isinstance(get_proper_type(template.upper_bound), CallableType):
353+
generic_bound = _infer_constraints(
354+
template.upper_bound, actual, direction, skip_neg_op
355+
)
356+
else:
357+
# HACK: Disregard CallableType because `(*Any, **Any) -> object`
358+
# will produce unwanted constraints
359+
generic_bound = []
360+
return generic_bound + [Constraint(template, direction, actual)]
355361

356362
if (
357363
isinstance(actual, TypeVarType)
@@ -360,7 +366,7 @@ def _infer_constraints(
360366
):
361367
# Unless template is also a type variable (or a union that contains one), using the upper
362368
# bound for inference will usually give better result for actual that is a type variable.
363-
if not isinstance(template, UnionType) or not any(
369+
if not isinstance(template, (UnionType, IntersectionType)) or not any(
364370
isinstance(t, TypeVarType) for t in template.items
365371
):
366372
actual = get_proper_type(actual.upper_bound)

mypy/dmypy_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ def serve(self) -> None:
225225
data = receive(server)
226226
sys.stdout = WriteToConn(server, "stdout") # type: ignore[assignment]
227227
sys.stderr = WriteToConn(server, "stderr") # type: ignore[assignment]
228+
self.options.color_output = False # needed so that initialize_unix_colors doesn't try to get the `fileno` of the WriteToConn
228229
resp: dict[str, Any] = {}
229230
if "command" not in data:
230231
resp = {"error": "No command found in request"}

mypy/errors.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,20 +242,20 @@ def filtered_errors(self) -> list[ErrorInfo]:
242242
class StoredBaselineError(TypedDict):
243243
"""Structure of an error while stored in a baseline file"""
244244

245-
code: Optional[str]
245+
code: str | None
246246
column: int
247247
message: str
248248
offset: int
249-
target: Optional[str]
249+
target: str | None
250250
src: str
251251

252252

253253
class BaselineError(TypedDict):
254-
code: Optional[str]
254+
code: str | None
255255
column: int
256256
line: int
257257
message: str
258-
target: Optional[str]
258+
target: str | None
259259
src: str
260260

261261

mypy/messages.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ def return_type_incompatible_with_supertype(
13711371
):
13721372
self.note(f'Consider declaring "{name}" in {target} without "async"', context)
13731373
self.note(
1374-
"See https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators",
1374+
"See https://kotlinisland.github.io/basedmypy/more_types.html#asynchronous-iterators",
13751375
context,
13761376
)
13771377

@@ -2470,7 +2470,9 @@ def quote_type_string(type_string: str) -> str:
24702470
"""Quotes a type representation for use in messages."""
24712471
no_quote_regex = r"^<(tuple|union): \d+ items>$"
24722472
if (
2473-
type_string in ["Module", "overloaded function", "Never", "<deleted>"]
2473+
# erm, "Never" should "Never" be unquoted!
2474+
type_string in ["Module", "overloaded function", "<deleted>"]
2475+
# type_string in ["Module", "overloaded function", "Never", "<deleted>"]
24742476
or type_string.startswith("Module ")
24752477
or re.match(no_quote_regex, type_string) is not None
24762478
or type_string.endswith("?")

mypy/stubdoc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def format_sig(
127127
args.append(arg_def)
128128

129129
retfield = ""
130-
ret_type = self.ret_type if self.ret_type else any_val
130+
ret_type = self.ret_type or any_val
131131
if ret_type is not None:
132132
retfield = " -> " + ret_type
133133

mypy/stubgen.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ def __init__(
422422
include_docstrings: bool = False,
423423
legacy: bool = False,
424424
) -> None:
425-
super().__init__(_all_, include_private, export_less, include_docstrings)
425+
super().__init__(_all_, include_private, export_less, include_docstrings, legacy=legacy)
426426
self._decorators: list[str] = []
427427
# Stack of defined variables (per scope).
428428
self._vars: list[list[str]] = [[]]
@@ -431,8 +431,6 @@ def __init__(
431431
self._current_class: ClassDef | None = None
432432
# Was the tree semantically analysed before?
433433
self.analyzed = analyzed
434-
# Don't use based features?
435-
self.legacy = legacy
436434
# Short names of methods defined in the body of the current class
437435
self.method_names: set[str] = set()
438436
self.processing_dataclass = False
@@ -539,10 +537,10 @@ def _get_func_return(self, o: FuncDef, ctx: FunctionContext) -> str | None:
539537
if o.abstract_status == IS_ABSTRACT or o.name in METHODS_WITH_RETURN_VALUE:
540538
# Always assume abstract methods return Any unless explicitly annotated. Also
541539
# some dunder methods should not have a None return type.
542-
return None # implicit Any
540+
return None if self.legacy else self.add_name("_typeshed.Incomplete") # implicit Any
543541
retname = infer_method_ret_type(o.name)
544542
if not self.legacy and retname == "None":
545-
retname = ""
543+
return None
546544
if retname is not None:
547545
return retname
548546
if has_yield_expression(o) or has_yield_from_expression(o):
@@ -561,9 +559,12 @@ def _get_func_return(self, o: FuncDef, ctx: FunctionContext) -> str | None:
561559
if has_return_statement(o):
562560
return_name = self.add_name("_typeshed.Incomplete")
563561
return f"{generator_name}[{yield_name}, {send_name}, {return_name}]"
562+
if o.is_property:
563+
return None
564+
564565
if not has_return_statement(o) and o.abstract_status == NOT_ABSTRACT:
565-
return "None"
566-
return None
566+
return "None" if self.legacy else None
567+
return None if self.legacy else self.add_name("_typeshed.Incomplete")
567568

568569
def _get_func_docstring(self, node: FuncDef) -> str | None:
569570
if not node.body.body:

mypy/stubgenc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ def __init__(
226226
export_less: bool = False,
227227
include_docstrings: bool = False,
228228
module: ModuleType | None = None,
229+
legacy=False,
229230
) -> None:
230231
self.doc_dir = doc_dir
231232
if module is None:
@@ -235,7 +236,7 @@ def __init__(
235236
self.is_c_module = is_c_module(self.module)
236237
self.known_modules = known_modules
237238
self.resort_members = self.is_c_module
238-
super().__init__(_all_, include_private, export_less, include_docstrings)
239+
super().__init__(_all_, include_private, export_less, include_docstrings, legacy=legacy)
239240
self.module_name = module_name
240241

241242
def get_default_function_sig(self, func: object, ctx: FunctionContext) -> FunctionSig:
@@ -686,7 +687,8 @@ def generate_property_stub(
686687

687688
def get_type_fullname(self, typ: type) -> str:
688689
"""Given a type, return a string representation"""
689-
if typ is Any:
690+
# typ is a TypeForm, not a type
691+
if typ is Any: # type: ignore[comparison-overlap, unused-ignore]
690692
return "Any"
691693
typename = getattr(typ, "__qualname__", typ.__name__)
692694
module_name = self.get_obj_module(typ)

mypy/stubutil.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,10 @@ def __init__(
558558
include_private: bool = False,
559559
export_less: bool = False,
560560
include_docstrings: bool = False,
561+
legacy=False,
561562
):
563+
self.legacy = legacy
564+
562565
# Best known value of __all__.
563566
self._all_ = _all_
564567
self._include_private = include_private
@@ -594,6 +597,9 @@ def add_name(self, fullname: str, require: bool = True) -> str:
594597
595598
The import will be internal to the stub (i.e don't reexport).
596599
"""
600+
601+
if fullname == "_typeshed.Incomplete" and not self.legacy:
602+
fullname = "basedtyping.Untyped"
597603
module, name = fullname.rsplit(".", 1)
598604
alias = "_" + name if name in self.defined_names else None
599605
self.import_tracker.add_import_from(module, [(name, alias)], require=require)

mypy/subtypes.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1635,7 +1635,12 @@ def are_parameters_compatible(
16351635
# (*Any) a supertype of all callables with positional arguments. This is needed in
16361636
# particular because we often refuse to try type inference if actual type is not
16371637
# a subtype of erased template type.
1638-
if all(k.is_positional() for k in left.arg_kinds) and ignore_pos_arg_names:
1638+
# HACK: working around upstream issues:
1639+
# https://github.com/python/mypy/issues/16567
1640+
# https://github.com/python/mypy/issues/16568
1641+
# https://github.com/python/mypy/issues/16569
1642+
# if all(k.is_positional() for k in left.arg_kinds) and ignore_pos_arg_names:
1643+
if all(k.is_positional() for k in left.arg_kinds):
16391644
return True
16401645

16411646
# Match up corresponding arguments and check them for compatibility. In

0 commit comments

Comments
 (0)