Pyright: Getting started: attrs not supported

Created on 15 Jun 2019  路  12Comments  路  Source: microsoft/pyright

Hi, I wanted to try this out after mypy, but I don't understand some of the errors I'm getting.

First

This looks like an attr.s thing

  10:17 - error: Expected no arguments to 'Foo' constructor
  10:17 - error: 'dq.Foo(dq.Bar.Thing.value)' has type 'Type[Foo]' and is not callable

Declaration:

import attr
from enum import Enum

@attr.s(frozen=True)
class Foo:
    name: str = attr.ib()

class Bar(Enum):
    Thing = "Thing"

Usage:

    a=dq.Foo(dq.Bar.Thing.value),

Second

This looks like it doesn't like @classmethod? Or it's an attr.s thing again

  45:6 - error: Argument of type '(cls: Type[Bar], details: Dict[str, Any]) -> Rule' cannot be assigned to parameter 'f' of type 'function'
@attr.s(auto_attribs=True, frozen=True)
class Foo(Rule):
    @classmethod # this line
    def _deserialize(cls, details: Dict[str, Any]) -> Rule:
        pass

Most helpful comment

Given the widespread use of attrs and the fact that dataclasses are not a full replacement of attrs I would still argue that type checking support from pyright would be justified. Even mypy ships with dedicated support for attrs, so I would not call it an arbitrary third-party library.

All 12 comments

The "attr" class decorator is modifying the standard behavior of the class it's decorating, and it's doing so in a way that the type checker has no visibility. If you look at the undecorated class Foo, there's no __init__ method specified and it derives from no other object that specifies an __init__ method, so pyright assumes that its initializer takes no parameters. The type stub file that accompanies the attires module contains a type definition for the @attr.s class decorator. This type definition indicates that it returns Callable[[_C], _C], which is to say that the __init__ method is unmodified by the decorator.

Class decorators that do "clever" things with python are difficult for type checkers to deal with in general because the type annotation language isn't rich enough to express the arbitrary behavioral changes that they can make to the class and its members.

I'm not sure what to suggest here other than stop using attrs if you want to use type checking.

Thanks so much @erictraut I'll stick with MyPy

It would be nice if we could use

```python
import attr # type: ignore

to disable all pyright checks for this package. I had to add 20+  `# type: ignore` to ignore any attrs object, e.g.:

@attr.s # type: ignore
attr.ib(...) # type: ignore
...
```

I don't believe this issue should be closed.

For the record, dataclasses.dataclass does work with pyright and (from the end-user's perspective) does the same thing (not sure about the differences under-the-hood).

The difference is that dataclass is part of the official python spec, whereas attr is not. Pyright contains a bunch of code specifically to handle dataclass. It does not contain code to deal with special-case behaviors implemented by arbitrary third-party libraries. I recommend moving away from attr to dataclass if it meets your needs.

The difference is that dataclass is part of the official python spec, whereas attr is not. Pyright contains a bunch of code specifically to handle dataclass. It does not contain code to deal with special-case behaviors implemented by arbitrary third-party libraries. I recommend moving away from attr to dataclass if it meets your needs.

That is exactly what I ended up doing, and I don't regret it (except that my minimum dependeny is now pyton 3.7)

Given the widespread use of attrs and the fact that dataclasses are not a full replacement of attrs I would still argue that type checking support from pyright would be justified. Even mypy ships with dedicated support for attrs, so I would not call it an arbitrary third-party library.

Hey just wondering if there's any reason for pyright over mypy?

You can inherit from a protocol to silence errors in Pyright:

from typing import Any, Protocol

import attr


class AttrProto(Protocol):
    def __init__(self, **kwargs: Any) -> None: ...


@attr.s()
class Foo(AttrProto):
    bar: str = attr.ib()


Foo(bar='baz')   # ok

Modifying the attrs stub file to use a generic protocol would also work.

As mentioned before, attrs is quite widely used (~24 million downloads last month), are there any plans to support this "arbitrary third-party" package or is work necessary from the @python-attrs developers?

We have no plans for Pyright to include knowledge of third-party libraries (i.e. those that are not part of the Python specification). Third-party libraries must be described by type stub files.

We might eventually provide an extensibility mechanism so Pyright's type logic can be extended by plug-ins, but such an extension mechanism would require significant work, add significant internal complexity, and limit future changes to Pyright. So it's not something we are in a rush to provide. Pyright needs to mature a bit more first.

I can understand that, but that would mean that Pyright is currently not very usable when you depend on attrs or for example SQLAlchemy. But I can understand you want to let Pyright mature first before making things a lot more complex 馃憤

Was this page helpful?
0 / 5 - 0 ratings