# Buggy code
def pattern(pat, cap=True, esc=False):
    """Return a 'natural' version of the pattern string for human-readable
    bits. Assumes all tags in the pattern are present."""
    from quodlibet.pattern import Pattern, XMLFromPattern

    class Fakesong(dict):
        cap = False

        def comma(self, key):
            return " - ".join(self.list(key))

        def list(self, key):
            return [tag(k, self.cap) for k in tagsplit(key)]

        list_seperate = list
        __call__ = comma

    fakesong = Fakesong({"filename": tag("filename", cap)})
    fakesong.cap = cap
    try:
        p = (esc and XMLFromPattern(pat)) or Pattern(pat)
    except ValueError:
        return _("Invalid pattern")

    return p.format(fakesong)


# Traceback (TypeError)
=== SYSTEM INFORMATION:
Quod Libet 3.5.1
Mutagen 1.27
Python 2.7.10 (default, Sep 24 2015, 17:50:09)
[GCC 5.1.1 20150618 (Red Hat 5.1.1-4)] linux2
Platform Linux-4.2.6-201.fc22.x86_64-x86_64-with-fedora-22-Twenty_Two

=== STACK TRACE
Traceback (most recent call last):

File "/usr/lib/python2.7/site-packages/quodlibet/util/__init__.py", line 680, in wrap
return handler(that, *args)

File "/usr/lib/python2.7/site-packages/quodlibet/browsers/paned/prefs.py", line 221, in __apply
browser.set_all_panes()

File "/usr/lib/python2.7/site-packages/quodlibet/browsers/paned/main.py", line 62, in set_all_panes
browser.refresh_panes()

File "/usr/lib/python2.7/site-packages/quodlibet/browsers/paned/main.py", line 206, in refresh_panes
pane = Pane(self._library, header, self._panes[0])

File "/usr/lib/python2.7/site-packages/quodlibet/browsers/paned/pane.py", line 32, in __init__
self.config = PaneConfig(prefs)

File "/usr/lib/python2.7/site-packages/quodlibet/browsers/paned/util.py", line 40, in __init__
title = util.pattern(pattern_from_markup(cat), esc=True)

File "/usr/lib/python2.7/site-packages/quodlibet/util/__init__.py", line 538, in pattern
return p.format(fakesong)

File "/usr/lib/python2.7/site-packages/quodlibet/pattern/_pattern.py", line 236, in format
value = u"".join(self.__func(self.SongProxy(song, self._format)))

File "<string>", line 5, in f

File "/usr/lib/python2.7/site-packages/quodlibet/query/_match.py", line 178, in search
num = data(self.__ftag, None)

File "/usr/lib/python2.7/site-packages/quodlibet/pattern/_pattern.py", line 211, in __call__
return self.__song(key, *args)

TypeError: comma() takes exactly 2 arguments (3 given)


