Skip to content

Allow strict in config, explicitly disallow inline #8192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow strict in config, explicitly disallow inline
  • Loading branch information
scop committed Jan 19, 2020
commit 2684385499691aab7c95250544f62b9adf8a95be
26 changes: 18 additions & 8 deletions mypy/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import re
import sys

from typing import Any, Dict, List, Mapping, Optional, Tuple, TextIO
from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple, TextIO
from typing_extensions import Final

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


def parse_config_file(options: Options, filename: Optional[str],
def parse_config_file(options: Options, set_strict_flags: Callable[[], None],
filename: Optional[str],
stdout: Optional[TextIO] = None,
stderr: Optional[TextIO] = None) -> None:
"""Parse a config file into an Options object.
Expand Down Expand Up @@ -127,15 +128,16 @@ def parse_config_file(options: Options, filename: Optional[str],
else:
section = parser['mypy']
prefix = '%s: [%s]: ' % (file_read, 'mypy')
updates, report_dirs = parse_section(prefix, options, section, stderr)
updates, report_dirs = parse_section(prefix, options, set_strict_flags, section, stderr)
for k, v in updates.items():
setattr(options, k, v)
options.report_dirs.update(report_dirs)

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


def parse_section(prefix: str, template: Options,
set_strict_flags: Callable[[], None],
section: Mapping[str, str],
stderr: TextIO = sys.stderr
) -> Tuple[Dict[str, object], Dict[str, str]]:
Expand Down Expand Up @@ -205,9 +208,7 @@ def parse_section(prefix: str, template: Options,
options_key = key[3:]
invert = True
elif key == 'strict':
print("%sStrict mode is not supported in configuration files: specify "
"individual flags instead (see 'mypy -h' for the list of flags enabled "
"in strict mode)" % prefix, file=stderr)
set_strict_flags()
else:
print("%sUnrecognized option: %s = %s" % (prefix, key, section[key]),
file=stderr)
Expand Down Expand Up @@ -330,10 +331,19 @@ def parse_mypy_comments(
errors.extend((lineno, x) for x in parse_errors)

stderr = StringIO()
new_sections, reports = parse_section('', template, parser['dummy'], stderr=stderr)
strict_found = False

def set_strict_flags() -> None:
nonlocal strict_found
strict_found = True

new_sections, reports = parse_section(
'', template, set_strict_flags, parser['dummy'], stderr=stderr)
errors.extend((lineno, x) for x in stderr.getvalue().strip().split('\n') if x)
if reports:
errors.append((lineno, "Reports not supported in inline configuration"))
if strict_found:
errors.append((lineno, "Setting 'strict' not supported in inline configuration"))
sections.update(new_sections)

return sections, errors
12 changes: 8 additions & 4 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -806,15 +806,19 @@ def add_invertible_flag(flag: str,
if config_file and not os.path.exists(config_file):
parser.error("Cannot find config file '%s'" % config_file)

# Parse config file first, so command line can override.
options = Options()
parse_config_file(options, config_file, stdout, stderr)

def set_strict_flags() -> None:
for dest, value in strict_flag_assignments:
setattr(options, dest, value)

# Parse config file first, so command line can override.
parse_config_file(options, set_strict_flags, config_file, stdout, stderr)

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

# Override cache_dir if provided in the environment
environ_cache_dir = os.getenv('MYPY_CACHE_DIR', '')
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testfinegrained.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def get_options(self,

for name, _ in testcase.files:
if 'mypy.ini' in name:
parse_config_file(options, name)
parse_config_file(options, lambda: None, name)
break

return options
Expand Down
16 changes: 16 additions & 0 deletions test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,22 @@ def f(c: A) -> None: # E: Missing type parameters for generic type "A"
pass
[out]

[case testStrictInConfigAnyGeneric]
# flags: --config-file tmp/mypy.ini
from typing import TypeVar, Generic

T = TypeVar('T')

class A(Generic[T]):
pass

def f(c: A) -> None: # E: Missing type parameters for generic type "A"
pass
[file mypy.ini]
\[mypy]
strict = True
[out]

[case testStrictAndStrictEquality]
# flags: --strict
x = 0
Expand Down
5 changes: 5 additions & 0 deletions test-data/unit/check-inline-config.test
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,8 @@ main:4: error: Unterminated quote in configuration comment
# mypy: skip-file
[out]
main:1: error: Unrecognized option: skip_file = True

[case testInlineStrict]
# mypy: strict
[out]
main:1: error: Setting 'strict' not supported in inline configuration