Skip to content

Add enable_incomplete_feature validation to stubtest #17635

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
Aug 5, 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
10 changes: 2 additions & 8 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from mypy.find_sources import InvalidSourceList, create_source_list
from mypy.fscache import FileSystemCache
from mypy.modulefinder import BuildSource, FindModuleCache, SearchPaths, get_search_dirs, mypy_path
from mypy.options import COMPLETE_FEATURES, INCOMPLETE_FEATURES, BuildType, Options
from mypy.options import INCOMPLETE_FEATURES, BuildType, Options
from mypy.split_namespace import SplitNamespace
from mypy.version import __version__

Expand Down Expand Up @@ -1336,13 +1336,7 @@ def set_strict_flags() -> None:
validate_package_allow_list(options.untyped_calls_exclude)

options.process_error_codes(error_callback=parser.error)

# Validate incomplete features.
for feature in options.enable_incomplete_feature:
if feature not in INCOMPLETE_FEATURES | COMPLETE_FEATURES:
parser.error(f"Unknown incomplete feature: {feature}")
if feature in COMPLETE_FEATURES:
print(f"Warning: {feature} is already enabled by default")
options.process_incomplete_features(error_callback=parser.error, warning_callback=print)

# Compute absolute path for custom typeshed (if present).
if options.custom_typeshed_dir is not None:
Expand Down
10 changes: 10 additions & 0 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,16 @@ def process_error_codes(self, *, error_callback: Callable[[str], Any]) -> None:
# Enabling an error code always overrides disabling
self.disabled_error_codes -= self.enabled_error_codes

def process_incomplete_features(
self, *, error_callback: Callable[[str], Any], warning_callback: Callable[[str], Any]
) -> None:
# Validate incomplete features.
for feature in self.enable_incomplete_feature:
if feature not in INCOMPLETE_FEATURES | COMPLETE_FEATURES:
error_callback(f"Unknown incomplete feature: {feature}")
if feature in COMPLETE_FEATURES:
warning_callback(f"Warning: {feature} is already enabled by default")

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 @@ -1945,7 +1945,13 @@ def error_callback(msg: str) -> typing.NoReturn:
print(_style("error:", color="red", bold=True), msg)
sys.exit(1)

def warning_callback(msg: str) -> None:
print(_style("warning:", color="yellow", bold=True), msg)

options.process_error_codes(error_callback=error_callback)
options.process_incomplete_features(
error_callback=error_callback, warning_callback=warning_callback
)

try:
modules = build_stubs(modules, options, find_submodules=not args.check_typeshed)
Expand Down
14 changes: 14 additions & 0 deletions mypy/test/teststubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2490,6 +2490,20 @@ def test_config_file_error_codes(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_wrong_incomplete_feature(self) -> None:
runtime = "x = 1\n"
stub = "x: int\n"
config_file = "[mypy]\nenable_incomplete_feature = Unpack\n"
output = run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file)
assert output == (
"warning: Warning: Unpack is already enabled by default\n"
"Success: no issues found in 1 module\n"
)

config_file = "[mypy]\nenable_incomplete_feature = not-a-valid-name\n"
with self.assertRaises(SystemExit):
run_stubtest(stub=stub, runtime=runtime, options=[], config_file=config_file)

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