=== LOG:
D: 642.71: PlaylistModel.set: Clearing model.
D: 642.71: PlaylistModel.set: Setting 8 songs.
D: 642.71: PlaylistModel.set: Done filling model.
D: 644.58: PlaylistModel.set: Clearing model.
D: 644.58: PlaylistModel.set: Setting 211 songs.
D: 644.58: PlaylistModel.set: Done filling model.
D: 645.79: PlaylistModel.set: Clearing model.
D: 645.79: PlaylistModel.set: Setting 1 songs.
D: 645.79: PlaylistModel.set: Done filling model.
D: 646.13: PlaylistModel.set: Clearing model.
D: 646.13: PlaylistModel.set: Setting 220 songs.
D: 646.13: PlaylistModel.set: Done filling model.
D: 696.51: PlaylistModel.set: Clearing model.
D: 696.51: PlaylistModel.set: Setting 1 songs.
D: 696.51: PlaylistModel.set: Done filling model.
D: 697.48: PlaylistModel.set: Clearing model.
D: 697.48: PlaylistModel.set: Setting 1 songs.
D: 697.48: PlaylistModel.set: Done filling model.
D: 697.78: PlaylistModel.set: Clearing model.
D: 697.78: PlaylistModel.set: Setting 220 songs.
D: 697.79: PlaylistModel.set: Done filling model.
D: 699.88: PlaylistModel.set: Clearing model.
D: 699.88: PlaylistModel.set: Setting 1 songs.
D: 699.88: PlaylistModel.set: Done filling model.
D: 700.24: PlaylistModel.set: Clearing model.
D: 700.24: PlaylistModel.set: Setting 220 songs.
D: 700.24: PlaylistModel.set: Done filling model.
D: 700.91: PlaylistModel.set: Clearing model.
D: 700.92: PlaylistModel.set: Setting 1 songs.
D: 700.92: PlaylistModel.set: Done filling model.
D: 701.24: PlaylistModel.set: Clearing model.
D: 701.25: PlaylistModel.set: Setting 220 songs.
D: 701.25: PlaylistModel.set: Done filling model.
D: 701.63: PlaylistModel.set: Clearing model.
D: 701.63: PlaylistModel.set: Setting 1 songs.
D: 701.63: PlaylistModel.set: Done filling model.
D: 702.14: PlaylistModel.set: Clearing model.
D: 702.14: PlaylistModel.set: Setting 220 songs.
D: 702.14: PlaylistModel.set: Done filling model.
D: 702.43: PlaylistModel.set: Clearing model.
D: 702.43: PlaylistModel.set: Setting 8 songs.
D: 702.43: PlaylistModel.set: Done filling model.
D: 702.77: PlaylistModel.set: Clearing model.
D: 702.77: PlaylistModel.set: Setting 1 songs.
D: 702.77: PlaylistModel.set: Done filling model.
D: 704.98: PlaylistModel.set: Clearing model.
D: 704.98: PlaylistModel.set: Setting 8 songs.
D: 704.98: PlaylistModel.set: Done filling model.
D: 718.78: PlaylistModel.set: Clearing model.
D: 718.78: PlaylistModel.set: Setting 220 songs.
D: 718.79: PlaylistModel.set: Done filling model.
D: 718.89: QueueModel.go_to: Told to go to None
D: 718.89: PlaylistModel.go_to: Told to go to None
D: 718.89: GStreamerPlayer._end: End song
D: 718.90: util.cover.manager.failure: Didn't get cover from FilesystemCover: This source is incapable of fetching covers
D: 718.90: util.cover.manager.run: Found local cover from EmbedCover
D: 718.90: GStreamerPlayer._end: Next song
D: 718.92: SongFileLibrary._changed: Changing 2 items.
D: 718.92: qltk.completion.__update_song: Updating tag model for 2 songs
D: 718.92: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 718.92: library.libraries.__changed: Updating affected albums for 2 items
D: 719.02: PlaylistModel.set: Clearing model.
D: 719.02: PlaylistModel.set: Setting 220 songs.
D: 719.02: PlaylistModel.set: Done filling model.
D: 734.68: config.save: Writing config...
D: 734.71: library.save: Saving all libraries...
D: 901.90: PlaylistModel.set: Clearing model.
D: 901.90: PlaylistModel.set: Setting 0 songs.
D: 901.90: PlaylistModel.set: Done filling model.
D: 905.64: PlaylistModel.set: Clearing model.
D: 905.64: PlaylistModel.set: Setting 219 songs.
D: 905.64: PlaylistModel.set: Done filling model.
D: 907.06: PlaylistModel.set: Clearing model.
D: 907.07: PlaylistModel.set: Setting 220 songs.
D: 907.07: PlaylistModel.set: Done filling model.

# Fixed code
def pattern(pat, cap=True, esc=False):
    """Return a 'natural' version of the pattern string for human-readable
    bits. Assumes all tags in the pattern are present."""
    from quodlibet.pattern import Pattern, XMLFromPattern

    class Fakesong(dict):
        cap = False

        def comma(self, key):
            return " - ".join(self.list(key))

        def list(self, key):
            return [tag(k, self.cap) for k in tagsplit(key)]

        list_separate = list

        def __call__(self, tag, default):
            return 0 if "~#" in tag[:2] else self.comma(tag)

    fakesong = Fakesong({"filename": tag("filename", cap)})
    fakesong.cap = cap
    try:
        p = (esc and XMLFromPattern(pat)) or Pattern(pat)
    except ValueError:
        return _("Invalid pattern")

    return p.format(fakesong)