mypy returns "Incompatible types in assignment" with on_setattr=setters.convert

Open
#889 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
python

Research direction

Start by reproducing the report with /tmp/test_mypy_attrs.py and mypy, focusing on the attrs.setters.convert assignment in the Glyph example. Trace how the converter and generated setter are represented to mypy, then confirm that plain-dict assignment type-checks while runtime conversion to Lib still works.

Written by the indexing model from the issue text.

Description

Typing

Not sure if this is a mypy issue or attrs or both.

I have an attrs class that defines a field with a converter that coerces the input value to a custom dict subclass.
It works fine when creating a new object, I pass in a dict and the field gets converted to the my dict subclass. I think #710 is responsible for inferring __init__ annotations from the converters'.

Now I would like to do the same with on_setattr, by using attrs.setters.convert: i.e. I want to set the field to a plain dict and have it converted automatically using the field converter to my dict subclass.

This works fine at runtime, but when I run mypy on my code, it complains that Incompatible types in assignment (expression has type Dict[...], variable has type "...") when I do that.

Here's a made up example:

from __future__ import annotations
from typing import Any, Dict, Mapping, Union
from attr import define, field, setters


class Lib(Dict[str, Any]):
    pass


def _convert_lib(v: Mapping[str, Any]) -> Lib:
    return v if isinstance(v, Lib) else Lib(v)


@define(on_setattr=setters.convert)
class Glyph:
    lib: Lib = field(factory=Lib, converter=_convert_lib)


g = Glyph({"foo": [1, 2, 3]})

assert isinstance(g.lib, Lib)

g.lib = {"bar": [4, 5, 6]}

assert isinstance(g.lib, Lib)
$ mypy /tmp/test_mypy_attrs.py
/tmp/test_mypy_attrs.py:23: error: Incompatible types in assignment (expression has type "Dict[str, List[int]]", variable has type "Lib")

Is there a way around this besides an ugly # type: ignore on every line I use the attrs generated setter-cum-converter?

thanks in advance

Dominant language
Python
Stars
5.8k
Forks
480
Avg merge
2h 15m
Merged PRs (30d)
2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from python-attrs/attrs

All issues in python-attrs/attrs

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.