Skip to content
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

Fix error code handling in stubtest with --mypy-config-file #17629

Merged
merged 1 commit into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 1 addition & 16 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
validate_package_allow_list,
)
from mypy.error_formatter import OUTPUT_CHOICES
from mypy.errorcodes import error_codes
from mypy.errors import CompileError
from mypy.find_sources import InvalidSourceList, create_source_list
from mypy.fscache import FileSystemCache
Expand Down Expand Up @@ -1336,21 +1335,7 @@ def set_strict_flags() -> None:

validate_package_allow_list(options.untyped_calls_exclude)

# Process `--enable-error-code` and `--disable-error-code` flags
disabled_codes = set(options.disable_error_code)
enabled_codes = set(options.enable_error_code)

valid_error_codes = set(error_codes.keys())

invalid_codes = (enabled_codes | disabled_codes) - valid_error_codes
if invalid_codes:
parser.error(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}")

options.disabled_error_codes |= {error_codes[code] for code in disabled_codes}
options.enabled_error_codes |= {error_codes[code] for code in enabled_codes}

# Enabling an error code always overrides disabling
options.disabled_error_codes -= options.enabled_error_codes
options.process_error_codes(error_callback=parser.error)

# Validate incomplete features.
for feature in options.enable_incomplete_feature:
Expand Down
17 changes: 17 additions & 0 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,23 @@ def snapshot(self) -> dict[str, object]:
def __repr__(self) -> str:
return f"Options({pprint.pformat(self.snapshot())})"

def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None:
# Process `--enable-error-code` and `--disable-error-code` flags
disabled_codes = set(self.disable_error_code)
enabled_codes = set(self.enable_error_code)

valid_error_codes = set(error_codes.keys())

invalid_codes = (enabled_codes | disabled_codes) - valid_error_codes
if invalid_codes:
error_callback(f"Invalid error code(s): {', '.join(sorted(invalid_codes))}")

self.disabled_error_codes |= {error_codes[code] for code in disabled_codes}
self.enabled_error_codes |= {error_codes[code] for code in enabled_codes}

# Enabling an error code always overrides disabling
self.disabled_error_codes -= self.enabled_error_codes

def apply_changes(self, changes: dict[str, object]) -> Options:
# Note: effects of this method *must* be idempotent.
new_options = Options()
Expand Down
6 changes: 6 additions & 0 deletions mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1941,6 +1941,12 @@ def set_strict_flags() -> None: # not needed yet

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

def error_callback(msg: str) -> typing.NoReturn:
print(_style("error:", color="red", bold=True), msg)
sys.exit(1)

options.process_error_codes(error_callback=error_callback)

try:
modules = build_stubs(modules, options, find_submodules=not args.check_typeshed)
except StubtestFailure as stubtest_failure:
Expand Down
13 changes: 13 additions & 0 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,19 @@ def test_config_file(self) -> None:
output = run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file)
assert output == "Success: no issues found in 1 module\n"

def test_config_file_error_codes(self) -> None:
runtime = "temp = 5\n"
stub = "temp = SOME_GLOBAL_CONST"
output = run_stubtest(stub=stub, runtime=runtime, options=[])
assert output == (
"error: not checking stubs due to mypy build errors:\n"
'test_module.pyi:1: error: Name "SOME_GLOBAL_CONST" is not defined [name-defined]\n'
)

config_file = "[mypy]\ndisable_error_code = name-defined\n"
output = run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file)
assert output == "Success: no issues found in 1 module\n"

def test_no_modules(self) -> None:
output = io.StringIO()
with contextlib.redirect_stdout(output):
Expand Down
Loading