Skip to content

Commit 5ec6868

Browse files
committed
Merge branch 'master' into refine-enum-branch-analysis
2 parents eaa0872 + 18a9fe1 commit 5ec6868

File tree

171 files changed

+7060
-4496
lines changed

Some content is hidden

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

171 files changed

+7060
-4496
lines changed

docs/source/command_line.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,19 @@ Miscellaneous
622622
have many scripts that import a large package, the behavior enabled
623623
by this flag is often more convenient.)
624624

625+
``--new-semantic-analyzer``
626+
This flag switches to an improved, experimental implementation of
627+
the *semantic analyzer* (the part of mypy that binds Python
628+
names to definitions). The old and the new semantic analyzers
629+
mostly behave identically. The new semantic analyzer is better at
630+
handling import cycles and forward references to definitions. It
631+
also fixes inconsistencies between the daemon and non-daemon modes,
632+
and it detects additional error conditions.
633+
634+
Likely, the next mypy release will use the new semantic analyzer by
635+
default, and the old semantic analyzer will be removed in the next
636+
release after that.
637+
625638
.. _PEP 420: https://www.python.org/dev/peps/pep-0420/
626639

627640
.. _PEP 561: https://www.python.org/dev/peps/pep-0561/

docs/source/common_issues.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,8 @@ to see the types of all local variables at once. Example:
456456
b = 'one'
457457
reveal_locals()
458458
# Revealed local types are:
459-
# a: builtins.int
460-
# b: builtins.str
459+
# a: builtins.int
460+
# b: builtins.str
461461
.. note::
462462

463463
``reveal_type`` and ``reveal_locals`` are only understood by mypy and

docs/source/config_file.rst

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,16 @@ characters.
5252

5353
.. _config-precedence:
5454

55-
When options conflict, the precedence order for the configuration sections is:
56-
1. Sections with concrete module names (``foo.bar``)
57-
2. Sections with "unstructured" wildcard patterns (``foo.*.baz``),
55+
When options conflict, the precedence order for configuration is:
56+
1. :ref:`Inline configuration <inline-config>` in the source file
57+
2. Sections with concrete module names (``foo.bar``)
58+
3. Sections with "unstructured" wildcard patterns (``foo.*.baz``),
5859
with sections later in the configuration file overriding
5960
sections earlier.
60-
3. Sections with "well-structured" wildcard patterns
61+
4. Sections with "well-structured" wildcard patterns
6162
(``foo.bar.*``), with more specific overriding more general.
62-
4. Command line options.
63-
5. Top-level configuration file options.
63+
5. Command line options.
64+
6. Top-level configuration file options.
6465

6566
The difference in precedence order between "structured" patterns (by
6667
specificity) and "unstructured" patterns (by order in the file) is
@@ -143,6 +144,10 @@ options take precedence. This lets you set global defaults and override them on
143144
module-by-module basis. If multiple pattern sections match a module, :ref:`the options from the
144145
most specific section are used where they disagree <config-precedence>`.
145146

147+
Options that take a boolean value may be inverted by adding ``no_`` to
148+
their name or by (when applicable) swapping their prefix from
149+
``disallow`` to ``allow`` (and vice versa).
150+
146151
.. _config-file-import-discovery-per-module:
147152

148153
Import discovery
@@ -294,7 +299,7 @@ Miscellaneous strictness flags
294299
Allows variables to be redefined with an arbitrary type, as long as the redefinition
295300
is in the same block and nesting level as the original definition.
296301

297-
``implicit-reexport`` (bool, default True)
302+
``implicit_reexport`` (bool, default True)
298303
By default, imported values to a module are treated as exported and mypy allows
299304
other modules to import them. When false, mypy will not re-export unless
300305
the item is imported using from-as. Note that mypy treats stub files as if this
@@ -311,6 +316,18 @@ Miscellaneous strictness flags
311316
Prohibit equality checks, identity checks, and container checks between
312317
non-overlapping types.
313318

