Skip to content

Class level __getattr__ causes error: __getattr__ is not valid at the module level outside a stub file #4069

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

Closed
stoklund opened this issue Oct 6, 2017 · 7 comments
Labels
bug mypy got something wrong priority-0-high

Comments

@stoklund
Copy link

stoklund commented Oct 6, 2017

After updating to mypy 0.530, I am getting an error on a __getattr__() method defined on a class:

$ mypy --version
mypy 0.530
$ python3 --version
Python 3.6.3
[~/cretonne/lib/cretonne/meta]
$ cat mypy.ini 
[mypy]
disallow_untyped_defs = True
warn_unused_ignores = True
warn_return_any = True
[~/cretonne/lib/cretonne/meta]
$ mypy cdsl/formats.py
cdsl/formats.py:143: error: __getattr__ is not valid at the module level outside a stub file

I don't have any module level __getattr__() functions.

This didn't reproduce with a smaller test case, but you can check out the Cretonne repo to reproduce.

stoklund pushed a commit to bytecodealliance/cranelift that referenced this issue Oct 6, 2017
Filed here: python/mypy#4069

We should go back to tracking the latest mypy releases as soon as
possible.
@emmatyping emmatyping added bug mypy got something wrong priority-0-high labels Oct 6, 2017
@emmatyping
Copy link
Member

Confirmed on master, I am stepping through now. I appears the issue only occurs in the second pass of the checker (the class is added to the scope stack in the first pass, but not in the second).

@emmatyping
Copy link
Member

It appears that when we defer functions to the second pass, we try to put the class context information. However, the function node is not removed on L261, so the class is not resolved, and that returns None. This later causes issues when we try to append the class context, but cannot, so the __getattr__ method appears to be in the file context (this occurs in check_second_pass). The __getattr__ checking for module levels if the first thing that relied on the size of the scope being 1 (module level), so it exposed this issue.

@gvanrossum
Copy link
Member

gvanrossum commented Oct 6, 2017 via email

@ilevkivskyi
Copy link
Member

@ethanhs Your diagnosis seems right. Here is a simple repro:

class C:
    def __getattr__(self, attr: str) -> int:
        x: F
        return x.f

class F:
    def __init__(self, f: int) -> None:
        self.f = f

@ilevkivskyi
Copy link
Member

A related bug:

from typing import TypeVar

T = TypeVar('T', bound=C)
class C:
    def m(self: T) -> T:
        class Inner:
            x: F
            f = x.f
        return self

class F:
    def __init__(self, f: int) -> None:
        self.f = f

results in a funny error:

main:5: error: The erased type of self '__main__.C' is not a supertype of its class '__main__.Inner@5'

@ilevkivskyi
Copy link
Member

OK, here is the PR #4073.

JukkaL pushed a commit that referenced this issue Oct 12, 2017
Fixes #4069

This pushes the correct enclosing class while deferring a method instead 
of just the top class.
@stoklund
Copy link
Author

Confirmed fixed in mypy-0.540. Thanks for the quick response!

stoklund pushed a commit to bytecodealliance/cranelift that referenced this issue Oct 21, 2017
Our bug (python/mypy#4069) was fixed in the
mypy-0.540 release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong priority-0-high
Projects
None yet
Development

No branches or pull requests

4 participants