I use this logic to maintain a directed tree of Object
instances :
class Object:
def __init__(self, *parents: 'Object'):
self.__parents = list(parents)
@property
def __ascendants(self):
for parent in self.__parents:
yield from parent.__ascendants
yield parent
This code runs fine, but PyLint is complaining about __ascendants
being a protected member of parent
, which is, to PyLint, a client class.
In the case of a protected, non-mangled, member, that would be fine : I should not access such members as they could be overriden by an Object
subclass.
But in this case, as the attributes are mangled, it's not possible for a subclass to override them, which is why I allow myself to use them even on external objects (provided to the constructor).
TLDR ; I'm looking for a way to make PyLint accept accessing mangled attributes of a client subclass, without having to resort to #pylint: disable=protected-access
each time, or disabling the warning globally.
It looks like I can use the astng
callback to register a MANAGER
, and transform a module so that PyLint can use additional information. However, I was only able to add stub members (so that dynamically added members can be used without warnings), and I'm not really sure that I can solve my problem this way.
I also tried to add assert isinstance(parent, Object)
, but it won't help.
EDIT :
I was able to write the code so that PyLInt doesn't raise protected-access
, but only to raise bad-staticmethod-argument
. I don't use other staticmethod s in this particular class, so maybe this can be an acceptable answer to this problem :
class Object:
def __init__(self, *parents: 'Object'):
self.__parents = list(parents)
@staticmethod
def __get_ascendants(self: 'Object'):
for parent in self.__parents:
yield from self.__get_ascendants(parent)
yield parent
EDIT 2 : (inspired by @shx2)
Using a lambda with the correct argument name also fools Pylint:
class Object:
def __init__(self, *parents: 'Object'):
self.__parents = list(parents)
@property
def __ascendants(self):
get_ascendants = lambda self: self.__ascendants
for parent in self.__parents:
yield from get_ascendants(parent)
yield parent
EDIT 3 : Because names do not leak out of generator expressions (or list omprehensions), it can also be written this way :
from itertools import chain
class Object:
def __init__(self, *parents: 'Object'):
self.__parents = list(parents)
@property
def __ascendants(self):
return chain(*(
chain(self.__ascendants, (self, ))
for self in self.__parents
))
I'm looking for a way to make PyLint accept accessing mangled attributes of a client subclass
There are ways to fool pylint.
One way is to disguise parent
as self
:
@property
def __ascendants(self):
for parent in self.__parents:
self = parent
yield from self.__ascendants
yield self
Another is accessing the attribute indirectly, using getattr
. Instead of:
yield from parent.__ascendants
do:
yield from getattr(parent, '__ascendants')