From 6afea649adb6dd8ebe6ee18a6757ba689ffc13d2 Mon Sep 17 00:00:00 2001 From: Ian Good Date: Sun, 13 Feb 2022 18:13:15 -0500 Subject: [PATCH 1/7] Support module-level `strict` config flag The current behavior of `strict = True` in a module-level config section actually enables all strictness flags globally, which seems like a bug. This change changes a module-level `strict = True` option to act as though all of the per-module strictness flags were enabled. --- mypy/config_parser.py | 17 +++++++++++------ mypy/main.py | 10 ++++++---- mypy/stubtest.py | 4 ++-- mypy/test/testfinegrained.py | 2 +- mypy/test/teststubtest.py | 14 ++++++++++++++ 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index fa57caee14a4..eab5e003224f 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -1,5 +1,6 @@ import argparse import configparser +from functools import partial import glob as fileglob from io import StringIO import os @@ -153,7 +154,8 @@ def check_follow_imports(choice: str) -> str: }) -def parse_config_file(options: Options, set_strict_flags: Callable[[], None], +def parse_config_file(options: Options, + set_strict_flags: Callable[[bool, Dict[str, object]], None], filename: Optional[str], stdout: Optional[TextIO] = None, stderr: Optional[TextIO] = None) -> None: @@ -205,6 +207,9 @@ def parse_config_file(options: Options, set_strict_flags: Callable[[], None], os.environ['MYPY_CONFIG_FILE_DIR'] = os.path.dirname( os.path.abspath(config_file)) + set_strict_flags_toplevel = partial(set_strict_flags, True) + set_strict_flags_module = partial(set_strict_flags, False) + if 'mypy' not in parser: if filename or file_read not in defaults.SHARED_CONFIG_FILES: print("%s: No [mypy] section in config file" % file_read, file=stderr) @@ -212,7 +217,7 @@ def parse_config_file(options: Options, set_strict_flags: Callable[[], None], section = parser['mypy'] prefix = '%s: [%s]: ' % (file_read, 'mypy') updates, report_dirs = parse_section( - prefix, options, set_strict_flags, section, config_types, stderr) + prefix, options, set_strict_flags_toplevel, section, config_types, stderr) for k, v in updates.items(): setattr(options, k, v) options.report_dirs.update(report_dirs) @@ -221,7 +226,7 @@ def parse_config_file(options: Options, set_strict_flags: Callable[[], None], 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_module, section, config_types, stderr) if report_dirs: print("%sPer-module sections should not specify reports (%s)" % (prefix, ', '.join(s + '_report' for s in sorted(report_dirs))), @@ -336,7 +341,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 @@ -416,7 +421,7 @@ def parse_section(prefix: str, template: Options, continue if key == 'strict': if v: - set_strict_flags() + set_strict_flags(results) continue if key == 'silent_imports': print("%ssilent_imports has been replaced by " @@ -523,7 +528,7 @@ def parse_mypy_comments( stderr = StringIO() strict_found = False - def set_strict_flags() -> None: + def set_strict_flags(ignored: Any) -> None: nonlocal strict_found strict_found = True diff --git a/mypy/main.py b/mypy/main.py index d765781838cf..fcb35a6cf481 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -22,7 +22,7 @@ from mypy.fscache import FileSystemCache from mypy.errors import CompileError from mypy.errorcodes import error_codes -from mypy.options import Options, BuildType +from mypy.options import Options, BuildType, PER_MODULE_OPTIONS from mypy.config_parser import get_config_module_names, parse_version, parse_config_file from mypy.split_namespace import SplitNamespace @@ -911,9 +911,10 @@ def add_invertible_flag(flag: str, options = Options() - def set_strict_flags() -> None: + def set_strict_flags(toplevel: bool, results: Dict[str, object]) -> None: for dest, value in strict_flag_assignments: - setattr(options, dest, value) + if toplevel or dest in PER_MODULE_OPTIONS: + results[dest] = value # Parse config file first, so command line can override. parse_config_file(options, set_strict_flags, config_file, stdout, stderr) @@ -921,7 +922,8 @@ def set_strict_flags() -> None: # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. if getattr(dummy, 'special-opts:strict'): # noqa - 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', '') diff --git a/mypy/stubtest.py b/mypy/stubtest.py index df36935a801f..839e92fc4cb5 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1207,8 +1207,8 @@ def test_stubs(args: argparse.Namespace, use_builtins_fixtures: bool = False) -> options.use_builtins_fixtures = use_builtins_fixtures if options.config_file: - def set_strict_flags() -> None: # not needed yet - return + def set_strict_flags(toplevel: bool, results: Dict[str, object]) -> None: # not needed yet + print("note: set_strict_flags called with toplevel={}".format(toplevel)) parse_config_file(options, set_strict_flags, options.config_file, sys.stdout, sys.stderr) try: diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index 79507948af14..f1eef5b12d8a 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -160,7 +160,7 @@ def get_options(self, 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, lambda t, r: None, name) break return options diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 2852299548ed..395cd3bb7da0 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1047,3 +1047,17 @@ def test_config_file(self) -> None: ) output = run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file) assert output == "" + + def test_config_file_strict(self) -> None: + config_file = ( + "[mypy]\n" + "strict = True\n" + ) + output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) + assert output == "note: set_strict_flags called with toplevel=True\n" + config_file = ( + "[mypy-submodule.*]\n" + "strict = True\n" + ) + output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) + assert output == "note: set_strict_flags called with toplevel=False\n" From f557a9b70f8c1791a68e8421f8f642afd9568e29 Mon Sep 17 00:00:00 2001 From: Ian Good Date: Mon, 14 Feb 2022 23:03:36 -0500 Subject: [PATCH 2/7] Use two inline functions for set_strict_flags --- mypy/config_parser.py | 16 ++++++++++------ mypy/main.py | 9 ++------- mypy/stubtest.py | 16 +++++++++++++--- mypy/test/testfinegrained.py | 2 +- mypy/test/teststubtest.py | 11 ++++++++--- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index eab5e003224f..14e8bd847a55 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -1,6 +1,5 @@ import argparse import configparser -from functools import partial import glob as fileglob from io import StringIO import os @@ -155,7 +154,7 @@ def check_follow_imports(choice: str) -> str: def parse_config_file(options: Options, - set_strict_flags: Callable[[bool, Dict[str, object]], None], + strict_flag_assignments: Sequence[Tuple[str, object]], filename: Optional[str], stdout: Optional[TextIO] = None, stderr: Optional[TextIO] = None) -> None: @@ -207,8 +206,8 @@ def parse_config_file(options: Options, os.environ['MYPY_CONFIG_FILE_DIR'] = os.path.dirname( os.path.abspath(config_file)) - set_strict_flags_toplevel = partial(set_strict_flags, True) - set_strict_flags_module = partial(set_strict_flags, False) + def set_strict_flags(updates: Dict[str, object]) -> None: + updates.update(strict_flag_assignments) if 'mypy' not in parser: if filename or file_read not in defaults.SHARED_CONFIG_FILES: @@ -217,16 +216,21 @@ def parse_config_file(options: Options, section = parser['mypy'] prefix = '%s: [%s]: ' % (file_read, 'mypy') updates, report_dirs = parse_section( - prefix, options, set_strict_flags_toplevel, section, config_types, stderr) + prefix, options, set_strict_flags, section, config_types, stderr) for k, v in updates.items(): 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_module, section, config_types, stderr) + prefix, options, set_strict_flags_section, section, config_types, stderr) if report_dirs: print("%sPer-module sections should not specify reports (%s)" % (prefix, ', '.join(s + '_report' for s in sorted(report_dirs))), diff --git a/mypy/main.py b/mypy/main.py index fcb35a6cf481..c7f033c8cdc2 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -22,7 +22,7 @@ from mypy.fscache import FileSystemCache from mypy.errors import CompileError from mypy.errorcodes import error_codes -from mypy.options import Options, BuildType, PER_MODULE_OPTIONS +from mypy.options import Options, BuildType from mypy.config_parser import get_config_module_names, parse_version, parse_config_file from mypy.split_namespace import SplitNamespace @@ -911,13 +911,8 @@ def add_invertible_flag(flag: str, options = Options() - def set_strict_flags(toplevel: bool, results: Dict[str, object]) -> None: - for dest, value in strict_flag_assignments: - if toplevel or dest in PER_MODULE_OPTIONS: - results[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. diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 839e92fc4cb5..5c01c8d2fc27 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1205,11 +1205,21 @@ def test_stubs(args: argparse.Namespace, use_builtins_fixtures: bool = False) -> options.custom_typeshed_dir = args.custom_typeshed_dir options.config_file = args.mypy_config_file options.use_builtins_fixtures = use_builtins_fixtures + options.per_module_options = {} if options.config_file: - def set_strict_flags(toplevel: bool, results: Dict[str, object]) -> None: # not needed yet - print("note: set_strict_flags called with toplevel={}".format(toplevel)) - parse_config_file(options, set_strict_flags, options.config_file, sys.stdout, sys.stderr) + strict_flags = set(['warn_unused_configs', 'warn_unused_ignores']) + + strict_flag_assignments = [(dest, True) for dest in strict_flags] + parse_config_file(options, strict_flag_assignments, options.config_file, + sys.stdout, sys.stderr) + + for dest in strict_flags: + if getattr(options, dest, False): + print('note: {} = True [global]'.format(dest)) + for glob, updates in options.per_module_options.items(): + if updates.get(dest): + print('note: {} = True [{}]'.format(dest, glob)) try: modules = build_stubs(modules, options, find_submodules=not args.check_typeshed) diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index f1eef5b12d8a..9e5a13ea6720 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -160,7 +160,7 @@ def get_options(self, for name, _ in testcase.files: if 'mypy.ini' in name or 'pyproject.toml' in name: - parse_config_file(options, lambda t, r: None, name) + parse_config_file(options, [], name) break return options diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 395cd3bb7da0..9c4d7d27e966 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1054,10 +1054,15 @@ def test_config_file_strict(self) -> None: "strict = True\n" ) output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == "note: set_strict_flags called with toplevel=True\n" + assert output == ( + "note: warn_unused_configs = True [global]\n" + "note: warn_unused_ignores = True [global]\n" + ) config_file = ( - "[mypy-submodule.*]\n" + "[mypy-test_module.*]\n" "strict = True\n" ) output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == "note: set_strict_flags called with toplevel=False\n" + assert output == ( + "note: warn_unused_ignores = True [test_module.*]\n" + ) From 346ce1ab6c7067aab84603f051a4b255b15dd0b5 Mon Sep 17 00:00:00 2001 From: Ian Good Date: Tue, 15 Feb 2022 00:47:14 -0500 Subject: [PATCH 3/7] Fix non-deterministic unit test --- mypy/stubtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 5c01c8d2fc27..f8bc8e5707ae 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1208,7 +1208,7 @@ def test_stubs(args: argparse.Namespace, use_builtins_fixtures: bool = False) -> options.per_module_options = {} if options.config_file: - strict_flags = set(['warn_unused_configs', 'warn_unused_ignores']) + strict_flags = ['warn_unused_configs', 'warn_unused_ignores'] strict_flag_assignments = [(dest, True) for dest in strict_flags] parse_config_file(options, strict_flag_assignments, options.config_file, From 87a8a93b1e67cd61af1248cd547469eda9afcfae Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Wed, 16 Oct 2024 23:40:12 -0700 Subject: [PATCH 4/7] blacken --- mypy/config_parser.py | 31 ++++++++++++++++++------------- mypy/main.py | 2 +- mypy/stubtest.py | 11 ++++++----- mypy/test/testfinegrained.py | 2 +- mypy/test/teststubtest.py | 14 +++----------- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index a73bac241a51..e8c686741edf 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -177,11 +177,13 @@ def check_follow_imports(choice: str) -> str: ) -def parse_config_file(options: Options, - strict_flag_assignments: Sequence[Tuple[str, object]], - filename: Optional[str], - stdout: Optional[TextIO] = None, - stderr: Optional[TextIO] = None) -> None: +def parse_config_file( + options: Options, + strict_flag_assignments: Sequence[Tuple[str, object]], + filename: Optional[str], + stdout: Optional[TextIO] = None, + stderr: Optional[TextIO] = None, +) -> None: """Parse a config file into an Options object. Errors are written to stderr but are not fatal. @@ -233,7 +235,7 @@ def parse_config_file(options: Options, def set_strict_flags(updates: Dict[str, object]) -> None: updates.update(strict_flag_assignments) - if 'mypy' not in parser: + if "mypy" not in parser: if filename or file_read not in defaults.SHARED_CONFIG_FILES: print(f"{file_read}: No [mypy] section in config file", file=stderr) else: @@ -255,7 +257,8 @@ def set_strict_flags_section(updates: Dict[str, object]) -> None: if name.startswith("mypy-"): prefix = get_prefix(file_read, name) updates, report_dirs = parse_section( - prefix, options, set_strict_flags_section, section, config_types, stderr) + prefix, options, set_strict_flags_section, section, config_types, stderr + ) if report_dirs: print( "%sPer-module sections should not specify reports (%s)" @@ -385,12 +388,14 @@ def destructure_overrides(toml_data: Dict[str, Any]) -> Dict[str, Any]: return result -def parse_section(prefix: str, template: Options, - set_strict_flags: Callable[[Dict[str, object]], None], - section: Mapping[str, Any], - config_types: Dict[str, Any], - stderr: TextIO = sys.stderr - ) -> Tuple[Dict[str, object], Dict[str, str]]: +def parse_section( + prefix: str, + template: Options, + set_strict_flags: Callable[[Dict[str, object]], None], + section: Mapping[str, Any], + config_types: Dict[str, Any], + stderr: TextIO = sys.stderr, +) -> Tuple[Dict[str, object], Dict[str, str]]: """Parse one section of a config file. Returns a dict of option values encountered, and a dict of report directories. diff --git a/mypy/main.py b/mypy/main.py index 4d3577735363..8f045126434f 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1180,7 +1180,7 @@ def add_invertible_flag( # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. - if getattr(dummy, 'special-opts:strict'): # noqa + if getattr(dummy, "special-opts:strict"): # noqa for dest, value in strict_flag_assignments: setattr(options, dest, value) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 0b678ca47286..32dfd859c6f6 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1460,18 +1460,19 @@ def test_stubs(args: _Arguments, use_builtins_fixtures: bool = False) -> int: options.per_module_options = {} if options.config_file: - strict_flags = ['warn_unused_configs', 'warn_unused_ignores'] + strict_flags = ["warn_unused_configs", "warn_unused_ignores"] strict_flag_assignments = [(dest, True) for dest in strict_flags] - parse_config_file(options, strict_flag_assignments, options.config_file, - sys.stdout, sys.stderr) + parse_config_file( + options, strict_flag_assignments, options.config_file, sys.stdout, sys.stderr + ) for dest in strict_flags: if getattr(options, dest, False): - print('note: {} = True [global]'.format(dest)) + print("note: {} = True [global]".format(dest)) for glob, updates in options.per_module_options.items(): if updates.get(dest): - print('note: {} = True [{}]'.format(dest, glob)) + print("note: {} = True [{}]".format(dest, glob)) try: modules = build_stubs(modules, options, find_submodules=not args.check_typeshed) diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index 6bf53f21afaa..9120ec7c09d1 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -150,7 +150,7 @@ def get_options(self, source: str, testcase: DataDrivenTestCase, build_cache: bo options.follow_imports = "error" for name, _ in testcase.files: - if 'mypy.ini' in name or 'pyproject.toml' in name: + if "mypy.ini" in name or "pyproject.toml" in name: parse_config_file(options, [], name) break diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 28c182a0f80c..396f73b9f8ee 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -1218,20 +1218,12 @@ def test_module_and_typeshed(self) -> None: ) def test_config_file_strict(self) -> None: - config_file = ( - "[mypy]\n" - "strict = True\n" - ) + config_file = "[mypy]\n" "strict = True\n" output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) assert output == ( "note: warn_unused_configs = True [global]\n" "note: warn_unused_ignores = True [global]\n" ) - config_file = ( - "[mypy-test_module.*]\n" - "strict = True\n" - ) + config_file = "[mypy-test_module.*]\n" "strict = True\n" output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == ( - "note: warn_unused_ignores = True [test_module.*]\n" - ) + assert output == ("note: warn_unused_ignores = True [test_module.*]\n") From 75bd97527cd0d831650dc7e7ec3acef2046b6361 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Wed, 16 Oct 2024 23:44:03 -0700 Subject: [PATCH 5/7] fix --- mypy/main.py | 2 +- mypy/test/teststubtest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index a7eb43a459be..6afbc42acb14 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1274,7 +1274,7 @@ def add_invertible_flag( # Set strict flags before parsing (if strict mode enabled), so other command # line options can override. - if getattr(dummy, "special-opts:strict"): # noqa + if getattr(dummy, "special-opts:strict"): for dest, value in strict_flag_assignments: setattr(options, dest, value) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 61bbd9f2613c..3d4bed22a4d5 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -2645,12 +2645,12 @@ def test_module_and_typeshed(self) -> None: ) def test_config_file_strict(self) -> None: - config_file = "[mypy]\n" "strict = True\n" + config_file = "[mypy]\nstrict = True\n" output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) assert output == ( "note: warn_unused_configs = True [global]\n" "note: warn_unused_ignores = True [global]\n" ) - config_file = "[mypy-test_module.*]\n" "strict = True\n" + config_file = "[mypy-test_module.*]\nstrict = True\n" output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) assert output == ("note: warn_unused_ignores = True [test_module.*]\n") From 7c7a771a09c33e6a13c56cf9884c7013167fc1fb Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Tue, 29 Oct 2024 22:06:46 -0700 Subject: [PATCH 6/7] More changes --- mypy/config_parser.py | 6 +++--- mypy/main.py | 4 ---- mypy/options.py | 2 +- mypy/test/teststubtest.py | 6 +++++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 9d80de1d633e..519e9fcb9769 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -284,7 +284,7 @@ def parse_config_file( os.environ["MYPY_CONFIG_FILE_DIR"] = os.path.dirname(os.path.abspath(config_file)) - def set_strict_flags(updates: Dict[str, object]) -> None: + def set_strict_flags(updates: dict[str, object]) -> None: updates.update(strict_flag_assignments) if "mypy" not in parser: @@ -300,7 +300,7 @@ def set_strict_flags(updates: Dict[str, object]) -> None: setattr(options, k, v) options.report_dirs.update(report_dirs) - def set_strict_flags_section(updates: Dict[str, object]) -> None: + 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 @@ -448,7 +448,7 @@ def destructure_overrides(toml_data: dict[str, Any]) -> dict[str, Any]: def parse_section( prefix: str, template: Options, - set_strict_flags: Callable[[Dict[str, object]], None], + set_strict_flags: Callable[[dict[str, object]], None], section: Mapping[str, Any], config_types: dict[str, Any], stderr: TextIO = sys.stderr, diff --git a/mypy/main.py b/mypy/main.py index b4fbe49f2d13..7616bbc4468d 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1265,7 +1265,6 @@ def add_invertible_flag( parser.error(f"Cannot find config file '{config_file}'") options = Options() - strict_option_set = False # Parse config file first, so command line can override. parse_config_file(options, strict_flag_assignments, config_file, stdout, stderr) @@ -1395,9 +1394,6 @@ def add_invertible_flag( " new type inference algorithm is already enabled by default" ) - if options.strict_concatenate and not strict_option_set: - print("Warning: --strict-concatenate is deprecated; use --extra-checks instead") - # Set target. if special_opts.modules + special_opts.packages: options.build_type = BuildType.MODULE diff --git a/mypy/options.py b/mypy/options.py index d315d297e023..e869781d9537 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -212,7 +212,7 @@ def __init__(self) -> None: # This makes 1 == '1', 1 in ['1'], and 1 is '1' errors. self.strict_equality = False - # Deprecated, use extra_checks instead. + # Make arguments prepended via Concatenate be truly positional-only. self.strict_concatenate = False # Enable additional checks that are technically correct but impractical. diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 4c9ff98498e4..207c634ca683 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -2650,7 +2650,11 @@ def test_config_file_strict(self) -> None: assert output == ( "note: warn_unused_configs = True [global]\n" "note: warn_unused_ignores = True [global]\n" + "Success: no issues found in 1 module\n" ) config_file = "[mypy-test_module.*]\nstrict = True\n" output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == ("note: warn_unused_ignores = True [test_module.*]\n") + assert output == ( + "note: warn_unused_ignores = True [test_module.*]\n" + "Success: no issues found in 1 module\n" + ) From 0317f43b7b5d6c9303d828cb6e74d51c4b86d8ab Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Tue, 29 Oct 2024 22:26:25 -0700 Subject: [PATCH 7/7] More changes --- mypy/config_parser.py | 2 +- mypy/stubtest.py | 14 +------------- mypy/test/teststubtest.py | 15 --------------- test-data/unit/check-flags.test | 25 +++++++++++++++++++++++++ 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 519e9fcb9769..c44a4cda24ba 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -639,7 +639,7 @@ def parse_mypy_comments( stderr = StringIO() strict_found = False - def set_strict_flags(ignored: Any) -> None: + def set_strict_flags(updates: dict[str, object]) -> None: nonlocal strict_found strict_found = True diff --git a/mypy/stubtest.py b/mypy/stubtest.py index 7ed1efc4d46c..b91466e6a9f5 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1945,19 +1945,7 @@ def test_stubs(args: _Arguments, use_builtins_fixtures: bool = False) -> int: options.pdb = args.pdb if options.config_file: - strict_flags = ["warn_unused_configs", "warn_unused_ignores"] - - strict_flag_assignments = [(dest, True) for dest in strict_flags] - parse_config_file( - options, strict_flag_assignments, options.config_file, sys.stdout, sys.stderr - ) - - for dest in strict_flags: - if getattr(options, dest, False): - print("note: {} = True [global]".format(dest)) - for glob, updates in options.per_module_options.items(): - if updates.get(dest): - print("note: {} = True [{}]".format(dest, glob)) + 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) diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index 207c634ca683..fcbf07b4d371 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -2643,18 +2643,3 @@ def test_module_and_typeshed(self) -> None: assert remove_color_code(output.getvalue()) == ( "error: cannot pass both --check-typeshed and a list of modules\n" ) - - def test_config_file_strict(self) -> None: - config_file = "[mypy]\nstrict = True\n" - output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == ( - "note: warn_unused_configs = True [global]\n" - "note: warn_unused_ignores = True [global]\n" - "Success: no issues found in 1 module\n" - ) - config_file = "[mypy-test_module.*]\nstrict = True\n" - output = run_stubtest(stub="", runtime="", options=[], config_file=config_file) - assert output == ( - "note: warn_unused_ignores = True [test_module.*]\n" - "Success: no issues found in 1 module\n" - ) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index c6419923ebc6..6219082171df 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2125,6 +2125,31 @@ 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 + +[file mypy.ini] +\[mypy] +strict = False +\[mypy-strictmodule] +strict = True [case testNoImplicitOptionalPerModule] # flags: --config-file tmp/mypy.ini