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

False no-member positive on defaultless instance variables on subclasses #3167

Closed
scop opened this issue Oct 6, 2019 · 9 comments · Fixed by #4194
Closed

False no-member positive on defaultless instance variables on subclasses #3167

scop opened this issue Oct 6, 2019 · 9 comments · Fixed by #4194
Labels
Enhancement ✨ Improvement to a component inference

Comments

@scop
Copy link
Contributor

scop commented Oct 6, 2019

t.py:

class A:
    myfield: int

class B(A):
    pass

a = A()
print(a.myfield)

b = B()
print(b.myfield)
# pylint 2.4.2, astroid 2.3.1
$ pylint t.py | grep no-member
t.py:11:6: E1101: Instance of 'B' has no 'myfield' member (no-member)

Pylint doesn't appear to "see" the subclass myfield member declared in the parent class (reports the error against B), but does see it in the parent class (doesn't report against A).

(Technically I suppose the member isn't actually there in the parent class either as it's an instance variable without a default [1], and I believe they kind of spring to life only when actually set to a value which doesn't happen in this example -- for this reason the example code actually raises when run. Pylint seems to "know" that it's (or will be) there nevertheless which I think is great, but it should also know that it's there in the subclass.
[1] https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations)

@PCManticore
Copy link
Contributor

Yeah, I think pylint should accept subclasses as well and maybe metaclasses. The reason we don't emit these is that variable annotations can be used to specify attributes that might exist at runtime somehow.

@PCManticore PCManticore added Enhancement ✨ Improvement to a component inference labels Oct 9, 2019
@PCManticore PCManticore self-assigned this Oct 9, 2019
@analog-cbarber
Copy link

You get the same error if A contains a method that refers to the declaration:

class A:
    myfield: int

    def get_myfield(self):
        return self.myfield # no-member

@Project-Magenta
Copy link

That is right, because myfield is static and can only be accessed with A.myfield

@soulmerge
Copy link

That is right, because myfield is static and can only be accessed with A.myfield

I think you are mistaken on two accounts here:

  • You can indeed access static members through instances, so accessing A().myfield would be ok.
  • Apart from being valid python, it is also a common way of telling static analyzers (like mypy) that instances of this class have a certain member, that might otherwise go undetected. Note, that if the author wanted to create an actual static member, they would have just defined its value there, instead of just declaring its type.

@analog-cbarber
Copy link

Yes, that is right. That was actually an instance variable annotation. Class variables are supposed to use the ClassVar annotation:

class A:
    myclassvar: ClassVar[int]

I do think that the chosen syntax has resulted in some confusion, but it is what it is.

@analog-cbarber
Copy link

As a workaround, you can assign the instance variable in a if False block in __init__:

class A:
    myvar: int

    def __init__(self):
        if False # pylint: disable=using-constant-test
            self.myvar = 42

Ick. But at least it saves you from having to add pylint comments anywhere the
instance variable is accessed.

If anyone knows a better workaround, I would love to hear it.

@nattyg93
Copy link

nattyg93 commented Jul 9, 2020

@PCManticore Is there any movement on resolving the scenario in the original issue? We are running into this issue on a daily basis. 🙂

@frenck
Copy link

frenck commented Feb 12, 2021

This issue causes us to either use improper typing and assign a None default and constantly make sure that it is asserted to satisfy type checking, or ignore about every line to either satisfy type checking or pylint.

It is rather sad, as it really degrades the whole goal of these tools in the first place. It has been a frustrating experience. Really hope that this can be picked up by someone 😢

@cdce8p
Copy link
Member

cdce8p commented Mar 5, 2021

I opened #4194 to fix this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement ✨ Improvement to a component inference
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants