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)
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.
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
That is right, because myfield is static and can only be accessed with A.myfield
That is right, because myfield is static and can only be accessed with
A.myfield
I think you are mistaken on two accounts here:
A().myfield would be ok.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.
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.
@PCManticore Is there any movement on resolving the scenario in the original issue? We are running into this issue on a daily basis. 馃檪
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 馃槩
I opened #4194 to fix this issue
Most helpful comment
@PCManticore Is there any movement on resolving the scenario in the original issue? We are running into this issue on a daily basis. 馃檪