Skip to content

Commit 1d40527

Browse files
authored
Refactor mypy.experiments (new name mypy.state) (#6134)
The old name made no sense any more. Also don't use ALL_CAPS with a non-final name.
1 parent 0560264 commit 1d40527

13 files changed

+56
-55
lines changed

mypy/checker.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@
6262
from mypy.plugin import Plugin, CheckerPluginInterface
6363
from mypy.sharedparse import BINARY_MAGIC_METHODS
6464
from mypy.scope import Scope
65-
66-
from mypy import experiments
65+
from mypy import state
6766

6867
MYPY = False
6968
if MYPY:
@@ -273,7 +272,7 @@ def check_first_pass(self) -> None:
273272
Deferred functions will be processed by check_second_pass().
274273
"""
275274
self.recurse_into_functions = True
276-
with experiments.strict_optional_set(self.options.strict_optional):
275+
with state.strict_optional_set(self.options.strict_optional):
277276
self.errors.set_file(self.path, self.tree.fullname(), scope=self.tscope)
278277
self.tscope.enter_file(self.tree.fullname())
279278
with self.enter_partial_types():
@@ -308,7 +307,7 @@ def check_second_pass(self,
308307
This goes through deferred nodes, returning True if there were any.
309308
"""
310309
self.recurse_into_functions = True
311-
with experiments.strict_optional_set(self.options.strict_optional):
310+
with state.strict_optional_set(self.options.strict_optional):
312311
if not todo and not self.deferred_nodes:
313312
return False
314313
self.errors.set_file(self.path, self.tree.fullname(), scope=self.tscope)
@@ -505,7 +504,7 @@ def check_overlapping_overloads(self, defn: OverloadedFuncDef) -> None:
505504
# def foo(x: str) -> str: ...
506505
#
507506
# See Python 2's map function for a concrete example of this kind of overload.
508-
with experiments.strict_optional_set(True):
507+
with state.strict_optional_set(True):
509508
if is_unsafe_overlapping_overload_signatures(sig1, sig2):
510509
self.msg.overloaded_signatures_overlap(
511510
i + 1, i + j + 2, item.func)

mypy/checkmember.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
if MYPY: # import for forward declaration only
2727
import mypy.checker
2828

29-
from mypy import experiments
29+
from mypy import state
3030

3131

3232
class MemberContext:
@@ -151,10 +151,10 @@ def analyze_instance_member_access(name: str,
151151
if override_info:
152152
info = override_info
153153

154-
if (experiments.find_occurrences and
155-
info.name() == experiments.find_occurrences[0] and
156-
name == experiments.find_occurrences[1]):
157-
mx.msg.note("Occurrence of '{}.{}'".format(*experiments.find_occurrences), mx.context)
154+
if (state.find_occurrences and
155+
info.name() == state.find_occurrences[0] and
156+
name == state.find_occurrences[1]):
157+
mx.msg.note("Occurrence of '{}.{}'".format(*state.find_occurrences), mx.context)
158158

159159
# Look up the member. First look up the method dictionary.
160160
method = info.get_method(name)

mypy/experiments.py

-13
This file was deleted.

mypy/join.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
is_protocol_implementation, find_member
1515
)
1616
from mypy.nodes import ARG_NAMED, ARG_NAMED_OPT
17-
18-
from mypy import experiments
17+
from mypy import state
1918

2019

2120
def join_simple(declaration: Optional[Type], s: Type, t: Type) -> Type:
@@ -114,7 +113,7 @@ def visit_any(self, t: AnyType) -> Type:
114113
return t
115114

116115
def visit_none_type(self, t: NoneTyp) -> Type:
117-
if experiments.STRICT_OPTIONAL:
116+
if state.strict_optional:
118117
if isinstance(self.s, (NoneTyp, UninhabitedType)):
119118
return t
120119
elif isinstance(self.s, UnboundType):

mypy/main.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from mypy import build
1515
from mypy import defaults
16-
from mypy import experiments
16+
from mypy import state
1717
from mypy import util
1818
from mypy.modulefinder import BuildSource, FindModuleCache, mypy_path, SearchPaths
1919
from mypy.find_sources import create_source_list, InvalidSourceList
@@ -746,11 +746,11 @@ def add_invertible_flag(flag: str,
746746
# TODO: Deprecate, then kill this flag
747747
options.strict_optional = True
748748
if special_opts.find_occurrences:
749-
experiments.find_occurrences = special_opts.find_occurrences.split('.')
750-
assert experiments.find_occurrences is not None
751-
if len(experiments.find_occurrences) < 2:
749+
state.find_occurrences = special_opts.find_occurrences.split('.')
750+
assert state.find_occurrences is not None
751+
if len(state.find_occurrences) < 2:
752752
parser.error("Can only find occurrences of class members.")
753-
if len(experiments.find_occurrences) != 2:
753+
if len(state.find_occurrences) != 2:
754754
parser.error("Can only find occurrences of non-nested class members.")
755755

756756
# Set reports.

mypy/meet.py

+10-11
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
)
1616
from mypy.erasetype import erase_type
1717
from mypy.maptype import map_instance_to_supertype
18-
19-
from mypy import experiments
18+
from mypy import state
2019

2120
# TODO Describe this module.
2221

@@ -41,7 +40,7 @@ def narrow_declared_type(declared: Type, narrowed: Type) -> Type:
4140
for x in declared.relevant_items()])
4241
elif not is_overlapping_types(declared, narrowed,
4342
prohibit_none_typevar_overlap=True):
44-
if experiments.STRICT_OPTIONAL:
43+
if state.strict_optional:
4544
return UninhabitedType()
4645
else:
4746
return NoneTyp()
@@ -137,7 +136,7 @@ def _is_overlapping_types(left: Type, right: Type) -> bool:
137136
# When running under non-strict optional mode, simplify away types of
138137
# the form 'Union[A, B, C, None]' into just 'Union[A, B, C]'.
139138

