Skip to content

Fix custom typeshed dir handling by is_typeshed_file() #13629

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 3 commits into from
Sep 8, 2022
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
12 changes: 3 additions & 9 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,16 +668,10 @@ def __init__(
raise CompileError(
[f"Failed to find builtin module {module}, perhaps typeshed is broken?"]
)
if is_typeshed_file(path):
if is_typeshed_file(options.abs_custom_typeshed_dir, path) or is_stub_package_file(
path
):
continue
if is_stub_package_file(path):
continue
if options.custom_typeshed_dir is not None:
# Check if module lives under custom_typeshed_dir subtree
custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir)
path = os.path.abspath(path)
if os.path.commonpath((path, custom_typeshed_dir)) == custom_typeshed_dir:
continue

raise CompileError(
[
Expand Down
2 changes: 1 addition & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def __init__(
self.pass_num = 0
self.current_node_deferred = False
self.is_stub = tree.is_stub
self.is_typeshed_stub = is_typeshed_file(path)
self.is_typeshed_stub = is_typeshed_file(options.abs_custom_typeshed_dir, path)
self.inferred_attribute_types = None

# If True, process function definitions. If False, don't. This is used
Expand Down
10 changes: 8 additions & 2 deletions mypy/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,10 @@ def clear_errors_in_targets(self, path: str, targets: set[str]) -> None:
self.has_blockers.remove(path)

def generate_unused_ignore_errors(self, file: str) -> None:
if is_typeshed_file(file) or file in self.ignored_files:
if (
is_typeshed_file(self.options.abs_custom_typeshed_dir if self.options else None, file)
or file in self.ignored_files
):
return
ignored_lines = self.ignored_lines[file]
used_ignored_lines = self.used_ignored_lines[file]
Expand Down Expand Up @@ -658,7 +661,10 @@ def generate_unused_ignore_errors(self, file: str) -> None:
def generate_ignore_without_code_errors(
self, file: str, is_warning_unused_ignores: bool
) -> None:
if is_typeshed_file(file) or file in self.ignored_files:
if (
is_typeshed_file(self.options.abs_custom_typeshed_dir if self.options else None, file)
or file in self.ignored_files
):
return

used_ignored_lines = self.used_ignored_lines[file]
Expand Down
4 changes: 4 additions & 0 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,10 @@ def set_strict_flags() -> None:
# Enabling an error code always overrides disabling
options.disabled_error_codes -= options.enabled_error_codes

# Compute absolute path for custom typeshed (if present).
if options.custom_typeshed_dir is not None:
options.abs_custom_typeshed_dir = os.path.abspath(options.custom_typeshed_dir)

# Set build flags.
if special_opts.find_occurrences:
state.find_occurrences = special_opts.find_occurrences.split(".")
Expand Down
2 changes: 2 additions & 0 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ def __init__(self) -> None:
self.platform = sys.platform
self.custom_typing_module: str | None = None
self.custom_typeshed_dir: str | None = None
# The abspath() version of the above, we compute it once as an optimization.
self.abs_custom_typeshed_dir: str | None = None
self.mypy_path: list[str] = []
self.report_dirs: dict[str, str] = {}
# Show errors in PEP 561 packages/site-packages modules
Expand Down
4 changes: 3 additions & 1 deletion mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,9 @@ def file_context(
self.cur_mod_id = file_node.fullname
with scope.module_scope(self.cur_mod_id):
self._is_stub_file = file_node.path.lower().endswith(".pyi")
self._is_typeshed_stub_file = is_typeshed_file(file_node.path)
self._is_typeshed_stub_file = is_typeshed_file(
options.abs_custom_typeshed_dir, file_node.path
)
self.globals = file_node.names
self.tvar_scope = TypeVarLikeScope()

Expand Down
12 changes: 10 additions & 2 deletions mypy/semanal_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ def check_type_arguments(graph: Graph, scc: list[str], errors: Errors) -> None:
for module in scc:
state = graph[module]
assert state.tree
analyzer = TypeArgumentAnalyzer(errors, state.options, is_typeshed_file(state.path or ""))
analyzer = TypeArgumentAnalyzer(
errors,
state.options,
is_typeshed_file(state.options.abs_custom_typeshed_dir, state.path or ""),
)
with state.wrap_context():
with mypy.state.state.strict_optional_set(state.options.strict_optional):
state.tree.accept(analyzer)
Expand All @@ -381,7 +385,11 @@ def check_type_arguments_in_targets(
This mirrors the logic in check_type_arguments() except that we process only
some targets. This is used in fine grained incremental mode.
"""
analyzer = TypeArgumentAnalyzer(errors, state.options, is_typeshed_file(state.path or ""))
analyzer = TypeArgumentAnalyzer(
errors,
state.options,
is_typeshed_file(state.options.abs_custom_typeshed_dir, state.path or ""),
)
with state.wrap_context():
with mypy.state.state.strict_optional_set(state.options.strict_optional):
for target in targets:
Expand Down
5 changes: 3 additions & 2 deletions mypy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,9 +769,10 @@ def format_error(
return self.style(msg, "red", bold=True)


def is_typeshed_file(file: str) -> bool:
def is_typeshed_file(typeshed_dir: str | None, file: str) -> bool:
typeshed_dir = typeshed_dir if typeshed_dir is not None else TYPESHED_DIR
try:
return os.path.commonpath((TYPESHED_DIR, os.path.abspath(file))) == TYPESHED_DIR
return os.path.commonpath((typeshed_dir, os.path.abspath(file))) == typeshed_dir
except ValueError: # Different drives on Windows
return False

Expand Down