Skip to content

Commit ce358ed

Browse files
finite-state-machinepre-commit-ci[bot]hynek
authored
Fix attrs.field(converter=...) type annotations (#1461)
* Fix `attrs.field(converter=...)` type annotations Converters can currently be specified as `_ConverterType`, `list[_ConverterType]`, or `tuple[_ConverterType]`. The last of these does not mean "tuple of `_ConverterType` instances" as was likely intended; it specifies a tuple with exactly one `_ConverterType` element. The correct form for a `tuple` with any number of instances is `tuple[_ConverterType, ...]`. * Add to `changelog.d` * Add regression test for PR 1461 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update changelog.d/1461.change.md * Update tests/test_pyright.py --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Hynek Schlawack <hs@ox.cx>
1 parent 19175d9 commit ce358ed

File tree

3 files changed

+38
-3
lines changed

3 files changed

+38
-3
lines changed

changelog.d/1461.change.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed annotations for `attrs.field(converter=...)`.
2+
Previously, a `tuple` of converters was only accepted if it had exactly one element.

src/attrs/__init__.pyi

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def field(
9898
metadata: Mapping[Any, Any] | None = ...,
9999
converter: _ConverterType
100100
| list[_ConverterType]
101-
| tuple[_ConverterType]
101+
| tuple[_ConverterType, ...]
102102
| None = ...,
103103
factory: Callable[[], _T] | None = ...,
104104
kw_only: bool | None = ...,
@@ -121,7 +121,7 @@ def field(
121121
metadata: Mapping[Any, Any] | None = ...,
122122
converter: _ConverterType
123123
| list[_ConverterType]
124-
| tuple[_ConverterType]
124+
| tuple[_ConverterType, ...]
125125
| None = ...,
126126
factory: Callable[[], _T] | None = ...,
127127
kw_only: bool | None = ...,
@@ -144,7 +144,7 @@ def field(
144144
metadata: Mapping[Any, Any] | None = ...,
145145
converter: _ConverterType
146146
| list[_ConverterType]
147-
| tuple[_ConverterType]
147+
| tuple[_ConverterType, ...]
148148
| None = ...,
149149
factory: Callable[[], _T] | None = ...,
150150
kw_only: bool | None = ...,

tests/test_pyright.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,36 @@ def test_pyright_attrsinstance_compat(tmp_path):
106106
)
107107
}
108108
assert diagnostics == expected_diagnostics
109+
110+
111+
def test_pyright_field_converters_tuple(tmp_path):
112+
"""
113+
Test that `field(converter=(_, _, ...))` raises no FPs in Pyright.
114+
"""
115+
test_pyright_field_converters_tuple_path = (
116+
tmp_path / "test_pyright_field_converters_tuple.py"
117+
)
118+
test_pyright_field_converters_tuple_path.write_text(
119+
"""\
120+
import attrs
121+
122+
123+
def square(value: int) -> int:
124+
return value * value
125+
126+
def negate(value: int) -> int:
127+
return -value
128+
129+
130+
@attrs.define
131+
class SomeClass:
132+
133+
value: int = attrs.field(converter=(square, negate))
134+
"""
135+
)
136+
137+
diagnostics = parse_pyright_output(
138+
test_pyright_field_converters_tuple_path
139+
)
140+
141+
assert not diagnostics

0 commit comments

Comments
 (0)