140-
if not experiments.STRICT_OPTIONAL:
139+
if not state.strict_optional:
141140
if isinstance(left, UnionType):
142141
left = UnionType.make_union(left.relevant_items())
143142
if isinstance(right, UnionType):
@@ -191,7 +190,7 @@ def is_none_typevar_overlap(t1: Type, t2: Type) -> bool:
191190
# We must perform this check after the TypeVar checks because
192191
# a TypeVar could be bound to None, for example.
193192

194-
if experiments.STRICT_OPTIONAL and isinstance(left, NoneTyp) != isinstance(right, NoneTyp):
193+
if state.strict_optional and isinstance(left, NoneTyp) != isinstance(right, NoneTyp):
195194
return False
196195

197196
# Next, we handle single-variant types that may be inherently partially overlapping:
@@ -362,7 +361,7 @@ def __init__(self, s: Type) -> None:
362361

363362
def visit_unbound_type(self, t: UnboundType) -> Type:
364363
if isinstance(self.s, NoneTyp):
365-
if experiments.STRICT_OPTIONAL:
364+
if state.strict_optional:
366365
return AnyType(TypeOfAny.special_form)
367366
else:
368367
return self.s
@@ -386,7 +385,7 @@ def visit_union_type(self, t: UnionType) -> Type:
386385
return UnionType.make_simplified_union(meets)
387386

388387
def visit_none_type(self, t: NoneTyp) -> Type:
389-
if experiments.STRICT_OPTIONAL:
388+
if state.strict_optional:
390389
if isinstance(self.s, NoneTyp) or (isinstance(self.s, Instance) and
391390
self.s.type.fullname() == 'builtins.object'):
392391
return t
@@ -400,7 +399,7 @@ def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
400399

401400
def visit_deleted_type(self, t: DeletedType) -> Type:
402401
if isinstance(self.s, NoneTyp):
403-
if experiments.STRICT_OPTIONAL:
402+
if state.strict_optional:
404403
return t
405404
else:
406405
return self.s
@@ -430,7 +429,7 @@ def visit_instance(self, t: Instance) -> Type:
430429
args.append(self.meet(t.args[i], si.args[i]))
431430
return Instance(t.type, args)
432431
else:
433-
if experiments.STRICT_OPTIONAL:
432+
if state.strict_optional:
434433
return UninhabitedType()
435434
else:
436435
return NoneTyp()
@@ -441,7 +440,7 @@ def visit_instance(self, t: Instance) -> Type:
441440
# See also above comment.
442441
return self.s
443442
else:
444-
if experiments.STRICT_OPTIONAL:
443+
if state.strict_optional:
445444
return UninhabitedType()
446445
else:
447446
return NoneTyp()
@@ -559,7 +558,7 @@ def default(self, typ: Type) -> Type:
559558
if isinstance(typ, UnboundType):
560559
return AnyType(TypeOfAny.special_form)
561560
else:
562-
if experiments.STRICT_OPTIONAL:
561+
if state.strict_optional:
563562
return UninhabitedType()
564563
else:
565564
return NoneTyp()

