10000 Fix attrs.evolve on bound TypeVar by ikonst · Pull Request #15022 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Fix attrs.evolve on bound TypeVar #15022

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
Apr 12, 2023
Merged
Changes from 1 commit
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
Prev Previous commit
remove extra assert
  • Loading branch information
ikonst committed Apr 9, 2023
commit a3364f1dca8908e4f7ec1bef8b33340625584308
20 changes: 12 additions & 8 deletions mypy/plugins/attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
LiteralType,
NoneType,
Overloaded,
ProperType,
TupleType,
Type,
TypeOfAny,
Expand Down Expand Up @@ -942,6 +943,14 @@ def _get_attrs_init_type(typ: Instance) -> CallableType | None:
return init_method.type


def _get_attrs_cls_and_init(typ: ProperType) -> tuple[Instance | None, CallableType | None]:
if isinstance(typ, TypeVarType):
typ = get_proper_type(typ.upper_bound)
if not isinstance(typ, Instance):
return None, None
return typ, _get_attrs_init_type(typ)


def evolve_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> CallableType:
"""
Generates a signature for the 'attr.evolve' function that's specific to the call site
Expand All @@ -966,21 +975,16 @@ def evolve_function_sig_callback(ctx: mypy.plugin.FunctionSigContext) -> Callabl
if isinstance(inst_type, AnyType):
return ctx.default_signature # evolve(Any, ....) -> Any
inst_type_str = format_type_bare(inst_type)
attrs_type = get_proper_type(
inst_type.upper_bound if isinstance(inst_type, TypeVarType) else inst_type
)
attrs_init_type = None
if isinstance(attrs_type, Instance):
attrs_init_type = _get_attrs_init_type(attrs_type)
if attrs_init_type is None:

attrs_type, attrs_init_type = _get_attrs_cls_and_init(inst_type)
if attrs_type is None or attrs_init_type is None:
ctx.api.fail(
f'Argument 1 to "evolve" has a variable type "{inst_type_str}" not bound to an attrs class'
if isinstance(inst_type, TypeVarType)
else f'Argument 1 to "evolve" has incompatible type "{inst_type_str}"; expected an attrs class',
ctx.context,
)
return ctx.default_signature
assert isinstance(attrs_type, Instance)

# AttrClass.__init__ has the following signature (or similar, if having kw-only & defaults):
# def __init__(self, attr1: Type1, attr2: Type2) -> None:
Expand Down
0