Skip to content

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

Closed

Description

@stoklund

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.

Activity

  1. emmatyping commented on Oct 6, 2017

    @emmatyping
    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).

  2. emmatyping commented on Oct 6, 2017

    @emmatyping
    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.

  3. gvanrossum commented on Oct 6, 2017

    @gvanrossum
    Member
  4. ilevkivskyi commented on Oct 8, 2017

    @ilevkivskyi
    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
  5. ilevkivskyi commented on Oct 8, 2017

    @ilevkivskyi
    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'
    
  6. ilevkivskyi commented on Oct 8, 2017

    @ilevkivskyi
    Member

    OK, here is the PR #4073.

  7. added a commit that references this issue on Oct 12, 2017
    ed5a057
  8. stoklund commented on Oct 21, 2017

    @stoklund
    Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions