Skip to content

Commit

Permalink
Add enable_incomplete_feature validation to stubtest (#17635)
Browse files Browse the repository at this point in the history
Closes #17634
Refs #17628 
Refs #17629
  • Loading branch information
sobolevn authored Aug 5, 2024
1 parent fc5e1ff commit 9d56820
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
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

0 comments on commit 9d56820

Please sign in to comment.