Skip to content
Draft
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
18 changes: 13 additions & 5 deletions mypy/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def _find_config_file(

def parse_config_file(
options: Options,
set_strict_flags: Callable[[], None],
strict_flag_assignments: Sequence[tuple[str, object]],
filename: str | None,
stdout: TextIO | None = None,
stderr: TextIO | None = None,
Expand All @@ -327,6 +327,9 @@ def parse_config_file(
options.config_file = file_read
os.environ["MYPY_CONFIG_FILE_DIR"] = os.path.dirname(os.path.abspath(file_read))

def set_strict_flags(updates: dict[str, object]) -> None:
updates.update(strict_flag_assignments)

if "mypy" not in parser:
if filename or os.path.basename(file_read) not in defaults.SHARED_CONFIG_NAMES:
print(f"{file_read}: No [mypy] section in config file", file=stderr)
Expand All @@ -340,11 +343,16 @@ def parse_config_file(
setattr(options, k, v)
options.report_dirs.update(report_dirs)

def set_strict_flags_section(updates: dict[str, object]) -> None:
for dest, value in strict_flag_assignments:
if dest in PER_MODULE_OPTIONS:
updates[dest] = value

for name, section in parser.items():
if name.startswith("mypy-"):
prefix = get_prefix(file_read, name)
updates, report_dirs = parse_section(
prefix, options, set_strict_flags, section, config_types, stderr
prefix, options, set_strict_flags_section, section, config_types, stderr
)
if report_dirs:
print(
Expand Down Expand Up @@ -483,7 +491,7 @@ def destructure_overrides(toml_data: dict[str, Any]) -> dict[str, Any]:
def parse_section(
prefix: str,
template: Options,
set_strict_flags: Callable[[], None],
set_strict_flags: Callable[[dict[str, object]], None],
section: Mapping[str, Any],
config_types: dict[str, Any],
stderr: TextIO = sys.stderr,
Expand Down Expand Up @@ -576,7 +584,7 @@ def parse_section(
continue
if key == "strict":
if v:
set_strict_flags()
set_strict_flags(results)
continue
results[options_key] = v

Expand Down Expand Up @@ -675,7 +683,7 @@ def parse_mypy_comments(
stderr = StringIO()
strict_found = False

def set_strict_flags() -> None:
def set_strict_flags(updates: dict[str, object]) -> None:
nonlocal strict_found
strict_found = True

Expand Down
15 changes: 3 additions & 12 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1397,21 +1397,15 @@ def process_options(
parser.error(f"Cannot find config file '{config_file}'")

options = Options()
strict_option_set = False

def set_strict_flags() -> None:
nonlocal strict_option_set
strict_option_set = True
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)
parse_config_file(options, strict_flag_assignments, 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"):
set_strict_flags()
for dest, value in strict_flag_assignments:
setattr(options, dest, value)

# Override cache_dir if provided in the environment
environ_cache_dir = os.getenv("MYPY_CACHE_DIR", "")
Expand Down Expand Up @@ -1529,9 +1523,6 @@ def set_strict_flags() -> None:
if options.logical_deps:
options.cache_fine_grained = True

if options.strict_concatenate and not strict_option_set:
print("Warning: --strict-concatenate is deprecated; use --extra-checks instead")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks unrelated, why is it needed?


# Set target.
if special_opts.modules + special_opts.packages:
options.build_type = BuildType.MODULE
Expand Down
2 changes: 1 addition & 1 deletion mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def __init__(self) -> None:
# Disable treating bytearray and memoryview as subtypes of bytes
self.strict_bytes = False

# Deprecated, use extra_checks instead.
# Make arguments prepended via Concatenate be truly positional-only.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, looks unrelated.

self.strict_concatenate = False

# Enable additional checks that are technically correct but impractical.
Expand Down
7 changes: 2 additions & 5 deletions mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2279,15 +2279,12 @@ def test_stubs(args: _Arguments, use_builtins_fixtures: bool = False) -> int:
options.abs_custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir)
options.config_file = args.mypy_config_file
options.use_builtins_fixtures = use_builtins_fixtures
options.per_module_options = {}
options.show_traceback = args.show_traceback
options.pdb = args.pdb

if options.config_file:

def set_strict_flags() -> None: # not needed yet
return

parse_config_file(options, set_strict_flags, options.config_file, sys.stdout, sys.stderr)
parse_config_file(options, [], options.config_file, sys.stdout, sys.stderr)

def error_callback(msg: str) -> typing.NoReturn:
print(_style("error:", color="red", bold=True), msg)
Expand Down
2 changes: 1 addition & 1 deletion mypy/test/testfinegrained.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def get_options(self, source: str, testcase: DataDrivenTestCase, build_cache: bo

for name, _ in testcase.files:
if "mypy.ini" in name or "pyproject.toml" in name:
parse_config_file(options, lambda: None, name)
parse_config_file(options, [], name)
break

return options
Expand Down
27 changes: 27 additions & 0 deletions test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -2152,6 +2152,33 @@ disallow_subclassing_any = true
module = 'm'
disallow_subclassing_any = false

[case testStrictPerModule]
# flags: --config-file tmp/mypy.ini

import strictmodule
import loosemodule
a = 0 # type: ignore

[file strictmodule.py]
def foo(): # E: Function is missing a return type annotation \
# N: Use "-> None" if function does not return a value
1 + "asdf" # E: Unsupported operand types for + ("int" and "str")

a = 0 # type: ignore # E: Unused "type: ignore" comment


[file loosemodule.py]
def foo():
1 + "asdf"

a = 0 # type: ignore
1 + "asdf" # E: Unsupported operand types for + ("int" and "str")

[file mypy.ini]
[mypy]
strict = False
[mypy-strictmodule]
strict = True

[case testNoImplicitOptionalPerModule]
# flags: --config-file tmp/mypy.ini
Expand Down
Loading