Skip to content

Commit 6bde2ab

Browse files
Merge branch 'master' into weak-proxy
2 parents 70ebebb + 68657d2 commit 6bde2ab

36 files changed

+613
-260
lines changed

.github/ISSUE_TEMPLATE/crash.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ labels: "crash"
1515

1616
**Traceback**
1717

18-
```
18+
```python-traceback
1919
(Insert traceback and other messages from mypy here -- use `--show-traceback`.)
2020
```
2121

@@ -25,6 +25,11 @@ labels: "crash"
2525
appreciated. We also very much appreciate it if you try to narrow the
2626
source down to a small stand-alone example.)
2727

28+
```python
29+
# Ideally, a small sample program that demonstrates the problem.
30+
# Or even better, a reproducible playground link https://mypy-play.net/ (use the "Gist" button)
31+
```
32+
2833
**Your Environment**
2934

3035
<!-- Include as many relevant details about the environment you experienced the bug in -->

docs/source/command_line.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,14 @@ of the above sections.
812812
Note: the exact list of flags enabled by running :option:`--strict` may change
813813
over time.
814814

815+
.. include:: strict_list.rst
816+
..
817+
The above file is autogenerated and included during html generation.
818+
(That's an include directive, and this is a comment.)
819+
It would be fine to generate it at some other time instead,
820+
theoretically, but we already had a convenient hook during html gen.
821+
822+
815823
.. option:: --disable-error-code
816824

817825
This flag allows disabling one or multiple error codes globally.

docs/source/common_issues.rst

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ daemon <mypy_daemon>`, which can speed up incremental mypy runtimes by
218218
a factor of 10 or more. :ref:`Remote caching <remote-cache>` can
219219
make cold mypy runs several times faster.
220220

221+
Furthermore: as of `mypy 1.13 <https://mypy-lang.blogspot.com/2024/10/mypy-113-released.html>`_,
222+
mypy allows use of the orjson library for handling the cache instead of the stdlib json, for
223+
improved performance. You can ensure the presence of orjson using the faster-cache extra:
224+
225+
python3 -m pip install -U mypy[faster-cache]
226+
227+
Mypy may depend on orjson by default in the future.
228+
221229
Types of empty collections
222230
--------------------------
223231

@@ -505,11 +513,15 @@ to see the types of all local variables at once. Example:
505513
# b: builtins.str
506514
.. note::
507515

508-
``reveal_type`` and ``reveal_locals`` are only understood by mypy and
509-
don't exist in Python. If you try to run your program, you'll have to
510-
remove any ``reveal_type`` and ``reveal_locals`` calls before you can
511-
run your code. Both are always available and you don't need to import
512-
them.
516+
``reveal_type`` and ``reveal_locals`` are handled specially by mypy during
517+
type checking, and don't have to be defined or imported.
518+
519+
However, if you want to run your code,
520+
you'll have to remove any ``reveal_type`` and ``reveal_locals``
521+
calls from your program or else Python will give you an error at runtime.
522+
523+
Alternatively, you can import ``reveal_type`` from ``typing_extensions``
524+
or ``typing`` (on Python 3.11 and newer)
513525

514526
.. _silencing-linters:
515527

docs/source/dynamic_typing.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
.. _dynamic-typing:
22

3-
43
Dynamically typed code
54
======================
65