319+
Platform configuration
320+
----------------------
321+
322+
``always_true`` (comma-separated list of strings)
323+
Specifies a list of variables that mypy will treat as
324+
compile-time constants that are always true.
325+
326+
``always_false`` (comma-separated list of strings)
327+
Specifies a list of variables that mypy will treat as
328+
compile-time constants that are always false.
329+
330+
314331
Global-only options
315332
*******************
316333

@@ -372,14 +389,6 @@ section of the command line docs.
372389
The default is the current platform as revealed by Python's
373390
``sys.platform`` variable.
374391

375-
``always_true`` (comma-separated list of strings)
376-
Specifies a list of variables that mypy will treat as
377-
compile-time constants that are always true.
378-
379-
``always_false`` (comma-separated list of strings)
380-
Specifies a list of variables that mypy will treat as
381-
compile-time constants that are always false.
382-
383392

384393
Incremental mode
385394
----------------
@@ -456,3 +465,7 @@ Miscellaneous
456465

457466
``verbosity`` (integer, default 0)
458467
Controls how much debug output will be generated. Higher numbers are more verbose.
468+
469+
``new_semantic_analyzer`` (bool, default False)
470+
Enables the experimental new semantic analyzer.
471+
(See :ref:`The mypy command line <command-line>` for more information.)

docs/source/extending_mypy.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,30 @@ insert some entries there) before the class body is analyzed.
235235
module. It is called before semantic analysis. For example, this can
236236
be used if a library has dependencies that are dynamically loaded
237237
based on configuration information.
238+
239+
Supporting the new semantic analyzer
240+
************************************
241+
242+
Support for the new semantic analyzer (enabled through
243+
``--new-semantic-analyzer``) requires some changes to plugins. Here is
244+
a short summary of the most important changes:
245+
246+
* The order of processing AST nodes is different. Code outside
247+
functions is processed first, and functions and methods are
248+
processed afterwards.
249+
250+
* Each AST node can be processed multiple times to resolve forward
251+
references. The same plugin hook may be called multiple times, so
252+
they need to be idempotent.
253+
254+
* The ``anal_type()`` API method returns ``None`` if some part of
255+
the type is not available yet due to forward references, for example.
256+
257+
* When looking up symbols, you may encounter *placeholder nodes* that
258+
are used for names that haven't been fully processed yet. You'll
259+
generally want to request another semantic analysis iteration by
260+
*deferring* in that case.
261+
262+
See the docstring at the top of
263+
`mypy/plugin.py <https://github.com/python/mypy/blob/master/mypy/plugin.py>`_
264+
for more details.

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Mypy is a static type checker for Python 3 and Python 2.7.
5454
running_mypy
5555
command_line
5656
config_file
57+
inline_config
5758
mypy_daemon
5859
installed_packages
5960
extending_mypy

docs/source/inline_config.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.. _inline-config:
2+
3+
Inline configuration
4+
====================
5+
6+
Mypy supports setting per-file configuration options inside files themselves
7+
using ``# mypy:`` comments. For example:
8+
9+
.. code-block:: python
10+
11+
# mypy: disallow-any-generics
12+
13+
Inline configuration comments take precedence over all other
14+
configuration mechanisms.
15+
16+
Configuration comment format
17+
****************************
18+
19+
Flags correspond to :ref:`config file flags <config-file>` but allow
20+
hyphens to be substituted for underscores.
21+
22+
Values are specified using ``=``, but ``= True`` may be omitted:
23+
24+
.. code-block:: python
25+
26+
# mypy: disallow-any-generics
27+
# mypy: always-true=FOO
28+
29+
Multiple flags can be separated by commas or placed on separate
30+
lines. To include a comma as part of an option's value, place the
31+
value inside quotes:
32+
33+
.. code-block:: python
34+
35+
# mypy: disallow-untyped-defs, always-false="FOO,BAR"
36+
37+
Like in the configuration file, options that take a boolean value may be
38+
inverted by adding ``no-`` to their name or by (when applicable)
39+
swapping their prefix from ``disallow`` to ``allow`` (and vice versa):
40+
41+
.. code-block:: python
42+
43+
# mypy: allow-untyped-defs, no-strict-optional

