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

Stubtest: Fix __mypy-replace false positives #15689

Merged
merged 6 commits into from Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions mypy/nodes.py
Expand Up @@ -3746,6 +3746,10 @@ class SymbolTableNode:
implicit: Was this defined by assignment to self attribute?
plugin_generated: Was this symbol generated by a plugin?
(And therefore needs to be removed in aststrip.)
internal_fictional: Flag to indicate that this is a node for internal
use only; it doesn't represent a method/attribute that actually
exists at runtime. (We generate some fictional methods for e.g.
dataclasses; stubtest needs to be able to spot these.)
no_serialize: Do not serialize this node if True. This is used to prevent
keys in the cache that refer to modules on which this file does not
depend. Currently this can happen if there is a module not in build
Expand All @@ -3771,6 +3775,7 @@ class SymbolTableNode:
"cross_ref",
"implicit",
"plugin_generated",
"internal_fictional",
"no_serialize",
)

Expand All @@ -3783,6 +3788,7 @@ def __init__(
module_hidden: bool = False,
*,
plugin_generated: bool = False,
fictional_plugin_generated: bool = False,
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
no_serialize: bool = False,
) -> None:
self.kind = kind
Expand All @@ -3792,6 +3798,7 @@ def __init__(
self.module_hidden = module_hidden
self.cross_ref: str | None = None
self.plugin_generated = plugin_generated
self.internal_fictional = internal_fictional
self.no_serialize = no_serialize

@property
Expand Down
2 changes: 2 additions & 0 deletions mypy/plugins/common.py
Expand Up @@ -219,6 +219,7 @@ def add_method_to_class(
tvar_def: TypeVarType | None = None,
is_classmethod: bool = False,
is_staticmethod: bool = False,
internal_fictional: bool = False,
) -> None:
"""Adds a new method to a class definition."""

Expand Down Expand Up @@ -289,6 +290,7 @@ def add_method_to_class(
else:
sym = SymbolTableNode(MDEF, func)
sym.plugin_generated = True
sym.internal_fictional = internal_fictional
info.names[name] = sym

info.defn.defs.body.append(func)
Expand Down
2 changes: 2 additions & 0 deletions mypy/plugins/dataclasses.py
Expand Up @@ -401,6 +401,7 @@ def _add_internal_replace_method(self, attributes: list[DataclassAttribute]) ->
args=[attr.to_argument(self._cls.info, of="replace") for attr in attributes],
return_type=NoneType(),
is_staticmethod=True,
internal_fictional=True,
)

def _add_internal_post_init_method(self, attributes: list[DataclassAttribute]) -> None:
Expand All @@ -414,6 +415,7 @@ def _add_internal_post_init_method(self, attributes: list[DataclassAttribute]) -
if attr.is_init_var
],
return_type=NoneType(),
internal_fictional=True,
)

def add_slots(
Expand Down
6 changes: 4 additions & 2 deletions mypy/stubtest.py
Expand Up @@ -495,8 +495,10 @@ def verify_typeinfo(
stub, runtime, object_path, is_runtime_typeddict=is_runtime_typeddict
)

# Check everything already defined on the stub class itself (i.e. not inherited)
to_check = set(stub.names)
# Check everything already defined on the stub class itself (i.e. not inherited),
# as long as it wasn't a fictional method generated by a plugin
# (__mypy-replace, __mypy-post_init, etc.)
to_check = {name for name, node in stub.names.items() if not node.internal_fictional}
# Check all public things on the runtime class
to_check.update(
m for m in vars(runtime) if not is_probably_private(m) and m not in IGNORABLE_CLASS_DUNDERS
Expand Down