2
import abc


class Human(object):
    __metaclass__ = abc.ABCMeta

    config = {
        'num_ears': 2,
        'num_hands': 2,
    }

    def __init__(self):
        self.config = dict(self.config.items() + self.derived_config.items())

    @abc.abstractproperty
    def derived_config(self):
        pass

    # logic that does stuff with self.config


class Clown(Human):

    derived_config = {
        'funny': True,
        'smile': True,
    }

    def __init__(self, *args, **kwargs):
        self.derived_config = dict(self.derived_config.items() + self.implementation_config.items())

        super(Clown, self).__init__(*args, **kwargs)

    @abc.abstractproperty
    def implementation_config(self):
        pass

    # logic that does stuff with self.config


class OneHandedClown(Clown):

    implementation_config = {
        'smile': False,
        'num_jokes': 20,
        'num_hands': 1,
    }


if __name__ == '__main__':
    s = OneHandedClown()
    print s.config     # {'funny': True, 'num_hands': 1, 'num_jokes': 20, 'num_ears': 2, 'smile': False}

I want to make it clear that the derived_config property is necessary for a derived class of Human, and the abstract property decorator does the trick, in the sense that code where derived classes that don't set this property will not run.

But pylint fails with the following error:

W: 39, 0: Method 'derived_config' is abstract in class 'Human' but is not overridden (abstract-method)

NB:

  • pylint doesn't complain for the abstract property implementation_config, but the pattern is the same (except that OneHandedClown is a terminal leaf).
  • pylint does complain if I remove the class variable implementation_config in OneHandedClown

How can I make sure lint passes without using pylint-disable while at the same time using an abstract property to make sure the inheritance contract is explicit?

yangmillstheory
  • 1,055
  • 13
  • 31
  • 1
    this is a bug that should be reported on the pylint issue tracker (https://bitbucket.org/logilab/pylint/issues) – sthenault Aug 25 '14 at 07:13

1 Answers1

1

I found a solution, but not an answer.

...


class Clown(Human):

    clown_config = {
        'funny': True,
        'smile': True,
    }

    @property
    def derived_config(self):
        return dict(self.clown_config.items() + self.implementation_config.items())


    @abc.abstractproperty
    def implementation_config(self):
        pass

    # logic that does stuff with self.config


...

In particular, why is setting the class variable implementation_config enough to implement the abstract property in Clown, but the previous implementation of derived_config in Clown not enough to implement the corresponding abstract property in Human?

yangmillstheory
  • 1,055
  • 13
  • 31