python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.49k stars 2.83k forks source link

The attrs.field converter parameter does not support higher-order functions. #16860

Open ViktorSky opened 9 months ago

ViktorSky commented 9 months ago

Bug Report

mypy marks a field conversion higher-order function as unsupported when it is correctly written with the annotations. the message is: Unsupported converter, only named functions, types and lambdas are currently supported

To Reproduce

from typing import Any, Callable, List, TypeAlias, TypeVar, cast
from attrs import define, field

T = TypeVar('T')
ItemConv: TypeAlias = Callable[[Any], T]

@define   # positional only  # class that resembles a mutable NamedTuple
class Media:
    mediaType: int
    name: str
    ...   # more methods

def media_list_converter(raw: List[List[Any]]) -> List[Media]:
    return [Media(*value) for value in raw]

def not_none(factory: Callable[[], Any], callback: ItemConv[T]) -> ItemConv[T]:
    def converter(raw: Any) -> T:
        if raw is None:
            return cast(T, factory())
        return callback(raw)
    return converter

@define(kw_only=True)
class Foo:
    mediaList: List[Media] = field(factory=list, converter=not_none(list, media_list_converter))  # error

obj = Foo(mediaList=[
    [1, 'the filename']  # more values ...
])

print(obj)  # output: Foo(mediaList=[Media(mediaType=1, name='the filename')])

Expected Behavior

I was hoping mypy would support the nested converter function that returns not_none.

Actual Behavior

>>> mypy media-test.py --strict
media-test.py:25: error: Unsupported converter, only named functions, types and lambdas are currently supported  [misc]
Found 1 error in 1 file (checked 1 source file)

Your Environment

thejcannon commented 3 months ago

We have a spec now: https://github.com/python/typing-council/issues/33