Skip to content

Commit 21f71eb

Browse files
ilevkivskyigvanrossum
authored andcommitted
[clean strict optional] Fix some strict optional errors in mypy (#3228)
This PR fixes 26 ``--strict-optional`` errors in mypy itself (out of 547 total) in following files: * stubgen.py * stubgenc.py * checkstrformat.py * report.py * strconv.py
1 parent fde3a0c commit 21f71eb

File tree

7 files changed

+43
-35
lines changed

7 files changed

+43
-35
lines changed

mypy/checkstrformat.py

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

33
import re
44

5-
from typing import cast, List, Tuple, Dict, Callable, Union
5+
from typing import cast, List, Tuple, Dict, Callable, Union, Optional
66

77
from mypy.types import (
88
Type, AnyType, TupleType, Instance, UnionType
@@ -18,6 +18,7 @@
1818
from mypy.messages import MessageBuilder
1919

2020
FormatStringExpr = Union[StrExpr, BytesExpr, UnicodeExpr]
21+
Checkers = Tuple[Callable[[Expression], None], Callable[[Type], None]]
2122

2223

2324
class ConversionSpecifier:
@@ -105,7 +106,7 @@ def parse_conversion_specifiers(self, format: str) -> List[ConversionSpecifier]:
105106
return specifiers
106107

107108
def analyze_conversion_specifiers(self, specifiers: List[ConversionSpecifier],
108-
context: Context) -> bool:
109+
context: Context) -> Optional[bool]:
109110
has_star = any(specifier.has_star() for specifier in specifiers)
110111
has_key = any(specifier.has_key() for specifier in specifiers)
111112
all_have_keys = all(
@@ -192,9 +193,8 @@ def check_mapping_str_interpolation(self, specifiers: List[ConversionSpecifier],
192193

193194
def build_replacement_checkers(self, specifiers: List[ConversionSpecifier],
194195
context: Context, expr: FormatStringExpr
195-
) -> List[Tuple[Callable[[Expression], None],
196-
Callable[[Type], None]]]:
197-
checkers = [] # type: List[Tuple[Callable[[Expression], None], Callable[[Type], None]]]
196+
) -> Optional[List[Checkers]]:
197+
checkers = [] # type: List[Checkers]
198198
for specifier in specifiers:
199199
checker = self.replacement_checkers(specifier, context, expr)
200200
if checker is None:
@@ -203,13 +203,12 @@ def build_replacement_checkers(self, specifiers: List[ConversionSpecifier],
203203
return checkers
204204

205205
def replacement_checkers(self, specifier: ConversionSpecifier, context: Context,
206-
expr: FormatStringExpr) -> List[Tuple[Callable[[Expression], None],
207-
Callable[[Type], None]]]:
206+
expr: FormatStringExpr) -> Optional[List[Checkers]]:
208207
"""Returns a list of tuples of two functions that check whether a replacement is
209208
of the right type for the specifier. The first functions take a node and checks
210209
its type in the right type context. The second function just checks a type.
211210
"""
212-
checkers = [] # type: List[Tuple[Callable[[Expression], None], Callable[[Type], None]]]
211+
checkers = [] # type: List[Checkers]
213212

214213
if specifier.width == '*':
215214
checkers.append(self.checkers_for_star(context))
@@ -227,14 +226,13 @@ def replacement_checkers(self, specifier: ConversionSpecifier, context: Context,
227226
checkers.append(c)
228227
return checkers
229228

230-
def checkers_for_star(self, context: Context) -> Tuple[Callable[[Expression], None],
231-
Callable[[Type], None]]:
229+
def checkers_for_star(self, context: Context) -> Checkers:
232230
"""Returns a tuple of check functions that check whether, respectively,
233231
a node or a type is compatible with a star in a conversion specifier
234232
"""
235233
expected = self.named_type('builtins.int')
236234

237-
def check_type(type: Type = None) -> None:
235+
def check_type(type: Type) -> None:
238236
expected = self.named_type('builtins.int')
239237
self.chk.check_subtype(type, expected, context, '* wants int')
240238

@@ -246,16 +244,16 @@ def check_expr(expr: Expression) -> None:
246244

247245
def checkers_for_regular_type(self, type: str,
248246
context: Context,
249-
expr: FormatStringExpr) -> Tuple[Callable[[Expression], None],
250-
Callable[[Type], None]]:
247+
expr: FormatStringExpr) -> Optional[Checkers]:
251248
"""Returns a tuple of check functions that check whether, respectively,
252249
a node or a type is compatible with 'type'. Return None in case of an
253250
"""
254251
expected_type = self.conversion_type(type, context, expr)
255252
if expected_type is None:
256253
return None
257254

258-
def check_type(type: Type = None) -> None:
255+
def check_type(type: Type) -> None:
256+
assert expected_type is not None
259257
self.chk.check_subtype(type, expected_type, context,
260258
messages.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION,
261259
'expression has type', 'placeholder has type')
@@ -268,16 +266,16 @@ def check_expr(expr: Expression) -> None:
268266

269267
def checkers_for_c_type(self, type: str,
270268
context: Context,
271-
expr: FormatStringExpr) -> Tuple[Callable[[Expression], None],
272-
Callable[[Type], None]]:
269+
expr: FormatStringExpr) -> Optional[Checkers]:
273270
"""Returns a tuple of check functions that check whether, respectively,
274271
a node or a type is compatible with 'type' that is a character type
275272
"""
276273
expected_type = self.conversion_type(type, context, expr)
277274
if expected_type is None:
278275
return None
279276

280-
def check_type(type: Type = None) -> None:
277+
def check_type(type: Type) -> None:
278+
assert expected_type is not None
281279
self.chk.check_subtype(type, expected_type, context,
282280
messages.INCOMPATIBLE_TYPES_IN_STR_INTERPOLATION,
283281
'expression has type', 'placeholder has type')
@@ -291,7 +289,7 @@ def check_expr(expr: Expression) -> None:
291289

292290
return check_expr, check_type
293291

294-
def conversion_type(self, p: str, context: Context, expr: FormatStringExpr) -> Type:
292+
def conversion_type(self, p: str, context: Context, expr: FormatStringExpr) -> Optional[Type]:
295293
"""Return the type that is accepted for a string interpolation
296294
conversion specifier type.
297295

mypy/parse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
def parse(source: Union[str, bytes],
99
fnam: str,
10-
errors: Errors,
10+
errors: Optional[Errors],
1111
options: Options) -> MypyFile:
1212
"""Parse a source file, without doing any semantic analysis.
1313

mypy/report.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
200200
if cur_indent is None:
201201
# Consume the line, but don't mark it as belonging to the function yet.
202202
cur_line += 1
203-
elif cur_indent > start_indent:
203+
elif start_indent is not None and cur_indent > start_indent:
204204
# A non-blank line that belongs to the function.
205205
cur_line += 1
206206
end_line = cur_line
@@ -211,7 +211,7 @@ def visit_func_def(self, defn: FuncDef) -> None:
211211
is_typed = defn.type is not None
212212
for line in range(start_line, end_line):
213213
old_indent, _ = self.lines_covered[line]
214-
assert start_indent > old_indent
214+
assert start_indent is not None and start_indent > old_indent
215215
self.lines_covered[line] = (start_indent, is_typed)
216216

217217
# Visit the body, in case there are nested functions
@@ -304,7 +304,7 @@ def __init__(self, reports: Reports, output_dir: str) -> None:
304304
self.css_html_path = os.path.join(reports.data_dir, 'xml', 'mypy-html.css')
305305
xsd_path = os.path.join(reports.data_dir, 'xml', 'mypy.xsd')
306306
self.schema = etree.XMLSchema(etree.parse(xsd_path))
307-
self.last_xml = None # type: etree._ElementTree
307+
self.last_xml = None # type: Optional[etree._ElementTree]
308308
self.files = [] # type: List[FileInfo]
309309

310310
def on_file(self,
@@ -532,6 +532,7 @@ def on_file(self,
532532

533533
def on_finish(self) -> None:
534534
last_xml = self.memory_xml.last_xml
535+
assert last_xml is not None
535536
out_path = os.path.join(self.output_dir, 'index.xml')
536537
out_xslt = os.path.join(self.output_dir, 'mypy-html.xslt')
537538
out_css = os.path.join(self.output_dir, 'mypy-html.css')
@@ -575,6 +576,7 @@ def on_file(self,
575576

576577
def on_finish(self) -> None:
577578
last_xml = self.memory_xml.last_xml
579+
assert last_xml is not None
578580
out_path = os.path.join(self.output_dir, 'index.html')
579581
out_css = os.path.join(self.output_dir, 'mypy-html.css')
580582
transformed_html = bytes(self.xslt_html(last_xml, ext=self.param_html))
@@ -606,6 +608,7 @@ def on_file(self,
606608

607609
def on_finish(self) -> None:
608610
last_xml = self.memory_xml.last_xml
611+
assert last_xml is not None
609612
out_path = os.path.join(self.output_dir, 'index.txt')
610613
stats.ensure_dir_exists(os.path.dirname(out_path))
611614
transformed_txt = bytes(self.xslt_txt(last_xml))

mypy/strconv.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ class StrConv(NodeVisitor[str]):
2424

2525
def __init__(self, show_ids: bool = False) -> None:
2626
self.show_ids = show_ids
27+
self.id_mapper = None # type: Optional[IdMapper]
2728
if show_ids:
2829
self.id_mapper = IdMapper()
29-
else:
30-
self.id_mapper = None
3130

32-
def get_id(self, o: object) -> int:
33-
return self.id_mapper.id(o)
31+
def get_id(self, o: object) -> Optional[int]:
32+
if self.id_mapper:
33+
return self.id_mapper.id(o)
34+
return None
3435

3536
def format_id(self, o: object) -> str:
3637
if self.id_mapper:
@@ -47,6 +48,7 @@ def dump(self, nodes: Sequence[object], obj: 'mypy.nodes.Context') -> str:
4748
"""
4849
tag = short_type(obj) + ':' + str(obj.get_line())
4950
if self.show_ids:
51+
assert self.id_mapper is not None
5052
tag += '<{}>'.format(self.get_id(obj))
5153
return dump_tagged(nodes, tag, self)
5254

@@ -504,7 +506,7 @@ def visit_backquote_expr(self, o: 'mypy.nodes.BackquoteExpr') -> str:
504506
return self.dump([o.expr], o)
505507

506508

507-
def dump_tagged(nodes: Sequence[object], tag: str, str_conv: 'StrConv') -> str:
509+
def dump_tagged(nodes: Sequence[object], tag: Optional[str], str_conv: 'StrConv') -> str:
508510
"""Convert an array into a pretty-printed multiline string representation.
509511
510512
The format is

mypy/stubgen.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,10 @@ def visit_decorator(self, o: Decorator) -> None:
311311
super().visit_decorator(o)
312312

313313
def visit_class_def(self, o: ClassDef) -> None:
314+
sep = None # type: Optional[int]
314315
if not self._indent and self._state != EMPTY:
315316
sep = len(self._output)
316317
self.add('\n')
317-
else:
318-
sep = None
319318
self.add('%sclass %s' % (self._indent, o.name))
320319
self.record_name(o.name)
321320
base_types = self.get_base_types(o)
@@ -465,7 +464,7 @@ def visit_import(self, o: Import) -> None:
465464
self.add_import_line('import %s as %s\n' % (id, target_name))
466465
self.record_name(target_name)
467466

468-
def get_init(self, lvalue: str, rvalue: Expression) -> str:
467+
def get_init(self, lvalue: str, rvalue: Expression) -> Optional[str]:
469468
"""Return initializer for a variable.
470469
471470
Return None if we've generated one already or if the variable is internal.
@@ -511,7 +510,9 @@ def output(self) -> str:
511510
def is_not_in_all(self, name: str) -> bool:
512511
if self.is_private_name(name):
513512
return False
514-
return self.is_top_level() and bool(self._all_) and name not in self._all_
513+
if self._all_:
514+
return self.is_top_level() and name not in self._all_
515+
return False
515516

516517
def is_private_name(self, name: str) -> bool:
517518
return name.startswith('_') and (not name.endswith('__')

mypy/stubgenc.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,15 @@ def generate_c_function_stub(module: ModuleType,
111111
self_arg = '%s, ' % self_var
112112
else:
113113
self_arg = ''
114-
if name in ('__new__', '__init__') and name not in sigs and class_name in class_sigs:
114+
if (name in ('__new__', '__init__') and name not in sigs and class_name and
115+
class_name in class_sigs):
115116
sig = class_sigs[class_name]
116117
else:
117118
docstr = getattr(obj, '__doc__', None)
118-
sig = infer_sig_from_docstring(docstr, name)
119-
if not sig:
119+
inferred = infer_sig_from_docstring(docstr, name)
120+
if inferred:
121+
sig = inferred
122+
else:
120123
if class_name and name not in sigs:
121124
sig = infer_method_sig(name)
122125
else:

mypy/stubutil.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ def is_c_module(module: ModuleType) -> bool:
9090
return '__file__' not in module.__dict__ or module.__dict__['__file__'].endswith('.so')
9191

9292

93-
def write_header(file: IO[str], module_name: str, pyversion: Tuple[int, int] = (3, 5)) -> None:
93+
def write_header(file: IO[str], module_name: Optional[str] = None,
94+
pyversion: Tuple[int, int] = (3, 5)) -> None:
9495
if module_name:
9596
if pyversion[0] >= 3:
9697
version = '%d.%d' % (sys.version_info.major,

0 commit comments

Comments
 (0)