prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  zero: Permit stripping album art
  It would be nice to have the option of automatically clearing embedded art when an item is imported.  Whether or not a media item actually contains embedded art, beets should ensure the resulting media item has no embedded art after being import.  There are two plugins which would offer a good place of implementation for this feature: the EmbedArt and the Zero plugins.
  
  The EmbedArt plugin already supports a command called `clearart` which allows for the manual stripping of embedded art from items which match a query.  Since the the `clearart` operation is not automatic and there is no option for automation, an extra step is required on the importation of media.
  
  What probably makes more sense is implementing support for the art field in the Zero plugin.  It can only be assumed that people who would use such a feature already have the Zero plugin deployed for clearing other fields.  That said, it would require less configuration as all a user would need to do is drop the art field in their configuration for the Zero plugin.  Moreover, with the EmbedArt plugin, it embeds art into media items by default.  This feature would need to be disabled in the configuration as well.
  
  
  </issue>
  <code>
  [start of beetsplug/zero.py]
  1 # This file is part of beets.
  2 # Copyright 2013, Blemjhoo Tezoulbr <baobab@heresiarch.info>.
  3 #
  4 # Permission is hereby granted, free of charge, to any person obtaining
  5 # a copy of this software and associated documentation files (the
  6 # "Software"), to deal in the Software without restriction, including
  7 # without limitation the rights to use, copy, modify, merge, publish,
  8 # distribute, sublicense, and/or sell copies of the Software, and to
  9 # permit persons to whom the Software is furnished to do so, subject to
  10 # the following conditions:
  11 #
  12 # The above copyright notice and this permission notice shall be
  13 # included in all copies or substantial portions of the Software.
  14 
  15 """ Clears tag fields in media files."""
  16 
  17 import re
  18 import logging
  19 from beets.plugins import BeetsPlugin
  20 from beets.library import Item
  21 from beets.importer import action
  22 from beets.util import confit
  23 
  24 __author__ = 'baobab@heresiarch.info'
  25 __version__ = '0.10'
  26 
  27 log = logging.getLogger('beets')
  28 
  29 
  30 class ZeroPlugin(BeetsPlugin):
  31 
  32     _instance = None
  33 
  34     def __init__(self):
  35         super(ZeroPlugin, self).__init__()
  36 
  37         # Listeners.
  38         self.register_listener('write', self.write_event)
  39         self.register_listener('import_task_choice',
  40                                self.import_task_choice_event)
  41 
  42         self.config.add({
  43             'fields': [],
  44         })
  45 
  46         self.patterns = {}
  47         self.warned = False
  48 
  49         for field in self.config['fields'].as_str_seq():
  50             if field in ('id', 'path', 'album_id'):
  51                 log.warn(u'[zero] field \'{0}\' ignored, zeroing '
  52                          u'it would be dangerous'.format(field))
  53                 continue
  54             if field not in Item._fields.keys():
  55                 log.error(u'[zero] invalid field: {0}'.format(field))
  56                 continue
  57 
  58             try:
  59                 self.patterns[field] = self.config[field].as_str_seq()
  60             except confit.NotFoundError:
  61                 # Matches everything
  62                 self.patterns[field] = [u'']
  63 
  64     def import_task_choice_event(self, session, task):
  65         """Listen for import_task_choice event."""
  66         if task.choice_flag == action.ASIS and not self.warned:
  67             log.warn(u'[zero] cannot zero in \"as-is\" mode')
  68             self.warned = True
  69         # TODO request write in as-is mode
  70 
  71     @classmethod
  72     def match_patterns(cls, field, patterns):
  73         """Check if field (as string) is matching any of the patterns in
  74         the list.
  75         """
  76         for p in patterns:
  77             if re.search(p, unicode(field), flags=re.IGNORECASE):
  78                 return True
  79         return False
  80 
  81     def write_event(self, item, path, tags):
  82         """Listen for write event."""
  83         if not self.patterns:
  84             log.warn(u'[zero] no fields, nothing to do')
  85             return
  86 
  87         for field, patterns in self.patterns.items():
  88             if field not in tags:
  89                 log.error(u'[zero] no such field: {0}'.format(field))
  90                 continue
  91 
  92             value = tags[field]
  93             if self.match_patterns(value, patterns):
  94                 log.debug(u'[zero] {0}: {1} -> None'.format(field, value))
  95                 tags[field] = None
  96
  [end of beetsplug/zero.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/beetsplug/zero.py b/beetsplug/zero.py
  --- a/beetsplug/zero.py
  +++ b/beetsplug/zero.py
  @@ -17,7 +17,7 @@
   import re
   import logging
   from beets.plugins import BeetsPlugin
  -from beets.library import Item
  +from beets.mediafile import MediaFile
   from beets.importer import action
   from beets.util import confit
   
  @@ -51,7 +51,7 @@
                   log.warn(u'[zero] field \'{0}\' ignored, zeroing '
                            u'it would be dangerous'.format(field))
                   continue
  -            if field not in Item._fields.keys():
  +            if field not in MediaFile.fields():
                   log.error(u'[zero] invalid field: {0}'.format(field))
                   continue
   
  @@ -59,7 +59,7 @@
                   self.patterns[field] = self.config[field].as_str_seq()
               except confit.NotFoundError:
                   # Matches everything
  -                self.patterns[field] = [u'']
  +                self.patterns[field] = True
   
       def import_task_choice_event(self, session, task):
           """Listen for import_task_choice event."""
  @@ -73,23 +73,29 @@
           """Check if field (as string) is matching any of the patterns in
           the list.
           """
  +        if patterns is True:
  +            return True
           for p in patterns:
               if re.search(p, unicode(field), flags=re.IGNORECASE):
                   return True
           return False
   
       def write_event(self, item, path, tags):
  -        """Listen for write event."""
  +        """Set values in tags to `None` if the key and value are matched
  +        by `self.patterns`.
  +        """
           if not self.patterns:
               log.warn(u'[zero] no fields, nothing to do')
               return
   
           for field, patterns in self.patterns.items():
  -            if field not in tags:
  -                log.error(u'[zero] no such field: {0}'.format(field))
  -                continue
  -
  -            value = tags[field]
  -            if self.match_patterns(value, patterns):
  +            if field in tags:
  +                value = tags[field]
  +                match = self.match_patterns(tags[field], patterns)
  +            else:
  +                value = ''
  +                match = patterns is True
  +
  +            if match:
                   log.debug(u'[zero] {0}: {1} -> None'.format(field, value))
                   tags[field] = None
  
verification_info: {"golden_diff": "diff --git a/beetsplug/zero.py b/beetsplug/zero.py\n--- a/beetsplug/zero.py\n+++ b/beetsplug/zero.py\n@@ -17,7 +17,7 @@\n import re\n import logging\n from beets.plugins import BeetsPlugin\n-from beets.library import Item\n+from beets.mediafile import MediaFile\n from beets.importer import action\n from beets.util import confit\n \n@@ -51,7 +51,7 @@\n                 log.warn(u'[zero] field \\'{0}\\' ignored, zeroing '\n                          u'it would be dangerous'.format(field))\n                 continue\n-            if field not in Item._fields.keys():\n+            if field not in MediaFile.fields():\n                 log.error(u'[zero] invalid field: {0}'.format(field))\n                 continue\n \n@@ -59,7 +59,7 @@\n                 self.patterns[field] = self.config[field].as_str_seq()\n             except confit.NotFoundError:\n                 # Matches everything\n-                self.patterns[field] = [u'']\n+                self.patterns[field] = True\n \n     def import_task_choice_event(self, session, task):\n         \"\"\"Listen for import_task_choice event.\"\"\"\n@@ -73,23 +73,29 @@\n         \"\"\"Check if field (as string) is matching any of the patterns in\n         the list.\n         \"\"\"\n+        if patterns is True:\n+            return True\n         for p in patterns:\n             if re.search(p, unicode(field), flags=re.IGNORECASE):\n                 return True\n         return False\n \n     def write_event(self, item, path, tags):\n-        \"\"\"Listen for write event.\"\"\"\n+        \"\"\"Set values in tags to `None` if the key and value are matched\n+        by `self.patterns`.\n+        \"\"\"\n         if not self.patterns:\n             log.warn(u'[zero] no fields, nothing to do')\n             return\n \n         for field, patterns in self.patterns.items():\n-            if field not in tags:\n-                log.error(u'[zero] no such field: {0}'.format(field))\n-                continue\n-\n-            value = tags[field]\n-            if self.match_patterns(value, patterns):\n+            if field in tags:\n+                value = tags[field]\n+                match = self.match_patterns(tags[field], patterns)\n+            else:\n+                value = ''\n+                match = patterns is True\n+\n+            if match:\n                 log.debug(u'[zero] {0}: {1} -> None'.format(field, value))\n                 tags[field] = None\n", "issue": "zero: Permit stripping album art\nIt would be nice to have the option of automatically clearing embedded art when an item is imported.  Whether or not a media item actually contains embedded art, beets should ensure the resulting media item has no embedded art after being import.  There are two plugins which would offer a good place of implementation for this feature: the EmbedArt and the Zero plugins.\n\nThe EmbedArt plugin already supports a command called `clearart` which allows for the manual stripping of embedded art from items which match a query.  Since the the `clearart` operation is not automatic and there is no option for automation, an extra step is required on the importation of media.\n\nWhat probably makes more sense is implementing support for the art field in the Zero plugin.  It can only be assumed that people who would use such a feature already have the Zero plugin deployed for clearing other fields.  That said, it would require less configuration as all a user would need to do is drop the art field in their configuration for the Zero plugin.  Moreover, with the EmbedArt plugin, it embeds art into media items by default.  This feature would need to be disabled in the configuration as well.\n\n", "before_files": [{"content": "# This file is part of beets.\n# Copyright 2013, Blemjhoo Tezoulbr <baobab@heresiarch.info>.\n#\n# Permission is hereby granted, free of charge, to any person obtaining\n# a copy of this software and associated documentation files (the\n# \"Software\"), to deal in the Software without restriction, including\n# without limitation the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the Software, and to\n# permit persons to whom the Software is furnished to do so, subject to\n# the following conditions:\n#\n# The above copyright notice and this permission notice shall be\n# included in all copies or substantial portions of the Software.\n\n\"\"\" Clears tag fields in media files.\"\"\"\n\nimport re\nimport logging\nfrom beets.plugins import BeetsPlugin\nfrom beets.library import Item\nfrom beets.importer import action\nfrom beets.util import confit\n\n__author__ = 'baobab@heresiarch.info'\n__version__ = '0.10'\n\nlog = logging.getLogger('beets')\n\n\nclass ZeroPlugin(BeetsPlugin):\n\n    _instance = None\n\n    def __init__(self):\n        super(ZeroPlugin, self).__init__()\n\n        # Listeners.\n        self.register_listener('write', self.write_event)\n        self.register_listener('import_task_choice',\n                               self.import_task_choice_event)\n\n        self.config.add({\n            'fields': [],\n        })\n\n        self.patterns = {}\n        self.warned = False\n\n        for field in self.config['fields'].as_str_seq():\n            if field in ('id', 'path', 'album_id'):\n                log.warn(u'[zero] field \\'{0}\\' ignored, zeroing '\n                         u'it would be dangerous'.format(field))\n                continue\n            if field not in Item._fields.keys():\n                log.error(u'[zero] invalid field: {0}'.format(field))\n                continue\n\n            try:\n                self.patterns[field] = self.config[field].as_str_seq()\n            except confit.NotFoundError:\n                # Matches everything\n                self.patterns[field] = [u'']\n\n    def import_task_choice_event(self, session, task):\n        \"\"\"Listen for import_task_choice event.\"\"\"\n        if task.choice_flag == action.ASIS and not self.warned:\n            log.warn(u'[zero] cannot zero in \\\"as-is\\\" mode')\n            self.warned = True\n        # TODO request write in as-is mode\n\n    @classmethod\n    def match_patterns(cls, field, patterns):\n        \"\"\"Check if field (as string) is matching any of the patterns in\n        the list.\n        \"\"\"\n        for p in patterns:\n            if re.search(p, unicode(field), flags=re.IGNORECASE):\n                return True\n        return False\n\n    def write_event(self, item, path, tags):\n        \"\"\"Listen for write event.\"\"\"\n        if not self.patterns:\n            log.warn(u'[zero] no fields, nothing to do')\n            return\n\n        for field, patterns in self.patterns.items():\n            if field not in tags:\n                log.error(u'[zero] no such field: {0}'.format(field))\n                continue\n\n            value = tags[field]\n            if self.match_patterns(value, patterns):\n                log.debug(u'[zero] {0}: {1} -> None'.format(field, value))\n                tags[field] = None\n", "path": "beetsplug/zero.py"}]}