mypy/binder.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
from typing import Dict, List, Set, Iterator, Union, Optional, Tuple, cast
21
from contextlib import contextmanager
32
from collections import defaultdict
43

5-
MYPY = False
6-
if MYPY:
7-
from typing import DefaultDict
4+
from typing import Dict, List, Set, Iterator, Union, Optional, Tuple, cast
5+
from typing_extensions import DefaultDict
86

97
from mypy.types import Type, AnyType, PartialType, UnionType, TypeOfAny, NoneType
108
from mypy.subtypes import is_subtype
@@ -34,11 +32,16 @@ def __init__(self) -> None:
3432
self.types = {} # type: Dict[Key, Type]
3533
self.unreachable = False
3634

35+
# Should be set only if we're entering a frame where it's not
36+
# possible to accurately determine whether or not contained
37+
# statements will be unreachable or not.
38+
#
39+
# Long-term, we should improve mypy to the point where we no longer
40+
# need this field.
41+
self.suppress_unreachable_warnings = False
42+
3743

38-
if MYPY:
39-
# This is the type of stored assignments for union type rvalues.
40-
# We use 'if MYPY: ...' since typing-3.5.1 does not have 'DefaultDict'
41-
Assigns = DefaultDict[Expression, List[Tuple[Type, Optional[Type]]]]
44+
Assigns = DefaultDict[Expression, List[Tuple[Type, Optional[Type]]]]
4245

4346

4447
class ConditionalTypeBinder:
@@ -136,6 +139,9 @@ def put(self, expr: Expression, typ: Type) -> None:
136139
def unreachable(self) -> None:
137140
self.frames[-1].unreachable = True
138141

142+
def suppress_unreachable_warnings(self) -> None:
143+
self.frames[-1].suppress_unreachable_warnings = True
144+
139145
def get(self, expr: Expression) -> Optional[Type]:
140146
key = literal_hash(expr)
141147
assert key is not None, 'Internal error: binder tried to get non-literal'
@@ -146,6 +152,10 @@ def is_unreachable(self) -> bool:
146152
# this traversal on every statement?
147153
return any(f.unreachable for f in self.frames)
148154

155+
def is_unreachable_warning_suppressed(self) -> bool:
156+
# TODO: See todo in 'is_unreachable'
157+
return any(f.suppress_unreachable_warnings for f in self.frames)
158+
149159
def cleanse(self, expr: Expression) -> None:
150160
"""Remove all references to a Node from the binder."""
151161
key = literal_hash(expr)

mypy/build.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@
2525

2626
from typing import (AbstractSet, Any, Dict, Iterable, Iterator, List,
2727
Mapping, NamedTuple, Optional, Set, Tuple, Union, Callable, TextIO)
28-
MYPY = False
29-
if MYPY:
30-
from typing import ClassVar
31-
from typing_extensions import Final
32-
28+
from typing_extensions import ClassVar, Final, TYPE_CHECKING
3329
from mypy_extensions import TypedDict
3430