mypy/semanal.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
from mypy.exprtotype import expr_to_unanalyzed_type, TypeTranslationError
7878
from mypy.sametypes import is_same_type
7979
from mypy.options import Options
80-
from mypy import experiments
80+
from mypy import state
8181
from mypy.plugin import (
8282
Plugin, ClassDefContext, SemanticAnalyzerPluginInterface,
8383
DynamicClassDefContext
@@ -283,7 +283,7 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options,
283283
self.enum_call_analyzer = EnumCallAnalyzer(options, self)
284284
self.newtype_analyzer = NewTypeAnalyzer(options, self, self.msg)
285285

286-
with experiments.strict_optional_set(options.strict_optional):
286+
with state.strict_optional_set(options.strict_optional):
287287
if 'builtins' in self.modules:
288288
self.globals['__builtins__'] = SymbolTableNode(MODULE_REF,
289289
self.modules['builtins'])

mypy/semanal_pass1.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from typing import List, Tuple
2121

22-
from mypy import experiments
22+
from mypy import state
2323
from mypy.nodes import (
2424
MypyFile, SymbolTable, SymbolTableNode, Var, Block, AssignmentStmt, FuncDef, Decorator,
2525
ClassDef, TypeInfo, ImportFrom, Import, ImportAll, IfStmt, WhileStmt, ForStmt, WithStmt,
@@ -76,7 +76,7 @@ def visit_file(self, file: MypyFile, fnam: str, mod_id: str, options: Options) -
7676

7777
defs = file.defs
7878

79-
with experiments.strict_optional_set(options.strict_optional):
79+
with state.strict_optional_set(options.strict_optional):
8080
# Add implicit definitions of module '__name__' etc.
8181
for name, t in implicit_module_attrs.items():
8282
# unicode docstrings should be accepted in Python 2

mypy/semanal_pass3.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from collections import OrderedDict
1313
from typing import Dict, List, Callable, Optional, Union, cast, Tuple
1414

15-
from mypy import messages, experiments
15+
from mypy import messages, state
1616
from mypy.nodes import (
1717
Node, Expression, MypyFile, FuncDef, Decorator, RefExpr, Context, TypeInfo, ClassDef,
1818
Block, TypedDictExpr, NamedTupleExpr, AssignmentStmt, IndexExpr, TypeAliasExpr, NameExpr,
@@ -65,7 +65,7 @@ def visit_file(self, file_node: MypyFile, fnam: str, options: Options,
6565
self.sem.cur_mod_id = file_node.fullname()
6666
self.cur_mod_node = file_node
6767
self.sem.globals = file_node.names
68-
with experiments.strict_optional_set(options.strict_optional):
68+
with state.strict_optional_set(options.strict_optional):
6969
self.scope.enter_file(file_node.fullname())
7070
self.update_imported_vars()
7171
self.accept(file_node)

mypy/state.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from contextlib import contextmanager
2+
from typing import Optional, Tuple, Iterator
3+
4+
# These are global mutable state. Don't add anything here unless there's a very
5+
# good reason.
6+
7+
# Value varies by file being processed
8+
strict_optional = False
9+
find_occurrences = None # type: Optional[Tuple[str, str]]
10+
11+
12+
@contextmanager
13+
def strict_optional_set(value: bool) -> Iterator[None]:
14+
global strict_optional
15+
saved = strict_optional
16+
strict_optional = value
17+
yield
18+
strict_optional = saved

mypy/subtypes.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121
from mypy.expandtype import expand_type_by_instance
2222
from mypy.sametypes import is_same_type
2323
from mypy.typestate import TypeState, SubtypeKind
24-
25-
from mypy import experiments
24+
from mypy import state
2625

2726
MYPY = False
2827
if MYPY:
@@ -165,7 +164,7 @@ def visit_any(self, left: AnyType) -> bool:
165164
return True
166165

167166
def visit_none_type(self, left: NoneTyp) -> bool:
168-
if experiments.STRICT_OPTIONAL:
167+
if state.strict_optional:
169168
return (isinstance(self.right, NoneTyp) or
170169
is_named_instance(self.right, 'builtins.object') or
171170
isinstance(self.right, Instance) and self.right.type.is_protocol and
@@ -1060,7 +1059,7 @@ def visit_any(self, left: AnyType) -> bool:
10601059
return isinstance(self.right, AnyType)
10611060

10621061
def visit_none_type(self, left: NoneTyp) -> bool:
1063-
if experiments.STRICT_OPTIONAL:
1062+
if state.strict_optional:
10641063
return (isinstance(self.right, NoneTyp) or
10651064
is_named_instance(self.right, 'builtins.object'))
10661065
return True

mypy/test/testtypes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from mypy.nodes import ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2, CONTRAVARIANT, INVARIANT, COVARIANT
1616
from mypy.subtypes import is_subtype, is_more_precise, is_proper_subtype
1717
from mypy.test.typefixture import TypeFixture, InterfaceTypeFixture
18-
from mypy.experiments import strict_optional_set
18+
from mypy.state import strict_optional_set
1919

2020

2121
class TypesSuite(Suite):

mypy/types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from typing_extensions import Final
1515

1616
import mypy.nodes
17-
from mypy import experiments
17+
from mypy import state
1818
from mypy.nodes import (
1919
INVARIANT, SymbolNode, ARG_POS, ARG_OPT, ARG_STAR, ARG_STAR2, ARG_NAMED, ARG_NAMED_OPT,
2020
FuncDef,
@@ -1538,7 +1538,7 @@ def has_readable_member(self, name: str) -> bool:
15381538

15391539
def relevant_items(self) -> List[Type]:
15401540
"""Removes NoneTypes from Unions when strict Optional checking is off."""
1541-
if experiments.STRICT_OPTIONAL:
1541+
if state.strict_optional:
15421542
return self.items
15431543
else:
15441544
return [i for i in self.items if not isinstance(i, NoneTyp)]

0 commit comments

Comments
 (0)