prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Allow Paths in save()
  Instead of allowing only string paths or file-likes, allow pathlib.Paths to be passed to `save()`.
  
  Are these two the only places that would have to be changed?
  
  https://github.com/altair-viz/altair/blob/54e03d403c1cec9ce2f2e8b14dc3d936c6686128/altair/utils/save.py#L8
  https://github.com/altair-viz/altair/blob/54e03d403c1cec9ce2f2e8b14dc3d936c6686128/altair/utils/save.py#L72
  
  </issue>
  <code>
  [start of altair/utils/save.py]
  1 import json
  2 
  3 from .mimebundle import spec_to_mimebundle
  4 
  5 
  6 def write_file_or_filename(fp, content, mode="w"):
  7     """Write content to fp, whether fp is a string or a file-like object"""
  8     if isinstance(fp, str):
  9         with open(fp, mode) as f:
  10             f.write(content)
  11     else:
  12         fp.write(content)
  13 
  14 
  15 def save(
  16     chart,
  17     fp,
  18     vega_version,
  19     vegaembed_version,
  20     format=None,
  21     mode=None,
  22     vegalite_version=None,
  23     embed_options=None,
  24     json_kwds=None,
  25     webdriver="chrome",
  26     scale_factor=1,
  27     **kwargs,
  28 ):
  29     """Save a chart to file in a variety of formats
  30 
  31     Supported formats are [json, html, png, svg]
  32 
  33     Parameters
  34     ----------
  35     chart : alt.Chart
  36         the chart instance to save
  37     fp : string filename or file-like object
  38         file in which to write the chart.
  39     format : string (optional)
  40         the format to write: one of ['json', 'html', 'png', 'svg'].
  41         If not specified, the format will be determined from the filename.
  42     mode : string (optional)
  43         Either 'vega' or 'vegalite'. If not specified, then infer the mode from
  44         the '$schema' property of the spec, or the ``opt`` dictionary.
  45         If it's not specified in either of those places, then use 'vegalite'.
  46     vega_version : string
  47         For html output, the version of vega.js to use
  48     vegalite_version : string
  49         For html output, the version of vegalite.js to use
  50     vegaembed_version : string
  51         For html output, the version of vegaembed.js to use
  52     embed_options : dict
  53         The vegaEmbed options dictionary. Default is {}
  54         (See https://github.com/vega/vega-embed for details)
  55     json_kwds : dict
  56         Additional keyword arguments are passed to the output method
  57         associated with the specified format.
  58     webdriver : string {'chrome' | 'firefox'}
  59         Webdriver to use for png or svg output
  60     scale_factor : float
  61         scale_factor to use to change size/resolution of png or svg output
  62     **kwargs :
  63         additional kwargs passed to spec_to_mimebundle.
  64     """
  65     if json_kwds is None:
  66         json_kwds = {}
  67 
  68     if embed_options is None:
  69         embed_options = {}
  70 
  71     if format is None:
  72         if isinstance(fp, str):
  73             format = fp.split(".")[-1]
  74         else:
  75             raise ValueError(
  76                 "must specify file format: " "['png', 'svg', 'pdf', 'html', 'json']"
  77             )
  78 
  79     spec = chart.to_dict()
  80 
  81     if mode is None:
  82         if "mode" in embed_options:
  83             mode = embed_options["mode"]
  84         elif "$schema" in spec:
  85             mode = spec["$schema"].split("/")[-2]
  86         else:
  87             mode = "vega-lite"
  88 
  89     if mode not in ["vega", "vega-lite"]:
  90         raise ValueError("mode must be 'vega' or 'vega-lite', " "not '{}'".format(mode))
  91 
  92     if mode == "vega-lite" and vegalite_version is None:
  93         raise ValueError("must specify vega-lite version")
  94 
  95     if format == "json":
  96         json_spec = json.dumps(spec, **json_kwds)
  97         write_file_or_filename(fp, json_spec, mode="w")
  98     elif format == "html":
  99         mimebundle = spec_to_mimebundle(
  100             spec=spec,
  101             format=format,
  102             mode=mode,
  103             vega_version=vega_version,
  104             vegalite_version=vegalite_version,
  105             vegaembed_version=vegaembed_version,
  106             embed_options=embed_options,
  107             json_kwds=json_kwds,
  108             **kwargs,
  109         )
  110         write_file_or_filename(fp, mimebundle["text/html"], mode="w")
  111     elif format in ["png", "svg", "pdf"]:
  112         mimebundle = spec_to_mimebundle(
  113             spec=spec,
  114             format=format,
  115             mode=mode,
  116             vega_version=vega_version,
  117             vegalite_version=vegalite_version,
  118             vegaembed_version=vegaembed_version,
  119             webdriver=webdriver,
  120             scale_factor=scale_factor,
  121             **kwargs,
  122         )
  123         if format == "png":
  124             write_file_or_filename(fp, mimebundle["image/png"], mode="wb")
  125         elif format == "pdf":
  126             write_file_or_filename(fp, mimebundle["application/pdf"], mode="wb")
  127         else:
  128             write_file_or_filename(fp, mimebundle["image/svg+xml"], mode="w")
  129     else:
  130         raise ValueError("unrecognized format: '{}'".format(format))
  131
  [end of altair/utils/save.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/altair/utils/save.py b/altair/utils/save.py
  --- a/altair/utils/save.py
  +++ b/altair/utils/save.py
  @@ -1,11 +1,13 @@
   import json
  +import pathlib
   
   from .mimebundle import spec_to_mimebundle
   
   
   def write_file_or_filename(fp, content, mode="w"):
  -    """Write content to fp, whether fp is a string or a file-like object"""
  -    if isinstance(fp, str):
  +    """Write content to fp, whether fp is a string, a pathlib Path or a
  +    file-like object"""
  +    if isinstance(fp, str) or isinstance(fp, pathlib.PurePath):
           with open(fp, mode) as f:
               f.write(content)
       else:
  @@ -34,8 +36,8 @@
       ----------
       chart : alt.Chart
           the chart instance to save
  -    fp : string filename or file-like object
  -        file in which to write the chart.
  +    fp : string filename, pathlib.Path or file-like object
  +        file to which to write the chart.
       format : string (optional)
           the format to write: one of ['json', 'html', 'png', 'svg'].
           If not specified, the format will be determined from the filename.
  @@ -71,6 +73,8 @@
       if format is None:
           if isinstance(fp, str):
               format = fp.split(".")[-1]
  +        elif isinstance(fp, pathlib.PurePath):
  +            format = fp.suffix.lstrip(".")
           else:
               raise ValueError(
                   "must specify file format: " "['png', 'svg', 'pdf', 'html', 'json']"
  
verification_info: {"golden_diff": "diff --git a/altair/utils/save.py b/altair/utils/save.py\n--- a/altair/utils/save.py\n+++ b/altair/utils/save.py\n@@ -1,11 +1,13 @@\n import json\n+import pathlib\n \n from .mimebundle import spec_to_mimebundle\n \n \n def write_file_or_filename(fp, content, mode=\"w\"):\n-    \"\"\"Write content to fp, whether fp is a string or a file-like object\"\"\"\n-    if isinstance(fp, str):\n+    \"\"\"Write content to fp, whether fp is a string, a pathlib Path or a\n+    file-like object\"\"\"\n+    if isinstance(fp, str) or isinstance(fp, pathlib.PurePath):\n         with open(fp, mode) as f:\n             f.write(content)\n     else:\n@@ -34,8 +36,8 @@\n     ----------\n     chart : alt.Chart\n         the chart instance to save\n-    fp : string filename or file-like object\n-        file in which to write the chart.\n+    fp : string filename, pathlib.Path or file-like object\n+        file to which to write the chart.\n     format : string (optional)\n         the format to write: one of ['json', 'html', 'png', 'svg'].\n         If not specified, the format will be determined from the filename.\n@@ -71,6 +73,8 @@\n     if format is None:\n         if isinstance(fp, str):\n             format = fp.split(\".\")[-1]\n+        elif isinstance(fp, pathlib.PurePath):\n+            format = fp.suffix.lstrip(\".\")\n         else:\n             raise ValueError(\n                 \"must specify file format: \" \"['png', 'svg', 'pdf', 'html', 'json']\"\n", "issue": "Allow Paths in save()\nInstead of allowing only string paths or file-likes, allow pathlib.Paths to be passed to `save()`.\r\n\r\nAre these two the only places that would have to be changed?\r\n\r\nhttps://github.com/altair-viz/altair/blob/54e03d403c1cec9ce2f2e8b14dc3d936c6686128/altair/utils/save.py#L8\r\nhttps://github.com/altair-viz/altair/blob/54e03d403c1cec9ce2f2e8b14dc3d936c6686128/altair/utils/save.py#L72\n", "before_files": [{"content": "import json\n\nfrom .mimebundle import spec_to_mimebundle\n\n\ndef write_file_or_filename(fp, content, mode=\"w\"):\n    \"\"\"Write content to fp, whether fp is a string or a file-like object\"\"\"\n    if isinstance(fp, str):\n        with open(fp, mode) as f:\n            f.write(content)\n    else:\n        fp.write(content)\n\n\ndef save(\n    chart,\n    fp,\n    vega_version,\n    vegaembed_version,\n    format=None,\n    mode=None,\n    vegalite_version=None,\n    embed_options=None,\n    json_kwds=None,\n    webdriver=\"chrome\",\n    scale_factor=1,\n    **kwargs,\n):\n    \"\"\"Save a chart to file in a variety of formats\n\n    Supported formats are [json, html, png, svg]\n\n    Parameters\n    ----------\n    chart : alt.Chart\n        the chart instance to save\n    fp : string filename or file-like object\n        file in which to write the chart.\n    format : string (optional)\n        the format to write: one of ['json', 'html', 'png', 'svg'].\n        If not specified, the format will be determined from the filename.\n    mode : string (optional)\n        Either 'vega' or 'vegalite'. If not specified, then infer the mode from\n        the '$schema' property of the spec, or the ``opt`` dictionary.\n        If it's not specified in either of those places, then use 'vegalite'.\n    vega_version : string\n        For html output, the version of vega.js to use\n    vegalite_version : string\n        For html output, the version of vegalite.js to use\n    vegaembed_version : string\n        For html output, the version of vegaembed.js to use\n    embed_options : dict\n        The vegaEmbed options dictionary. Default is {}\n        (See https://github.com/vega/vega-embed for details)\n    json_kwds : dict\n        Additional keyword arguments are passed to the output method\n        associated with the specified format.\n    webdriver : string {'chrome' | 'firefox'}\n        Webdriver to use for png or svg output\n    scale_factor : float\n        scale_factor to use to change size/resolution of png or svg output\n    **kwargs :\n        additional kwargs passed to spec_to_mimebundle.\n    \"\"\"\n    if json_kwds is None:\n        json_kwds = {}\n\n    if embed_options is None:\n        embed_options = {}\n\n    if format is None:\n        if isinstance(fp, str):\n            format = fp.split(\".\")[-1]\n        else:\n            raise ValueError(\n                \"must specify file format: \" \"['png', 'svg', 'pdf', 'html', 'json']\"\n            )\n\n    spec = chart.to_dict()\n\n    if mode is None:\n        if \"mode\" in embed_options:\n            mode = embed_options[\"mode\"]\n        elif \"$schema\" in spec:\n            mode = spec[\"$schema\"].split(\"/\")[-2]\n        else:\n            mode = \"vega-lite\"\n\n    if mode not in [\"vega\", \"vega-lite\"]:\n        raise ValueError(\"mode must be 'vega' or 'vega-lite', \" \"not '{}'\".format(mode))\n\n    if mode == \"vega-lite\" and vegalite_version is None:\n        raise ValueError(\"must specify vega-lite version\")\n\n    if format == \"json\":\n        json_spec = json.dumps(spec, **json_kwds)\n        write_file_or_filename(fp, json_spec, mode=\"w\")\n    elif format == \"html\":\n        mimebundle = spec_to_mimebundle(\n            spec=spec,\n            format=format,\n            mode=mode,\n            vega_version=vega_version,\n            vegalite_version=vegalite_version,\n            vegaembed_version=vegaembed_version,\n            embed_options=embed_options,\n            json_kwds=json_kwds,\n            **kwargs,\n        )\n        write_file_or_filename(fp, mimebundle[\"text/html\"], mode=\"w\")\n    elif format in [\"png\", \"svg\", \"pdf\"]:\n        mimebundle = spec_to_mimebundle(\n            spec=spec,\n            format=format,\n            mode=mode,\n            vega_version=vega_version,\n            vegalite_version=vegalite_version,\n            vegaembed_version=vegaembed_version,\n            webdriver=webdriver,\n            scale_factor=scale_factor,\n            **kwargs,\n        )\n        if format == \"png\":\n            write_file_or_filename(fp, mimebundle[\"image/png\"], mode=\"wb\")\n        elif format == \"pdf\":\n            write_file_or_filename(fp, mimebundle[\"application/pdf\"], mode=\"wb\")\n        else:\n            write_file_or_filename(fp, mimebundle[\"image/svg+xml\"], mode=\"w\")\n    else:\n        raise ValueError(\"unrecognized format: '{}'\".format(format))\n", "path": "altair/utils/save.py"}]}