prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Use information on how a bug is filed as a feature
  This could be especially useful for the Spam model.
  
  https://bugzilla.mozilla.org/show_bug.cgi?id=1565403
  
  </issue>
  <code>
  [start of bugbug/models/spambug.py]
  1 # -*- coding: utf-8 -*-
  2 # This Source Code Form is subject to the terms of the Mozilla Public
  3 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4 # You can obtain one at http://mozilla.org/MPL/2.0/.
  5 
  6 import xgboost
  7 from imblearn.over_sampling import BorderlineSMOTE
  8 from sklearn.compose import ColumnTransformer
  9 from sklearn.feature_extraction import DictVectorizer
  10 from sklearn.pipeline import Pipeline
  11 
  12 from bugbug import bug_features, bugzilla, feature_cleanup, utils
  13 from bugbug.model import BugModel
  14 
  15 
  16 class SpamBugModel(BugModel):
  17     def __init__(self, lemmatization=False):
  18         BugModel.__init__(self, lemmatization)
  19 
  20         self.sampler = BorderlineSMOTE(random_state=0)
  21         self.calculate_importance = False
  22 
  23         feature_extractors = [
  24             bug_features.has_str(),
  25             bug_features.has_regression_range(),
  26             bug_features.severity(),
  27             bug_features.has_crash_signature(),
  28             bug_features.has_url(),
  29             bug_features.whiteboard(),
  30             bug_features.product(),
  31             # TODO: We would like to use the component at the time of filing too,
  32             # but we can't because the rollback script doesn't support changes to
  33             # components yet.
  34             # bug_features.component(),
  35             bug_features.num_words_title(),
  36             bug_features.num_words_comments(),
  37             bug_features.keywords(),
  38             bug_features.priority(),
  39             bug_features.version(),
  40             bug_features.target_milestone(),
  41             bug_features.has_attachment(),
  42             bug_features.platform(),
  43             bug_features.op_sys(),
  44         ]
  45 
  46         cleanup_functions = [
  47             feature_cleanup.fileref(),
  48             feature_cleanup.url(),
  49             feature_cleanup.synonyms(),
  50         ]
  51 
  52         self.extraction_pipeline = Pipeline(
  53             [
  54                 (
  55                     "bug_extractor",
  56                     bug_features.BugExtractor(
  57                         feature_extractors, cleanup_functions, rollback=True
  58                     ),
  59                 ),
  60                 (
  61                     "union",
  62                     ColumnTransformer(
  63                         [
  64                             ("data", DictVectorizer(), "data"),
  65                             ("title", self.text_vectorizer(min_df=0.0001), "title"),
  66                             (
  67                                 "comments",
  68                                 self.text_vectorizer(min_df=0.0001),
  69                                 "comments",
  70                             ),
  71                         ]
  72                     ),
  73                 ),
  74             ]
  75         )
  76 
  77         self.clf = xgboost.XGBClassifier(n_jobs=utils.get_physical_cpu_count())
  78         self.clf.set_params(predictor="cpu_predictor")
  79 
  80     def get_labels(self):
  81         classes = {}
  82 
  83         for bug_data in bugzilla.get_bugs(include_invalid=True):
  84             bug_id = bug_data["id"]
  85 
  86             # Skip bugs filed by Mozillians, since we are sure they are not spam.
  87             if "@mozilla" in bug_data["creator"]:
  88                 continue
  89 
  90             # A bug that was moved out of 'Invalid Bugs' is definitely a legitimate bug.
  91             for history in bug_data["history"]:
  92                 for change in history["changes"]:
  93                     if (
  94                         change["field_name"] == "product"
  95                         and change["removed"] == "Invalid Bugs"
  96                     ):
  97                         classes[bug_id] = 0
  98 
  99             # A fixed bug is definitely a legitimate bug.
  100             if bug_data["resolution"] == "FIXED":
  101                 classes[bug_id] = 0
  102 
  103             # A bug in the 'Invalid Bugs' product is definitely a spam bug.
  104             elif bug_data["product"] == "Invalid Bugs":
  105                 classes[bug_id] = 1
  106 
  107         print(
  108             "{} bugs are classified as non-spam".format(
  109                 sum(1 for label in classes.values() if label == 0)
  110             )
  111         )
  112         print(
  113             "{} bugs are classified as spam".format(
  114                 sum(1 for label in classes.values() if label == 1)
  115             )
  116         )
  117 
  118         return classes, [0, 1]
  119 
  120     def items_gen(self, classes):
  121         # Overwriting this method to add include_invalid=True to get_bugs to
  122         # include spam bugs.
  123         return (
  124             (bug, classes[bug["id"]])
  125             for bug in bugzilla.get_bugs(include_invalid=True)
  126             if bug["id"] in classes
  127         )
  128 
  129     def get_feature_names(self):
  130         return self.extraction_pipeline.named_steps["union"].get_feature_names_out()
  131 
  132     def overwrite_classes(self, bugs, classes, probabilities):
  133         for i, bug in enumerate(bugs):
  134             if "@mozilla" in bug["creator"]:
  135                 if probabilities:
  136                     classes[i] = [1.0, 0.0]
  137                 else:
  138                     classes[i] = 0
  139 
  140         return classes
  141
  [end of bugbug/models/spambug.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/bugbug/models/spambug.py b/bugbug/models/spambug.py
  --- a/bugbug/models/spambug.py
  +++ b/bugbug/models/spambug.py
  @@ -41,6 +41,7 @@
               bug_features.has_attachment(),
               bug_features.platform(),
               bug_features.op_sys(),
  +            bug_features.filed_via(),
           ]
   
           cleanup_functions = [
  
verification_info: {"golden_diff": "diff --git a/bugbug/models/spambug.py b/bugbug/models/spambug.py\n--- a/bugbug/models/spambug.py\n+++ b/bugbug/models/spambug.py\n@@ -41,6 +41,7 @@\n             bug_features.has_attachment(),\n             bug_features.platform(),\n             bug_features.op_sys(),\n+            bug_features.filed_via(),\n         ]\n \n         cleanup_functions = [\n", "issue": "Use information on how a bug is filed as a feature\nThis could be especially useful for the Spam model.\r\n\r\nhttps://bugzilla.mozilla.org/show_bug.cgi?id=1565403\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# This Source Code Form is subject to the terms of the Mozilla Public\n# License, v. 2.0. If a copy of the MPL was not distributed with this file,\n# You can obtain one at http://mozilla.org/MPL/2.0/.\n\nimport xgboost\nfrom imblearn.over_sampling import BorderlineSMOTE\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.feature_extraction import DictVectorizer\nfrom sklearn.pipeline import Pipeline\n\nfrom bugbug import bug_features, bugzilla, feature_cleanup, utils\nfrom bugbug.model import BugModel\n\n\nclass SpamBugModel(BugModel):\n    def __init__(self, lemmatization=False):\n        BugModel.__init__(self, lemmatization)\n\n        self.sampler = BorderlineSMOTE(random_state=0)\n        self.calculate_importance = False\n\n        feature_extractors = [\n            bug_features.has_str(),\n            bug_features.has_regression_range(),\n            bug_features.severity(),\n            bug_features.has_crash_signature(),\n            bug_features.has_url(),\n            bug_features.whiteboard(),\n            bug_features.product(),\n            # TODO: We would like to use the component at the time of filing too,\n            # but we can't because the rollback script doesn't support changes to\n            # components yet.\n            # bug_features.component(),\n            bug_features.num_words_title(),\n            bug_features.num_words_comments(),\n            bug_features.keywords(),\n            bug_features.priority(),\n            bug_features.version(),\n            bug_features.target_milestone(),\n            bug_features.has_attachment(),\n            bug_features.platform(),\n            bug_features.op_sys(),\n        ]\n\n        cleanup_functions = [\n            feature_cleanup.fileref(),\n            feature_cleanup.url(),\n            feature_cleanup.synonyms(),\n        ]\n\n        self.extraction_pipeline = Pipeline(\n            [\n                (\n                    \"bug_extractor\",\n                    bug_features.BugExtractor(\n                        feature_extractors, cleanup_functions, rollback=True\n                    ),\n                ),\n                (\n                    \"union\",\n                    ColumnTransformer(\n                        [\n                            (\"data\", DictVectorizer(), \"data\"),\n                            (\"title\", self.text_vectorizer(min_df=0.0001), \"title\"),\n                            (\n                                \"comments\",\n                                self.text_vectorizer(min_df=0.0001),\n                                \"comments\",\n                            ),\n                        ]\n                    ),\n                ),\n            ]\n        )\n\n        self.clf = xgboost.XGBClassifier(n_jobs=utils.get_physical_cpu_count())\n        self.clf.set_params(predictor=\"cpu_predictor\")\n\n    def get_labels(self):\n        classes = {}\n\n        for bug_data in bugzilla.get_bugs(include_invalid=True):\n            bug_id = bug_data[\"id\"]\n\n            # Skip bugs filed by Mozillians, since we are sure they are not spam.\n            if \"@mozilla\" in bug_data[\"creator\"]:\n                continue\n\n            # A bug that was moved out of 'Invalid Bugs' is definitely a legitimate bug.\n            for history in bug_data[\"history\"]:\n                for change in history[\"changes\"]:\n                    if (\n                        change[\"field_name\"] == \"product\"\n                        and change[\"removed\"] == \"Invalid Bugs\"\n                    ):\n                        classes[bug_id] = 0\n\n            # A fixed bug is definitely a legitimate bug.\n            if bug_data[\"resolution\"] == \"FIXED\":\n                classes[bug_id] = 0\n\n            # A bug in the 'Invalid Bugs' product is definitely a spam bug.\n            elif bug_data[\"product\"] == \"Invalid Bugs\":\n                classes[bug_id] = 1\n\n        print(\n            \"{} bugs are classified as non-spam\".format(\n                sum(1 for label in classes.values() if label == 0)\n            )\n        )\n        print(\n            \"{} bugs are classified as spam\".format(\n                sum(1 for label in classes.values() if label == 1)\n            )\n        )\n\n        return classes, [0, 1]\n\n    def items_gen(self, classes):\n        # Overwriting this method to add include_invalid=True to get_bugs to\n        # include spam bugs.\n        return (\n            (bug, classes[bug[\"id\"]])\n            for bug in bugzilla.get_bugs(include_invalid=True)\n            if bug[\"id\"] in classes\n        )\n\n    def get_feature_names(self):\n        return self.extraction_pipeline.named_steps[\"union\"].get_feature_names_out()\n\n    def overwrite_classes(self, bugs, classes, probabilities):\n        for i, bug in enumerate(bugs):\n            if \"@mozilla\" in bug[\"creator\"]:\n                if probabilities:\n                    classes[i] = [1.0, 0.0]\n                else:\n                    classes[i] = 0\n\n        return classes\n", "path": "bugbug/models/spambug.py"}]}