Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No exception for missing attributes with __getattr__ #6251

Closed
samuelcolvin opened this issue Jan 24, 2019 · 3 comments
Closed

No exception for missing attributes with __getattr__ #6251

samuelcolvin opened this issue Jan 24, 2019 · 3 comments

Comments

@samuelcolvin
Copy link
Sponsor Contributor

(Apologies if this has already been answered somewhere else, I've looked but couldn't find a duplicate, it's kind of the opposite of #520)

I'm trying to get pydantic to work better with mypy. This is taken from pydantic/pydantic#245.

class Model(BaseModel):
    age: int

m = Model(age=5)
print(m.foobar)

This code obviously raises an AttributeError with python, but mypy doesn't complain since as per #520 the __getattr__ method is defined so mypy can't know if m.foobar exists.

Is there any way to get mypy to fail in a case like this?

The only thing I can think of is to define BaseModel differently based on TYPE_CHECKING so __getattr__ isn't defined in that case. This that the best/only way to go or is there some magic comment or annotation I can add to get mypy to ignore __getattr__?

@Michael0x2a
Copy link
Collaborator

I think in this case, the issue isn't that BaseModel has a __getattr__ method. Rather, it's that your pydantic library doesn't come distributed with type hints/isn't in typeshed. So, mypy defaults to treating anything you import from pydantic as implicitly being of type Any -- including BaseModel. And hey, since BaseModel is of type Any, it might define a foobar attribute, who knows.

(Normally, mypy will report an error with the import in cases like these, but it looks like your docs tell people to suppress it with the --ignore-missing-imports flag.)

Anyways, I think you can fix this by making your package PEP 561 compatible -- basically, add type hints to your code, or bundle a separate set of type stubs files with your library. Probably the latter might be easiest in your case? You can add type stubs for just the classes that your mypy users are likely to use (and omit a definition for BaseModel.__getattr__ in your stubs completely).

Regarding the getattr thing -- I believe you can make mypy ignore the __getattr__ method completely by decorating it with typing.no_type_check. For example, when I try doing this:

from typing import no_type_check

class Base:
    @no_type_check
    def __getattr__(self, name):
        pass

class Model(Base):
    age: int


m = Model()
reveal_type(m.foo)

...I get the following error messages:

test.py:13: error: Revealed type is 'Any'
test.py:13: error: "Model" has no attribute "foo"

If I remove the annotation, the "Model has no attribute" error stops showing up.

(But making just this change to your code would be moot for your users if you don't also make your package PEP 561 compatible.)

@samuelcolvin
Copy link
Sponsor Contributor Author

Thanks @Michael0x2a that's very helpful, as it happens I have been discussing adding type hints today anyway.

The reason I hadn't worked hard on type hints already was some confusion about different PEPs/python versions and what the best way to add type hints was. Some people seemed to suggest stub files while others said: "just add types to your code", there was also typeshed and "*-stubs" packages.

The verdict today seems to be "just add types to your code" so I'll do that.

@samuelcolvin
Copy link
Sponsor Contributor Author

Thanks so much for the help, this is now fixed in pydantic.

For the record and anyone else trying to do this sort of thing: I had to add @no_type_check to both __getattr__ and the __new__ method of the metaclass.

AChenQ pushed a commit to AChenQ/tensorbay-python-sdk that referenced this issue May 26, 2021
Mypy did not raise an error on a missing method when base class
defined a `__getattr__` function, so make mypy ignore that method
by decorating `__getattr__` with `typing.no_type_check`.

related issue: python/mypy#6251
AChenQ pushed a commit to AChenQ/tensorbay-python-sdk that referenced this issue May 26, 2021
Mypy does not raise an error on a `missing method` when base class
defined a `__getattr__` function, so make mypy ignore that method
by decorating `__getattr__` with `typing.no_type_check`.

related issue: python/mypy#6251
AChenQ pushed a commit to AChenQ/tensorbay-python-sdk that referenced this issue May 26, 2021
Mypy does not raise an error on a `missing method` when base class
defines a `__getattr__` function, so make mypy ignore that method
by decorating `__getattr__` with `typing.no_type_check`.

related issue: python/mypy#6251
AChenQ pushed a commit to AChenQ/tensorbay-python-sdk that referenced this issue May 26, 2021
Mypy does not raise an error on a `missing method` when base class
defines a `__getattr__` function, so make mypy ignore that method
by decorating `__getattr__` with `typing.no_type_check`.

related issue: python/mypy#6251

PR Closed: Graviti-AI#607
AChenQ pushed a commit to Graviti-AI/tensorbay-python-sdk that referenced this issue May 26, 2021
Mypy does not raise an error on a `missing method` when base class
defines a `__getattr__` function, so make mypy ignore that method
by decorating `__getattr__` with `typing.no_type_check`.

related issue: python/mypy#6251

PR Closed: #607
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants