Skip to content

Commit cb0ceb0

Browse files
authored
Allow strict in config, explicitly disallow inline (#8192)
1 parent 310f9e3 commit cb0ceb0

File tree

5 files changed

+52
-13
lines changed

5 files changed

+52
-13
lines changed

mypy/config_parser.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import re
77
import sys
88

9-
from typing import Any, Dict, List, Mapping, Optional, Tuple, TextIO
9+
from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, TextIO
1010
from typing_extensions import Final
1111

1212
from mypy import defaults
@@ -88,7 +88,8 @@ def split_and_match_files(paths: str) -> List[str]:
8888
} # type: Final
8989

9090

91-
def parse_config_file(options: Options, filename: Optional[str],
91+
def parse_config_file(options: Options, set_strict_flags: Callable[[], None],
92+
filename: Optional[str],
9293
stdout: Optional[TextIO] = None,
9394
stderr: Optional[TextIO] = None) -> None:
9495
"""Parse a config file into an Options object.
@@ -127,15 +128,16 @@ def parse_config_file(options: Options, filename: Optional[str],
127128
else:
128129
section = parser['mypy']
129130
prefix = '%s: [%s]: ' % (file_read, 'mypy')
130-
updates, report_dirs = parse_section(prefix, options, section, stderr)
131+
updates, report_dirs = parse_section(prefix, options, set_strict_flags, section, stderr)
131132
for k, v in updates.items():
132133
setattr(options, k, v)
133134
options.report_dirs.update(report_dirs)
134135

135136
for name, section in parser.items():
136137
if name.startswith('mypy-'):
137138
prefix = '%s: [%s]: ' % (file_read, name)
138-
updates, report_dirs = parse_section(prefix, options, section, stderr)
139+
updates, report_dirs = parse_section(
140+
prefix, options, set_strict_flags, section, stderr)
139141
if report_dirs:
140142
print("%sPer-module sections should not specify reports (%s)" %
141143
(prefix, ', '.join(s + '_report' for s in sorted(report_dirs))),
@@ -163,6 +165,7 @@ def parse_config_file(options: Options, filename: Optional[str],
163165

164166

165167
def parse_section(prefix: str, template: Options,
168+
set_strict_flags: Callable[[], None],
166169
section: Mapping[str, str],
167170
stderr: TextIO = sys.stderr
168171
) -> Tuple[Dict[str, object], Dict[str, str]]:
@@ -205,9 +208,7 @@ def parse_section(prefix: str, template: Options,
205208
options_key = key[3:]
206209
invert = True
207210
elif key == 'strict':
208-
print("%sStrict mode is not supported in configuration files: specify "
209-
"individual flags instead (see 'mypy -h' for the list of flags enabled "
210-
"in strict mode)" % prefix, file=stderr)
211+
set_strict_flags()
211212
else:
212213
print("%sUnrecognized option: %s = %s" % (prefix, key, section[key]),
213214
file=stderr)
@@ -330,10 +331,23 @@ def parse_mypy_comments(
330331
errors.extend((lineno, x) for x in parse_errors)
331332

332333
stderr = StringIO()
333-
new_sections, reports = parse_section('', template, parser['dummy'], stderr=stderr)
334+
strict_found = False
335+
336+
def set_strict_flags() -> None:
337+
nonlocal strict_found
338+
strict_found = True
339+
340+
new_sections, reports = parse_section(
341+
'', template, set_strict_flags, parser['dummy'], stderr=stderr)
334342
errors.extend((lineno, x) for x in stderr.getvalue().strip().split('\n') if x)
335343
if reports:
336344
errors.append((lineno, "Reports not supported in inline configuration"))
345+
if strict_found:
346+
errors.append((lineno,
347+
"Setting 'strict' not supported in inline configuration: specify it in "
348+
"a configuration file instead, or set individual inline flags "
349+
"(see 'mypy -h' for the list of flags enabled in strict mode)"))
350+
337351
sections.update(new_sections)
338352

339353
return sections, errors

mypy/main.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -806,15 +806,19 @@ def add_invertible_flag(flag: str,
806806
if config_file and not os.path.exists(config_file):
807807
parser.error("Cannot find config file '%s'" % config_file)
808808

809-
# Parse config file first, so command line can override.
810809
options = Options()
811-
parse_config_file(options, config_file, stdout, stderr)
810+
811+
def set_strict_flags() -> None:
812+
for dest, value in strict_flag_assignments:
813+
setattr(options, dest, value)
814+
815+
# Parse config file first, so command line can override.
816+
parse_config_file(options, set_strict_flags, config_file, stdout, stderr)
812817

813818
# Set strict flags before parsing (if strict mode enabled), so other command
814819
# line options can override.
815820
if getattr(dummy, 'special-opts:strict'): # noqa
816-
for dest, value in strict_flag_assignments:
817-
setattr(options, dest, value)
821+
set_strict_flags()
818822

819823
# Override cache_dir if provided in the environment
820824
environ_cache_dir = os.getenv('MYPY_CACHE_DIR', '')

mypy/test/testfinegrained.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def get_options(self,
193193

194194
for name, _ in testcase.files:
195195
if 'mypy.ini' in name:
196-
parse_config_file(options, name)
196+
parse_config_file(options, lambda: None, name)
197197
break
198198

199199
return options

test-data/unit/check-flags.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,22 @@ def f(c: A) -> None: # E: Missing type parameters for generic type "A"
11491149
pass
11501150
[out]
11511151

1152+
[case testStrictInConfigAnyGeneric]
1153+
# flags: --config-file tmp/mypy.ini
1154+
from typing import TypeVar, Generic
1155+
1156+
T = TypeVar('T')
1157+
1158+
class A(Generic[T]):
1159+
pass
1160+
1161+
def f(c: A) -> None: # E: Missing type parameters for generic type "A"
1162+
pass
1163+
[file mypy.ini]
1164+
\[mypy]
1165+
strict = True
1166+
[out]
1167+
11521168
[case testStrictAndStrictEquality]
11531169
# flags: --strict
11541170
x = 0

test-data/unit/check-inline-config.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,8 @@ main:4: error: Unterminated quote in configuration comment
157157
# mypy: skip-file
158158
[out]
159159
main:1: error: Unrecognized option: skip_file = True
160+
161+
[case testInlineStrict]
162+
# mypy: strict
163+
[out]
164+
main:1: error: Setting 'strict' not supported in inline configuration: specify it in a configuration file instead, or set individual inline flags (see 'mypy -h' for the list of flags enabled in strict mode)

0 commit comments

Comments
 (0)