attrs
attrs copied to clipboard
Type annotation for attr.ib wrappers functions
It's possible to type a method that wraps an attr.ib attribute?
Example:
import attr
from typing import Any
def typed() -> Any:
return attr.ib(type=str)
@attr.s
class TestingParams:
foo = attr.ib(type=str)
acme = typed()
TestingParams(foo='1', acme='3')
Executing mypy (0.812) with Python (3.7.3) and attrs (20.3.0) I got the following output
error: Unexpected keyword argument "acme" for "TestingParams" [call-arg]
Sadly, the plugin works by looking for certain hard coded names. attr.ib and others.
But if you're using Python 3 you can probably use
@attr.define
class TestingParams:
foo: str
acme: str
and forget about attr.ib
Does it work if you write it as acme = Factory(typed)?
(That said, I'd probably go with @attr.define and use acme: str = typed().)
Sorry for the late answer
@euresti Thanks for the input, using @attr.define indeed works with mypy (without this, mypy fails to recognize the type).
Just for disclosure, my actual usage is a bit more "heavy" than the sample. Think about around 60 attr decorated the class with multiple attributes defined with converters, validators, and different default values according to parameters informed, and for this reason, I'm trying to type in a way that mypy recognizes it.
About the @wsanchez question:
Does it work if you write it as acme = Factory(typed)?
No =/
Perhaps I'm doing it wrong but I testes in this way.
@attr.s
class TestingParams:
foo = attr.ib(type=str)
acme =Factory(typed)
error: Unexpected keyword argument "acme" for "TestingParams"
Just adding new information to the discussion, while testing attr.define I noticed that mypy and wrapped attributes works fine;
@attr.define
class TestingParams:
foo: str
acme: str = typed()
But without the auto_attrib mypy fails to recognize the attribute that has a wrapped function.
@attr.s
class TestingParams:
foo: str = attr.ib()
acme: str = typed()
>>> attr.fields_dict(TestingParams)['acme'].type
<class 'str'>
>>> mypy test.py
error: Unexpected keyword argument "acme" for "TestingParams"
So I believe that besides the limitation from the mypy plugin that cannot get the type from the wrapped function there is this bug with mypy failing to recognize the type from the acme parameter.
Hrm… I'm getting a different result:
wsanchez$ python3.9 -m venv test
wsanchez$ ./test/bin/pip install -q attrs mypy
wsanchez$ ./test/bin/pip freeze
attrs==20.3.0
mypy==0.812
mypy-extensions==0.4.3
typed-ast==1.4.2
typing-extensions==3.7.4.3
import attr
from typing import Any
def typed() -> Any:
return attr.ib(type=str)
@attr.define
class TestingParams:
foo: str
acme: str = attr.Factory(typed)
TestingParams(foo='1', acme='3')
wsanchez$ mypy test.py
Success: no issues found in 1 source file
Ah wait, you said that does work, but only with auto_attribs=True.
You can always use a "plugin" to tell the attrs plugin that typed is an "attrib_maker"
See https://github.com/python-attrs/attrs/issues/630#issuecomment-607281253
There's even proper docs: https://www.attrs.org/en/stable/extending.html#wrapping-the-decorator