3531
from mypy.nodes import MypyFile, ImportBase, Import, ImportFrom, ImportAll, SymbolTable
@@ -45,7 +41,7 @@
4541
from mypy.util import (
4642
DecodeError, decode_python_encoding, is_sub_path, get_mypy_comments, module_prefix
4743
)
48-
if MYPY:
44+
if TYPE_CHECKING:
4945
from mypy.report import Reports # Avoid unconditional slow import
5046
from mypy import moduleinfo
5147
from mypy.fixup import fixup_module
@@ -117,7 +113,7 @@ def is_source(self, file: MypyFile) -> bool:
117113
return True
118114
elif file._fullname in self.source_modules:
119115
return True
120-
elif file.path is None and self.source_text_present:
116+
elif self.source_text_present:
121117
return True
122118
else:
123119
return False
@@ -576,6 +572,10 @@ def __init__(self, data_dir: str,
576572
self.plugins_snapshot = plugins_snapshot
577573
self.old_plugins_snapshot = read_plugins_snapshot(self)
578574
self.quickstart_state = read_quickstart_file(options, self.stdout)
575+
# Fine grained targets (module top levels and top level functions) processed by
576+
# the semantic analyzer, used only for testing. Currently used only by the new
577+
# semantic analyzer.
578+
self.processed_targets = [] # type: List[str]
579579

580580
def dump_stats(self) -> None:
581581
self.log("Stats:")
@@ -1020,12 +1020,16 @@ def read_deps_cache(manager: BuildManager,
10201020
def _load_json_file(file: str, manager: BuildManager,
10211021
log_sucess: str, log_error: str) -> Optional[Dict[str, Any]]:
10221022
"""A simple helper to read a JSON file with logging."""
1023+
t0 = time.time()
10231024
try:
10241025
data = manager.metastore.read(file)
10251026
except IOError:
10261027
manager.log(log_error + file)
10271028
return None
1028-
manager.trace(log_sucess + data.rstrip())
1029+
manager.add_stats(metastore_read_time=time.time() - t0)
1030+
# Only bother to compute the log message if we are logging it, since it could be big
1031+
if manager.verbosity() >= 2:
1032+
manager.trace(log_sucess + data.rstrip())
10291033
try:
10301034
result = json.loads(data)
10311035
except ValueError: # TODO: JSONDecodeError in 3.5
@@ -1109,14 +1113,18 @@ def find_cache_meta(id: str, path: str, manager: BuildManager) -> Optional[Cache
11091113
meta = _load_json_file(meta_json, manager,
11101114
log_sucess='Meta {} '.format(id),
11111115
log_error='Could not load cache for {}: '.format(id))
1116+
t1 = time.time()
11121117
if meta is None:
11131118
return None
11141119
if not isinstance(meta, dict):
11151120
manager.log('Could not load cache for {}: meta cache is not a dict: {}'
11161121
.format(id, repr(meta)))
11171122
return None
11181123
m = cache_meta_from_dict(meta, data_json)
1119-
manager.add_stats(load_meta_time=time.time() - t0)
1124+
t2 = time.time()
1125+
manager.add_stats(load_meta_time=t2 - t0,
1126+
load_meta_load_time=t1 - t0,
1127+
load_meta_from_dict_time=t2 - t1)
11201128

11211129
# Don't check for path match, that is dealt with in validate_meta().
11221130
if (m.id != id or
@@ -1876,20 +1884,17 @@ def patch_dependency_parents(self) -> None:
18761884
details.
18771885
18781886
However, this patching process can occur after `a` has been parsed and
1879-
serialized during increment mode. Consequently, we need to repeat this
1887+
serialized during incremental mode. Consequently, we need to repeat this
18801888
patch when deserializing a cached file.
18811889
18821890
This function should be called only when processing fresh SCCs -- the
18831891
semantic analyzer will perform this patch for us when processing stale
18841892
SCCs.
18851893
"""
1886-
Analyzer = Union[SemanticAnalyzerPass2, NewSemanticAnalyzer] # noqa
1887-
if self.manager.options.new_semantic_analyzer:
1888-
analyzer = self.manager.new_semantic_analyzer # type: Analyzer
1889-
else:
1894+
if not self.manager.options.new_semantic_analyzer:
18901895
analyzer = self.manager.semantic_analyzer
1891-
for dep in self.dependencies:
1892-
analyzer.add_submodules_to_parent_modules(dep, True)
1896+
for dep in self.dependencies:
1897+
analyzer.add_submodules_to_parent_modules(dep, True)
18931898

18941899
def fix_suppressed_dependencies(self, graph: Graph) -> None:
18951900
"""Corrects whether dependencies are considered stale in silent mode.

0 commit comments

Comments
 (0)