0

I Have a set of classes which represent audio tracks an their metadata. For some of the file formats I only support reading tags, for others writing is also implemented.

class ReadableTrack(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def _get_artist(self):
        raise NotImplementedError

    @property
    def artist(self):
        return self._get_artist()


class DsfTrack(ReadableTrack):
    """
        Support for DSF files
    """
    def _get__get_artist(self):
        pass  # code here

File formats to which writing meta is supported are derived from a subclass of ReadableTrack which implements setters for tags

class WritableTrack(ReadableTrack):
    """
        A track to which metadata can also be written.
    """

    @abc.abstractmethod
    def _set_artist(self, artist):
        raise NotImplementedError

    @artist.setter
    def artist(self, value):
        self._set_artist()


class FlacTrack(WritableTrack):
    """
        Class to get the metadata from .flac file extensions
    """

    def _get_artist(self):
        pass  # code here

    def _set_artist(self, value):
        pass  # code here

Unfortunatly, the above will cause an the following error:

File "/system/audio/metadata/Track/FlacTrack.py", line 11, in <module>
    from system.audio.metadata.Track import WritableTrack
  File "/system/audio/metadata/Track/__init__.py", line 23, in <module>
    from system.audio.metadata.Track.WritableTrack import WritableTrack
  File "/system/audio/metadata/Track/WritableTrack.py", line 13, in <module>
    class WritableTrack(ReadableTrack):
  File "/system/audio/metadata/Track/WritableTrack.py", line 171, in WritableTrack
    @artist.setter
NameError: name 'artist' is not defined

Which can be "workedaround" by redefining the the artist property in WritableTrack like so:

class WritableTrack2(ReadableTrack):
    """
        A track to which metadata can also be written.
    """

    @abc.abstractmethod
    def _get_artist(self):
        raise NotImplementedError

    @abc.abstractmethod
    def _set_artist(self, value):
        raise NotImplementedError

    @property
    def artist(self):
        return self._get_artist()

    @artist.setter
    def artist(self, value):
        self._set_artist(value)

So basically in WritableTrack I can't define a @property.setter for a property defined in a superclass. The properties are defined in the superclasses because they include some I/O validation to ensure interface consistency between the various subclasses of ReadableTrack and WritableTrack. Re-defining the property is redundant and defeats the purpose of inheritance... I'd like to find the "correct" way of doing it. Any hints?

Emanuel Ey
  • 2,724
  • 5
  • 30
  • 38
  • 2
    Reference the original property object on the parent class: `@ReadableTrack.artist.setter`. – Martijn Pieters Jul 15 '16 at 17:34
  • @MartijnPieters -- Won't that just define `artist.__set__` on the original parent class (making the parent class writable too)? – mgilson Jul 15 '16 at 17:36
  • @mgilson: no, the decorator *returns a new property object*; you get a new property object on the WritableTrack class with the getter inherited, and a new setter function. The parent class is unaffected. – Martijn Pieters Jul 15 '16 at 17:36
  • @mgilson: see [How does the `@property` decorator work?](https://stackoverflow.com/a/17330273) – Martijn Pieters Jul 15 '16 at 17:37
  • Interesting, you're right. At least, if we're to believe the "pure python" implementation on the descriptor page of the docs: https://docs.python.org/3/howto/descriptor.html (and I do). – mgilson Jul 15 '16 at 17:38
  • @MartijnPieters Thanks for the awesome ninja-quick solution! – Emanuel Ey Jul 15 '16 at 17:38

0 Answers0