Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add support for converters with TypeVars on generic attrs classes - #14908

Merged
hauntsaninja merged 3 commits into
python:masterfrom
chadrik:attrs_converters
Mar 25, 2023
Merged

Add support for converters with TypeVars on generic attrs classes#14908
hauntsaninja merged 3 commits into
python:masterfrom
chadrik:attrs_converters

Conversation

@chadrik

@chadrik chadrik commented Mar 16, 2023

Copy link
Copy Markdown
Contributor

When creating generic classes using attrs, converters with type vars are not properly integrated into the generated __init__:

from typing import TypeVar, Generic, List, Iterable, Iterator
import attr

T = TypeVar('T')

def int_gen() -> Iterator[int]:
    yield 1

def list_converter(x: Iterable[T]) -> List[T]:
    return list(x)

@attr.s(auto_attribs=True)
class A(Generic[T]):
    x: List[T] = attr.ib(converter=list_converter)
    y: T = attr.ib()

a1 = A([1], 2)   # E: Argument 1 to "A" has incompatible type "Iterator[int]"; expected "Iterable[T]"

This MR fixes the bug by copying type vars from the field/attrib into the type extracted from the converter.

@github-actions

This comment has been minimized.

@chadrik
chadrik force-pushed the attrs_converters branch 3 times, most recently from 98fead7 to f33f58c Compare March 16, 2023 05:00
@github-actions

This comment has been minimized.

@chadrik

chadrik commented Mar 16, 2023

Copy link
Copy Markdown
Contributor Author

@t4lz @euresti Do either of you have a moment to review this attrs-related change, please?

@euresti euresti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks good to me.

Comment thread mypy/plugins/attrs.py
variables = {
binder.id: arg for binder, arg in zip(converter_vars, init_vars)
}
init_type = expand_type(init_type, variables)

@chadrik chadrik Mar 16, 2023

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea behind this change is that a converter should ideally return the same type as the attrs field that it is added to. For example:

def list_converter(x: Iterable[T]) -> List[T]:
    return list(x)

@attr.s(auto_attribs=True)
class A(Generic[T]):
    x: List[T] = attr.ib(converter=list_converter)

A.x is type List[T] and list_converter returns List[T], and in theory this should always be the case for converters, since their purpose is to convert the init arg to the type of the field. In my changes I'm forgoing a complete comparison of the two types, but the assumption tells us that the number and order of TypeVars should be the same. We use that to generate a replacement map which will replace the converter's broken typevars, with typevars that work within the class's context.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I assume the def int_gen slipped in from another example?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. I fixed the example.

@github-actions

This comment has been minimized.

1 similar comment
@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉

@chadrik

chadrik commented Mar 17, 2023

Copy link
Copy Markdown
Contributor Author

Hi @JukkaL, can you or someone else from the mypy team merge this, please?

@chadrik

chadrik commented Mar 21, 2023

Copy link
Copy Markdown
Contributor Author

Hi all, can anyone help me get this one merged? It's approved and all ready to go!

@hauntsaninja hauntsaninja left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@hauntsaninja
hauntsaninja merged commit 3f35ebb into python:master Mar 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants