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

Cannot get attrs.Converter() with takes_self pass through mypy #1378

Closed
nyoxi opened this issue Dec 5, 2024 · 3 comments · May be fixed by #1382
Closed

Cannot get attrs.Converter() with takes_self pass through mypy #1378

nyoxi opened this issue Dec 5, 2024 · 3 comments · May be fixed by #1382

Comments

@nyoxi
Copy link

nyoxi commented Dec 5, 2024

I've been playing with the attrs.Converter() but I am unable to get it type-checked with mypy when using takes_self. Now I am not considering (the obvious) Unsupported converter, only named functions, types and lambdas are currently supported error. What I am struggling with is how to annotate the self. The following code:

def str2int(s: str|int, self_: "C") -> int:
    return int(s)

@attrs.define
class C:
    x: int = attrs.field(
        converter=attrs.Converter(str2int, takes_self=True)
    )

Leads to the following error:

error: No overload variant of "Converter" matches argument types "Callable[[str | int, C], int]", "bool"  [call-overload]
note: Possible overload variants:
note:     def [In, Out] Converter(self, converter: Callable[[In], Out]) -> Converter[In, Out]
note:     def [In, Out] Converter(self, converter: Callable[[In, AttrsInstance, Attribute[Any]], Out], *, takes_self: Literal[True], takes_field: Literal[True]) -> Converter[In, Out]
note:     def [In, Out] Converter(self, converter: Callable[[In, Attribute[Any]], Out], *, takes_field: Literal[True]) -> Converter[In, Out]
note:     def [In, Out] Converter(self, converter: Callable[[In, AttrsInstance], Out], *, takes_self: Literal[True]) -> Converter[In, Out]

Is this just my own ignorance or an issue with attrs or mypy?

I am using:

  • attrs 24.2.0
  • mypy 1.13.0
@nyoxi
Copy link
Author

nyoxi commented Dec 5, 2024

I just noticed that the check passes with mypy 1.12.1 which may suggest a regression in mypy.
Edit: Please ignore that.

@nyoxi
Copy link
Author

nyoxi commented Dec 13, 2024

I forgot to circle back here. After playing a bit more with converters and validators I figured that the solution is actually pretty simple and straightforward:

def str2int(s: str|int, self_: attrs.AttrsInstance) -> int:
    if not isinstance(self_, C):
        raise TypeError(f"Converter does not know how to work with {type(self_)}")
    # Now the type of `self_` is properly inferred as `C`
    return int(s)

@attrs.define
class C:
    x: int = attrs.field(
        converter=attrs.Converter(str2int, takes_self=True)
    )

I am closing the issue. If anyone thinks this is worth documenting I can prepare a pull request for that.

@nyoxi nyoxi closed this as completed Dec 13, 2024
@filbranden
Copy link
Contributor

Also possible to use typing.cast here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants