Skip to content

Commit 818175d

Browse files
Merge branch 'master' into fix_typevar_default
2 parents 1a3957a + 374fefb commit 818175d

File tree

92 files changed

+4520
-1312
lines changed

Some content is hidden

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

92 files changed

+4520
-1312
lines changed

.github/workflows/mypy_primer.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ jobs:
6767
--debug \
6868
--additional-flags="--debug-serialize" \
6969
--output concise \
70+
--mypy-install-librt \
7071
| tee diff_${{ matrix.shard-index }}.txt
7172
) || [ $? -eq 1 ]
7273
- if: ${{ matrix.shard-index == 0 }}

docs/source/command_line.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ definitions or calls.
372372

373373
.. option:: --untyped-calls-exclude
374374

375-
This flag allows to selectively disable :option:`--disallow-untyped-calls`
375+
This flag allows one to selectively disable :option:`--disallow-untyped-calls`
376376
for functions and methods defined in specific packages, modules, or classes.
377377
Note that each exclude entry acts as a prefix. For example (assuming there
378378
are no type annotations for ``third_party_lib`` available):
@@ -562,7 +562,7 @@ potentially problematic or redundant in some way.
562562

563563
.. option:: --deprecated-calls-exclude
564564

565-
This flag allows to selectively disable :ref:`deprecated<code-deprecated>` warnings
565+
This flag allows one to selectively disable :ref:`deprecated<code-deprecated>` warnings
566566
for functions and methods defined in specific packages, modules, or classes.
567567
Note that each exclude entry acts as a prefix. For example (assuming ``foo.A.func`` is deprecated):
568568

@@ -1255,12 +1255,18 @@ Miscellaneous
12551255
stub packages were found, they are installed and then another run
12561256
is performed.
12571257

1258-
.. option:: --junit-xml JUNIT_XML
1258+
.. option:: --junit-xml JUNIT_XML_OUTPUT_FILE
12591259

12601260
Causes mypy to generate a JUnit XML test result document with
12611261
type checking results. This can make it easier to integrate mypy
12621262
with continuous integration (CI) tools.
12631263

1264+
.. option:: --junit-format {global,per_file}
1265+
1266+
If --junit-xml is set, specifies format.
1267+
global (default): single test with all errors;
1268+
per_file: one test entry per file with failures.
1269+
12641270
.. option:: --find-occurrences CLASS.MEMBER
12651271

12661272
This flag will make mypy print out all usages of a class member

docs/source/common_issues.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ This example demonstrates both safe and unsafe overrides:
731731
732732
class NarrowerReturn(A):
733733
# A more specific return type is fine
734-
def test(self, t: Sequence[int]) -> List[str]: # OK
734+
def test(self, t: Sequence[int]) -> list[str]: # OK
735735
...
736736
737737
class GeneralizedReturn(A):
@@ -746,7 +746,7 @@ not necessary:
746746
.. code-block:: python
747747
748748
class NarrowerArgument(A):
749-
def test(self, t: List[int]) -> Sequence[str]: # type: ignore[override]
749+
def test(self, t: list[int]) -> Sequence[str]: # type: ignore[override]
750750
...
751751
752752
.. _unreachable:

docs/source/config_file.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,15 @@ These options may only be set in the global section (``[mypy]``).
11531153
type checking results. This can make it easier to integrate mypy
11541154
with continuous integration (CI) tools.
11551155

1156+
.. confval:: junit_format
1157+
1158+
:type: string
1159+
:default: ``global``
1160+
1161+
If junit_xml is set, specifies format.
1162+
global (default): single test with all errors;
1163+
per_file: one test entry per file with failures.
1164+
11561165
.. confval:: scripts_are_modules
11571166

11581167
:type: boolean

docs/source/error_code_list.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,8 +1032,8 @@ Warn about top level await expressions [top-level-await]
10321032
This error code is separate from the general ``[syntax]`` errors, because in
10331033
some environments (e.g. IPython) a top level ``await`` is allowed. In such
10341034
environments a user may want to use ``--disable-error-code=top-level-await``,
1035-
that allows to still have errors for other improper uses of ``await``, for
1036-
example:
1035+
which allows one to still have errors for other improper uses of ``await``,
1036+
for example:
10371037

10381038
.. code-block:: python
10391039

docs/source/error_code_list2.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,3 +676,26 @@ Example:
676676
print("red")
677677
case _:
678678
print("other")
679+
680+
.. _code-untyped-decorator:
681+
682+
Error if an untyped decorator makes a typed function effectively untyped [untyped-decorator]
683+
--------------------------------------------------------------------------------------------
684+
685+
If enabled with :option:`--disallow-untyped-decorators <mypy --disallow-untyped-decorators>`
686+
mypy generates an error if a typed function is wrapped by an untyped decorator
687+
(as this would effectively remove the benefits of typing the function).
688+
689+
Example:
690+
691+
.. code-block:: python
692+
693+
def printing_decorator(func):
694+
def wrapper(*args, **kwds):
695+
print("Calling", func)
696+
return func(*args, **kwds)
697+
return wrapper
698+
# A decorated function.
699+
@printing_decorator # E: Untyped decorator makes function "add_forty_two" untyped [untyped-decorator]
700+
def add_forty_two(value: int) -> int:
701+
return value + 42

docs/source/mypy_daemon.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,16 +252,16 @@ command.
252252
Statically inspect expressions
253253
******************************
254254

255-
The daemon allows to get declared or inferred type of an expression (or other
255+
The daemon allows one to get the declared or inferred type of an expression (or other
256256
information about an expression, such as known attributes or definition location)
257-
using ``dmypy inspect LOCATION`` command. The location of the expression should be
257+
using the ``dmypy inspect LOCATION`` command. The location of the expression should be
258258
specified in the format ``path/to/file.py:line:column[:end_line:end_column]``.
259259
Both line and column are 1-based. Both start and end position are inclusive.
260260
These rules match how mypy prints the error location in error messages.
261261

262262
If a span is given (i.e. all 4 numbers), then only an exactly matching expression
263263
is inspected. If only a position is given (i.e. 2 numbers, line and column), mypy
264-
will inspect all *expressions*, that include this position, starting from the
264+
will inspect all expressions that include this position, starting from the
265265
innermost one.
266266

267267
Consider this Python code snippet:

docs/source/stubtest.rst

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,75 @@ to mypy build errors". In this case, you will need to mitigate those errors
9999
before stubtest will run. Despite potential overlap in errors here, stubtest is
100100
not intended as a substitute for running mypy directly.
101101

102+
Allowlist
103+
*********
104+
102105
If you wish to ignore some of stubtest's complaints, stubtest supports a
103-
pretty handy allowlist system.
106+
pretty handy :option:`--allowlist` system.
107+
108+
Let's say that you have this python module called ``ex``:
109+
110+
.. code-block:: python
111+
112+
try:
113+
import optional_expensive_dep
114+
except ImportError:
115+
optional_expensive_dep = None
116+
117+
first = 1
118+
if optional_expensive_dep:
119+
second = 2
120+
121+
Let's say that you can't install ``optional_expensive_dep`` in CI for some reason,
122+
but you still want to include ``second: int`` in the stub file:
123+
124+
.. code-block:: python
125+
126+
first: int
127+
second: int
128+
129+
In this case stubtest will correctly complain:
130+
131+
.. code-block:: shell
132+
133+
error: ex.second is not present at runtime
134+
Stub: in file /.../ex.pyi:2
135+
builtins.int
136+
Runtime:
137+
MISSING
138+
139+
Found 1 error (checked 1 module)
140+
141+
To fix this, you can add an ``allowlist`` entry:
142+
143+
.. code-block:: ini
144+
145+
# Allowlist entries in `allowlist.txt` file:
146+
147+
# Does not exist if `optional_expensive_dep` is not installed:
148+
ex.second
149+
150+
And now when running stubtest with ``--allowlist=allowlist.txt``,
151+
no errors will be generated anymore.
152+
153+
Allowlists also support regular expressions,
154+
which can be useful to ignore many similar errors at once.
155+
They can also be useful for suppressing stubtest errors that occur sometimes,
156+
but not on every CI run. For example, if some CI workers have
157+
``optional_expensive_dep`` installed, stubtest might complain with this message
158+
on those workers if you had the ``ex.second`` allowlist entry:
159+
160+
.. code-block:: ini
161+
162+
note: unused allowlist entry ex.second
163+
Found 1 error (checked 1 module)
164+
165+
Changing ``ex.second`` to be ``(ex\.second)?`` will make this error optional,
166+
meaning that stubtest will pass whether or not a CI runner
167+
has``optional_expensive_dep`` installed.
168+
169+
CLI
170+
***
104171

105172
The rest of this section documents the command line interface of stubtest.
106173

@@ -119,15 +186,15 @@ The rest of this section documents the command line interface of stubtest.
119186
.. option:: --allowlist FILE
120187

121188
Use file as an allowlist. Can be passed multiple times to combine multiple
122-
allowlists. Allowlists can be created with --generate-allowlist. Allowlists
123-
support regular expressions.
189+
allowlists. Allowlists can be created with :option:`--generate-allowlist`.
190+
Allowlists support regular expressions.
124191

125192
The presence of an entry in the allowlist means stubtest will not generate
126193
any errors for the corresponding definition.
127194

128195
.. option:: --generate-allowlist
129196

130-
Print an allowlist (to stdout) to be used with --allowlist
197+
Print an allowlist (to stdout) to be used with :option:`--allowlist`.
131198

132199
When introducing stubtest to an existing project, this is an easy way to
133200
silence all existing errors.
@@ -141,17 +208,17 @@ The rest of this section documents the command line interface of stubtest.
141208

142209
Note if an allowlist entry is a regex that matches the empty string,
143210
stubtest will never consider it unused. For example, to get
144-
`--ignore-unused-allowlist` behaviour for a single allowlist entry like
211+
``--ignore-unused-allowlist`` behaviour for a single allowlist entry like
145212
``foo.bar`` you could add an allowlist entry ``(foo\.bar)?``.
146213
This can be useful when an error only occurs on a specific platform.
147214

148215
.. option:: --mypy-config-file FILE
149216

150-
Use specified mypy config file to determine mypy plugins and mypy path
217+
Use specified mypy config *file* to determine mypy plugins and mypy path
151218

152219
.. option:: --custom-typeshed-dir DIR
153220

154-
Use the custom typeshed in DIR
221+
Use the custom typeshed in *DIR*
155222

156223
.. option:: --check-typeshed
157224

misc/analyze_cache.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def extract(chunks: Iterable[JsonDict]) -> Iterable[JsonDict]:
4141
if isinstance(chunk, dict):
4242
yield chunk
4343
yield from extract(chunk.values())
44-
elif isinstance(chunk, list):
44+
elif isinstance(chunk, list): # type: ignore[unreachable] #TODO: is this actually unreachable, or are our types wrong?
4545
yield from extract(chunk)
4646

4747
yield from extract([chunk.data for chunk in chunks])
@@ -93,7 +93,7 @@ def compress(chunk: JsonDict) -> JsonDict:
9393
def helper(chunk: JsonDict) -> JsonDict:
9494
nonlocal counter
9595
if not isinstance(chunk, dict):
96-
return chunk
96+
return chunk # type: ignore[unreachable] #TODO: is this actually unreachable, or are our types wrong?
9797

9898
if len(chunk) <= 2:
9999
return chunk
@@ -124,7 +124,7 @@ def decompress(chunk: JsonDict) -> JsonDict:
124124

125125
def helper(chunk: JsonDict) -> JsonDict:
126126
if not isinstance(chunk, dict):
127-
return chunk
127+
return chunk # type: ignore[unreachable] #TODO: is this actually unreachable, or are our types wrong?
128128
if ".id" in chunk:
129129
return cache[chunk[".id"]]
130130

misc/profile_check.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,22 @@ def check_requirements() -> None:
7878
if sys.platform != "linux":
7979
# TODO: How to make this work on other platforms?
8080
sys.exit("error: Only Linux is supported")
81-
82-
try:
83-
subprocess.run(["perf", "-h"], capture_output=True)
84-
except (subprocess.CalledProcessError, FileNotFoundError):
85-
print("error: The 'perf' profiler is not installed")
86-
sys.exit(1)
87-
88-
try:
89-
subprocess.run(["clang", "--version"], capture_output=True)
90-
except (subprocess.CalledProcessError, FileNotFoundError):
91-
print("error: The clang compiler is not installed")
92-
sys.exit(1)
93-
94-
if not os.path.isfile("mypy_self_check.ini"):
95-
print("error: Run this in the mypy repository root")
96-
sys.exit(1)
81+
else: # fun fact/todo: we have to use else here, because of https://github.com/python/mypy/issues/10773
82+
try:
83+
subprocess.run(["perf", "-h"], capture_output=True)
84+
except (subprocess.CalledProcessError, FileNotFoundError):
85+
print("error: The 'perf' profiler is not installed")
86+
sys.exit(1)
87+
88+
try:
89+
subprocess.run(["clang", "--version"], capture_output=True)
90+
except (subprocess.CalledProcessError, FileNotFoundError):
91+
print("error: The clang compiler is not installed")
92+
sys.exit(1)
93+
94+
if not os.path.isfile("mypy_self_check.ini"):
95+
print("error: Run this in the mypy repository root")
96+
sys.exit(1)
9797

9898

9999
def main() -> None:

0 commit comments

Comments
 (0)