@@ -94,6 +93,8 @@ third party libraries that mypy does not know about. This is particularly the ca
9493
when using the :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`
9594
flag. See :ref:`fix-missing-imports` for more information about this.
9695

96+
.. _any-vs-object:
97+
9798
Any vs. object
9899
--------------
99100

docs/source/html_builder.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,37 @@
1111
from sphinx.builders.html import StandaloneHTMLBuilder
1212
from sphinx.environment import BuildEnvironment
1313

14+
from mypy.main import define_options
15+
1416

1517
class MypyHTMLBuilder(StandaloneHTMLBuilder):
18+
strict_file: Path
19+
1620
def __init__(self, app: Sphinx, env: BuildEnvironment) -> None:
1721
super().__init__(app, env)
1822
self._ref_to_doc = {}
23+
self.strict_file = Path(self.srcdir) / "strict_list.rst"
24+
self._add_strict_list()
1925

2026
def write_doc(self, docname: str, doctree: document) -> None:
2127
super().write_doc(docname, doctree)
2228
self._ref_to_doc.update({_id: docname for _id in doctree.ids})
2329

30+
def _add_strict_list(self) -> None:
31+
strict_flags: list[str]
32+
_, strict_flags, _ = define_options()
33+
strict_part = ", ".join(f":option:`{s} <mypy {s}>`" for s in strict_flags)
34+
if (
35+
not strict_part
36+
or strict_part.isspace()
37+
or len(strict_part) < 20
38+
or len(strict_part) > 2000
39+
):
40+
raise ValueError(f"{strict_part=}, which doesn't look right (by a simple heuristic).")
41+
self.strict_file.write_text(
42+
"For this version of mypy, the list of flags enabled by strict is: " + strict_part
43+
)
44+
2445
def _verify_error_codes(self) -> None:
2546
from mypy.errorcodes import error_codes
2647

@@ -55,6 +76,7 @@ def _write_ref_redirector(self) -> None:
5576
def finish(self) -> None:
5677
super().finish()
5778
self._write_ref_redirector()
79+
self.strict_file.unlink()
5880

5981

6082
def setup(app: Sphinx) -> dict[str, Any]:

docs/source/kinds_of_types.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ operations are permitted on the value, and the operations are only checked
4141
at runtime. You can use ``Any`` as an "escape hatch" when you can't use
4242
a more precise type for some reason.
4343

44+
This should not be confused with the
45+
:py:class:`object` type, which represents the set of all values.
46+
Unlike ``object``, ``Any`` introduces type unsafety — see
47+
:ref:`any-vs-object` for more.
48+
4449
``Any`` is compatible with every other type, and vice versa. You can freely
4550
assign a value of type ``Any`` to a variable with a more precise type:
4651

mypy/checker.py

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@ def _visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
726726
assert isinstance(item, Decorator)
727727
item_type = self.extract_callable_type(item.var.type, item)
728728
if item_type is not None:
729+
item_type.definition = item
729730
item_types.append(item_type)
730731
if item_types:
731732
defn.type = Overloaded(item_types)
@@ -3751,6 +3752,9 @@ def check_assignment_to_slots(self, lvalue: Lvalue) -> None:
37513752
return
37523753

37533754
inst = get_proper_type(self.expr_checker.accept(lvalue.expr))
3755+
if isinstance(inst, TypeVarType) and inst.id.is_self():
3756+
# Unwrap self type
3757+
inst = get_proper_type(inst.upper_bound)
37543758
if not isinstance(inst, Instance):
37553759
return
37563760
if inst.type.slots is None:
@@ -4927,17 +4931,7 @@ def visit_operator_assignment_stmt(self, s: OperatorAssignmentStmt) -> None:
49274931
inplace, method = infer_operator_assignment_method(lvalue_type, s.op)
49284932
if inplace:
49294933
# There is __ifoo__, treat as x = x.__ifoo__(y)
4930-
rvalue_type, method_type = self.expr_checker.check_op(method, lvalue_type, s.rvalue, s)
4931-
if isinstance(inst := get_proper_type(lvalue_type), Instance) and isinstance(
4932-
defn := inst.type.get_method(method), OverloadedFuncDef
4933-
):
4934-
for item in defn.items:
4935-
if (
4936-
isinstance(item, Decorator)
4937-
and isinstance(typ := item.func.type, CallableType)
4938-
and (bind_self(typ) == method_type)
4939-
):
4940-
self.warn_deprecated(item.func, s)
4934+
rvalue_type, _ = self.expr_checker.check_op(method, lvalue_type, s.rvalue, s)
49414935
if not is_subtype(rvalue_type, lvalue_type):
49424936
self.msg.incompatible_operator_assignment(s.op, s)
49434937
else:
@@ -7962,7 +7956,7 @@ def warn_deprecated(self, node: Node | None, context: Context) -> None:
79627956
node = node.func
79637957
if (
79647958
isinstance(node, (FuncDef, OverloadedFuncDef, TypeInfo))
7965-
and ((deprecated := node.deprecated) is not None)
7959+
and (deprecated := node.deprecated) is not None
79667960
and not self.is_typeshed_stub
79677961
and not any(
79687962
node.fullname == p or node.fullname.startswith(f"{p}.")
@@ -7972,21 +7966,6 @@ def warn_deprecated(self, node: Node | None, context: Context) -> None:
79727966
warn = self.msg.note if self.options.report_deprecated_as_note else self.msg.fail
79737967
warn(deprecated, context, code=codes.DEPRECATED)
79747968

7975-
def warn_deprecated_overload_item(
7976-
self, node: Node | None, context: Context, *, target: Type, selftype: Type | None = None
7977-
) -> None:
7978-
"""Warn if the overload item corresponding to the given callable is deprecated."""
7979-
target = get_proper_type(target)
7980-
if isinstance(node, OverloadedFuncDef) and isinstance(target, CallableType):
7981-
for item in node.items:
7982-
if isinstance(item, Decorator) and isinstance(
7983-
candidate := item.func.type, CallableType
7984-
):
7985-
if selftype is not None and not node.is_static:
7986-
candidate = bind_self(candidate, selftype)
7987-
if candidate == target:
7988-
self.warn_deprecated(item.func, context)
7989-
79907969
# leafs
79917970

79927971
def visit_pass_stmt(self, o: PassStmt, /) -> None:

mypy/checker_shared.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,6 @@ def check_deprecated(self, node: Node | None, context: Context) -> None:
253253
def warn_deprecated(self, node: Node | None, context: Context) -> None:
254254
raise NotImplementedError
255255

256-
@abstractmethod
257-
def warn_deprecated_overload_item(
258-
self, node: Node | None, context: Context, *, target: Type, selftype: Type | None = None
259-
) -> None:
260-
raise NotImplementedError
261-
262256
@abstractmethod
263257
def type_is_iterable(self, type: Type) -> bool:
264258
raise NotImplementedError

mypy/checkexpr.py

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@
129129
validate_instance,
130130
)
131131
from mypy.typeops import (
132-
bind_self,
133132
callable_type,
134133
custom_special_method,
135134
erase_to_union_or_bound,
@@ -1517,15 +1516,6 @@ def check_call_expr_with_callee_type(
15171516
object_type=object_type,
15181517
)
15191518
proper_callee = get_proper_type(callee_type)
1520-
if isinstance(e.callee, (NameExpr, MemberExpr)):
1521-
node = e.callee.node
1522-
if node is None and member is not None and isinstance(object_type, Instance):
1523-
if (symbol := object_type.type.get(member)) is not None:
1524-
node = symbol.node
1525-
self.chk.check_deprecated(node, e)
1526-
self.chk.warn_deprecated_overload_item(
1527-
node, e, target=callee_type, selftype=object_type
1528-
)
15291519
if isinstance(e.callee, RefExpr) and isinstance(proper_callee, CallableType):
15301520
# Cache it for find_isinstance_check()
15311521
if proper_callee.type_guard is not None:
@@ -2943,6 +2933,8 @@ def infer_overload_return_type(
29432933
# check for ambiguity due to 'Any' below.
29442934
if not args_contain_any:
29452935
self.chk.store_types(m)
2936+
if isinstance(infer_type, ProperType) and isinstance(infer_type, CallableType):
2937+
self.chk.check_deprecated(infer_type.definition, context)
29462938
return ret_type, infer_type
29472939
p_infer_type = get_proper_type(infer_type)
29482940
if isinstance(p_infer_type, CallableType):
@@ -2979,6 +2971,11 @@ def infer_overload_return_type(
29792971
else:
29802972
# Success! No ambiguity; return the first match.
29812973
self.chk.store_types(type_maps[0])
2974+
inferred_callable = inferred_types[0]
2975+
if isinstance(inferred_callable, ProperType) and isinstance(
2976+
inferred_callable, CallableType
2977+
):
2978+
self.chk.check_deprecated(inferred_callable.definition, context)
29822979
return return_types[0], inferred_types[0]
29832980

29842981
def overload_erased_call_targets(
@@ -4103,16 +4100,6 @@ def lookup_definer(typ: Instance, attr_name: str) -> str | None:
41034100
errors.append(local_errors.filtered_errors())
41044101
results.append(result)
41054102
else:
4106-
if isinstance(obj, Instance) and isinstance(
4107-
defn := obj.type.get_method(name), OverloadedFuncDef
4108-
):
4109-
for item in defn.items:
4110-
if (
4111-
isinstance(item, Decorator)
4112-
and isinstance(typ := item.func.type, CallableType)
4113-
and bind_self(typ) == result[1]
4114-
):
4115-
self.chk.check_deprecated(item.func, context)
41164103
return result
41174104

41184105
# We finish invoking above operators and no early return happens. Therefore,
@@ -6043,8 +6030,10 @@ def accept(
60436030
# We cannot use cache inside lambdas, because they skip immediate type
60446031
# context, and use enclosing one, see infer_lambda_type_using_context().
60456032
# TODO: consider using cache for more expression kinds.
6046-
elif isinstance(node, (CallExpr, ListExpr, TupleExpr, DictExpr, OpExpr)) and not (
6047-
self.in_lambda_expr or self.chk.current_node_deferred
6033+
elif (
6034+
isinstance(node, (CallExpr, ListExpr, TupleExpr, DictExpr, OpExpr))
6035+
and not (self.in_lambda_expr or self.chk.current_node_deferred)
6036+
and not self.chk.options.disable_expression_cache
60486037
):
60496038
if (node, type_context) in self.expr_cache:
60506039
binder_version, typ, messages, type_map = self.expr_cache[(node, type_context)]

0 commit comments

Comments
 (0)