We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unable to use Tidy on html
Hi, 

I enabled the tidy filter on html file:

from nikola import filters
FILTERS = {
        ".html": [filters.tidy],
        }

and now NIkola refuses to build my site: 

TaskError - taskid:render_tags:../categories/index.html
PythonAction Error
Traceback (most recent call last):
  File "/usr/lib64/python3.3/site-packages/doit/action.py", line 360, in execute
    returned_value = self.py_callable(_self.args, *_kwargs)
  File "/usr/lib64/python3.3/site-packages/nikola/utils.py", line 529, in unlessLink
    action(target)
  File "/usr/lib64/python3.3/site-packages/nikola/filters.py", line 144, in tidy
    for line in output.split("\n"):
TypeError: Type str doesn't support the buffer AP

Is there a problem with tidy ? Can I use another thing as a replacement ?

Unable to use Tidy on html
Hi, 

I enabled the tidy filter on html file:

from nikola import filters
FILTERS = {
        ".html": [filters.tidy],
        }

and now NIkola refuses to build my site: 

TaskError - taskid:render_tags:../categories/index.html
PythonAction Error
Traceback (most recent call last):
  File "/usr/lib64/python3.3/site-packages/doit/action.py", line 360, in execute
    returned_value = self.py_callable(_self.args, *_kwargs)
  File "/usr/lib64/python3.3/site-packages/nikola/utils.py", line 529, in unlessLink
    action(target)
  File "/usr/lib64/python3.3/site-packages/nikola/filters.py", line 144, in tidy
    for line in output.split("\n"):
TypeError: Type str doesn't support the buffer AP

Is there a problem with tidy ? Can I use another thing as a replacement ?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nikola/filters.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright © 2012-2014 Roberto Alsina and others.
4 
5 # Permission is hereby granted, free of charge, to any
6 # person obtaining a copy of this software and associated
7 # documentation files (the "Software"), to deal in the
8 # Software without restriction, including without limitation
9 # the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the
11 # Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice
15 # shall be included in all copies or substantial portions of
16 # the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
22 # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 """Utility functions to help you run filters on files."""
28 
29 from .utils import req_missing
30 from functools import wraps
31 import os
32 import codecs
33 import re
34 import shutil
35 import subprocess
36 import tempfile
37 import shlex
38 
39 try:
40     import typogrify.filters as typo
41 except ImportError:
42     typo = None  # NOQA
43 
44 
45 def apply_to_binary_file(f):
46     """Take a function f that transforms a data argument, and returns
47     a function that takes a filename and applies f to the contents,
48     in place.  Reads files in binary mode."""
49     @wraps(f)
50     def f_in_file(fname):
51         with open(fname, 'rb') as inf:
52             data = inf.read()
53         data = f(data)
54         with open(fname, 'wb+') as outf:
55             outf.write(data)
56 
57     return f_in_file
58 
59 
60 def apply_to_text_file(f):
61     """Take a function f that transforms a data argument, and returns
62     a function that takes a filename and applies f to the contents,
63     in place.  Reads files in UTF-8."""
64     @wraps(f)
65     def f_in_file(fname):
66         with codecs.open(fname, 'r', 'utf-8') as inf:
67             data = inf.read()
68         data = f(data)
69         with codecs.open(fname, 'w+', 'utf-8') as outf:
70             outf.write(data)
71 
72     return f_in_file
73 
74 
75 def list_replace(the_list, find, replacement):
76     "Replace all occurrences of ``find`` with ``replacement`` in ``the_list``"
77     for i, v in enumerate(the_list):
78         if v == find:
79             the_list[i] = replacement
80 
81 
82 def runinplace(command, infile):
83     """Run a command in-place on a file.
84 
85     command is a string of the form: "commandname %1 %2" and
86     it will be execed with infile as %1 and a temporary file
87     as %2. Then, that temporary file will be moved over %1.
88 
89     Example usage:
90 
91     runinplace("yui-compressor %1 -o %2", "myfile.css")
92 
93     That will replace myfile.css with a minified version.
94 
95     You can also supply command as a list.
96     """
97 
98     if not isinstance(command, list):
99         command = shlex.split(command)
100 
101     tmpdir = None
102 
103     if "%2" in command:
104         tmpdir = tempfile.mkdtemp(prefix="nikola")
105         tmpfname = os.path.join(tmpdir, os.path.basename(infile))
106 
107     try:
108         list_replace(command, "%1", infile)
109         if tmpdir:
110             list_replace(command, "%2", tmpfname)
111 
112         subprocess.check_call(command)
113 
114         if tmpdir:
115             shutil.move(tmpfname, infile)
116     finally:
117         if tmpdir:
118             shutil.rmtree(tmpdir)
119 
120 
121 def yui_compressor(infile):
122     yuicompressor = False
123     try:
124         subprocess.call('yui-compressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))
125         yuicompressor = 'yui-compressor'
126     except Exception:
127         pass
128     if not yuicompressor:
129         try:
130             subprocess.call('yuicompressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))
131             yuicompressor = 'yuicompressor'
132         except:
133             raise Exception("yui-compressor is not installed.")
134             return False
135 
136     return runinplace(r'{} --nomunge %1 -o %2'.format(yuicompressor), infile)
137 
138 
139 def optipng(infile):
140     return runinplace(r"optipng -preserve -o2 -quiet %1", infile)
141 
142 
143 def jpegoptim(infile):
144     return runinplace(r"jpegoptim -p --strip-all -q %1", infile)
145 
146 
147 def tidy(inplace):
148     # Google site verifcation files are not HTML
149     if re.match(r"google[a-f0-9]+.html", os.path.basename(inplace)) \
150             and open(inplace).readline().startswith(
151                 "google-site-verification:"):
152         return
153 
154     # Tidy will give error exits, that we will ignore.
155     output = subprocess.check_output(
156         "tidy -m -w 90 --indent no --quote-marks"
157         "no --keep-time yes --tidy-mark no "
158         "--force-output yes '{0}'; exit 0".format(inplace), stderr=subprocess.STDOUT, shell=True)
159 
160     for line in output.split("\n"):
161         if "Warning:" in line:
162             if '<meta> proprietary attribute "charset"' in line:
163                 # We want to set it though.
164                 continue
165             elif '<meta> lacks "content" attribute' in line:
166                 # False alarm to me.
167                 continue
168             elif '<div> anchor' in line and 'already defined' in line:
169                 # Some seeming problem with JavaScript terminators.
170                 continue
171             elif '<img> lacks "alt" attribute' in line:
172                 # Happens in gallery code, probably can be tolerated.
173                 continue
174             elif '<table> lacks "summary" attribute' in line:
175                 # Happens for tables, TODO: Check this is normal.
176                 continue
177             elif 'proprietary attribute "data-toggle"' in line or \
178                  'proprietary attribute "data-target"':
179                 # Some of our own tricks
180                 continue
181             else:
182                 assert False, (inplace, line)
183         elif "Error:" in line:
184             if '<time> is not recognized' in line:
185                 # False alarm, time is proper HTML5.
186                 continue
187             else:
188                 assert False, line
189 
190 
191 @apply_to_text_file
192 def typogrify(data):
193     if typo is None:
194         req_missing(['typogrify'], 'use the typogrify filter')
195 
196     data = typo.amp(data)
197     data = typo.widont(data)
198     data = typo.smartypants(data)
199     # Disabled because of typogrify bug where it breaks <title>
200     # data = typo.caps(data)
201     data = typo.initial_quotes(data)
202     return data
203
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nikola/filters.py b/nikola/filters.py
--- a/nikola/filters.py
+++ b/nikola/filters.py
@@ -30,7 +30,6 @@
 from functools import wraps
 import os
 import codecs
-import re
 import shutil
 import subprocess
 import tempfile
@@ -144,50 +143,6 @@
     return runinplace(r"jpegoptim -p --strip-all -q %1", infile)
 
 
-def tidy(inplace):
-    # Google site verifcation files are not HTML
-    if re.match(r"google[a-f0-9]+.html", os.path.basename(inplace)) \
-            and open(inplace).readline().startswith(
-                "google-site-verification:"):
-        return
-
-    # Tidy will give error exits, that we will ignore.
-    output = subprocess.check_output(
-        "tidy -m -w 90 --indent no --quote-marks"
-        "no --keep-time yes --tidy-mark no "
-        "--force-output yes '{0}'; exit 0".format(inplace), stderr=subprocess.STDOUT, shell=True)
-
-    for line in output.split("\n"):
-        if "Warning:" in line:
-            if '<meta> proprietary attribute "charset"' in line:
-                # We want to set it though.
-                continue
-            elif '<meta> lacks "content" attribute' in line:
-                # False alarm to me.
-                continue
-            elif '<div> anchor' in line and 'already defined' in line:
-                # Some seeming problem with JavaScript terminators.
-                continue
-            elif '<img> lacks "alt" attribute' in line:
-                # Happens in gallery code, probably can be tolerated.
-                continue
-            elif '<table> lacks "summary" attribute' in line:
-                # Happens for tables, TODO: Check this is normal.
-                continue
-            elif 'proprietary attribute "data-toggle"' in line or \
-                 'proprietary attribute "data-target"':
-                # Some of our own tricks
-                continue
-            else:
-                assert False, (inplace, line)
-        elif "Error:" in line:
-            if '<time> is not recognized' in line:
-                # False alarm, time is proper HTML5.
-                continue
-            else:
-                assert False, line
-
-
 @apply_to_text_file
 def typogrify(data):
     if typo is None:

{"golden_diff": "diff --git a/nikola/filters.py b/nikola/filters.py\n--- a/nikola/filters.py\n+++ b/nikola/filters.py\n@@ -30,7 +30,6 @@\n from functools import wraps\n import os\n import codecs\n-import re\n import shutil\n import subprocess\n import tempfile\n@@ -144,50 +143,6 @@\n     return runinplace(r\"jpegoptim -p --strip-all -q %1\", infile)\n \n \n-def tidy(inplace):\n-    # Google site verifcation files are not HTML\n-    if re.match(r\"google[a-f0-9]+.html\", os.path.basename(inplace)) \\\n-            and open(inplace).readline().startswith(\n-                \"google-site-verification:\"):\n-        return\n-\n-    # Tidy will give error exits, that we will ignore.\n-    output = subprocess.check_output(\n-        \"tidy -m -w 90 --indent no --quote-marks\"\n-        \"no --keep-time yes --tidy-mark no \"\n-        \"--force-output yes '{0}'; exit 0\".format(inplace), stderr=subprocess.STDOUT, shell=True)\n-\n-    for line in output.split(\"\\n\"):\n-        if \"Warning:\" in line:\n-            if '<meta> proprietary attribute \"charset\"' in line:\n-                # We want to set it though.\n-                continue\n-            elif '<meta> lacks \"content\" attribute' in line:\n-                # False alarm to me.\n-                continue\n-            elif '<div> anchor' in line and 'already defined' in line:\n-                # Some seeming problem with JavaScript terminators.\n-                continue\n-            elif '<img> lacks \"alt\" attribute' in line:\n-                # Happens in gallery code, probably can be tolerated.\n-                continue\n-            elif '<table> lacks \"summary\" attribute' in line:\n-                # Happens for tables, TODO: Check this is normal.\n-                continue\n-            elif 'proprietary attribute \"data-toggle\"' in line or \\\n-                 'proprietary attribute \"data-target\"':\n-                # Some of our own tricks\n-                continue\n-            else:\n-                assert False, (inplace, line)\n-        elif \"Error:\" in line:\n-            if '<time> is not recognized' in line:\n-                # False alarm, time is proper HTML5.\n-                continue\n-            else:\n-                assert False, line\n-\n-\n @apply_to_text_file\n def typogrify(data):\n     if typo is None:\n", "issue": "Unable to use Tidy on html\nHi, \n\nI enabled the tidy filter on html file:\n\nfrom nikola import filters\nFILTERS = {\n        \".html\": [filters.tidy],\n        }\n\nand now NIkola refuses to build my site: \n\nTaskError - taskid:render_tags:../categories/index.html\nPythonAction Error\nTraceback (most recent call last):\n  File \"/usr/lib64/python3.3/site-packages/doit/action.py\", line 360, in execute\n    returned_value = self.py_callable(_self.args, *_kwargs)\n  File \"/usr/lib64/python3.3/site-packages/nikola/utils.py\", line 529, in unlessLink\n    action(target)\n  File \"/usr/lib64/python3.3/site-packages/nikola/filters.py\", line 144, in tidy\n    for line in output.split(\"\\n\"):\nTypeError: Type str doesn't support the buffer AP\n\nIs there a problem with tidy ? Can I use another thing as a replacement ?\n\nUnable to use Tidy on html\nHi, \n\nI enabled the tidy filter on html file:\n\nfrom nikola import filters\nFILTERS = {\n        \".html\": [filters.tidy],\n        }\n\nand now NIkola refuses to build my site: \n\nTaskError - taskid:render_tags:../categories/index.html\nPythonAction Error\nTraceback (most recent call last):\n  File \"/usr/lib64/python3.3/site-packages/doit/action.py\", line 360, in execute\n    returned_value = self.py_callable(_self.args, *_kwargs)\n  File \"/usr/lib64/python3.3/site-packages/nikola/utils.py\", line 529, in unlessLink\n    action(target)\n  File \"/usr/lib64/python3.3/site-packages/nikola/filters.py\", line 144, in tidy\n    for line in output.split(\"\\n\"):\nTypeError: Type str doesn't support the buffer AP\n\nIs there a problem with tidy ? Can I use another thing as a replacement ?\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2014 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Utility functions to help you run filters on files.\"\"\"\n\nfrom .utils import req_missing\nfrom functools import wraps\nimport os\nimport codecs\nimport re\nimport shutil\nimport subprocess\nimport tempfile\nimport shlex\n\ntry:\n    import typogrify.filters as typo\nexcept ImportError:\n    typo = None  # NOQA\n\n\ndef apply_to_binary_file(f):\n    \"\"\"Take a function f that transforms a data argument, and returns\n    a function that takes a filename and applies f to the contents,\n    in place.  Reads files in binary mode.\"\"\"\n    @wraps(f)\n    def f_in_file(fname):\n        with open(fname, 'rb') as inf:\n            data = inf.read()\n        data = f(data)\n        with open(fname, 'wb+') as outf:\n            outf.write(data)\n\n    return f_in_file\n\n\ndef apply_to_text_file(f):\n    \"\"\"Take a function f that transforms a data argument, and returns\n    a function that takes a filename and applies f to the contents,\n    in place.  Reads files in UTF-8.\"\"\"\n    @wraps(f)\n    def f_in_file(fname):\n        with codecs.open(fname, 'r', 'utf-8') as inf:\n            data = inf.read()\n        data = f(data)\n        with codecs.open(fname, 'w+', 'utf-8') as outf:\n            outf.write(data)\n\n    return f_in_file\n\n\ndef list_replace(the_list, find, replacement):\n    \"Replace all occurrences of ``find`` with ``replacement`` in ``the_list``\"\n    for i, v in enumerate(the_list):\n        if v == find:\n            the_list[i] = replacement\n\n\ndef runinplace(command, infile):\n    \"\"\"Run a command in-place on a file.\n\n    command is a string of the form: \"commandname %1 %2\" and\n    it will be execed with infile as %1 and a temporary file\n    as %2. Then, that temporary file will be moved over %1.\n\n    Example usage:\n\n    runinplace(\"yui-compressor %1 -o %2\", \"myfile.css\")\n\n    That will replace myfile.css with a minified version.\n\n    You can also supply command as a list.\n    \"\"\"\n\n    if not isinstance(command, list):\n        command = shlex.split(command)\n\n    tmpdir = None\n\n    if \"%2\" in command:\n        tmpdir = tempfile.mkdtemp(prefix=\"nikola\")\n        tmpfname = os.path.join(tmpdir, os.path.basename(infile))\n\n    try:\n        list_replace(command, \"%1\", infile)\n        if tmpdir:\n            list_replace(command, \"%2\", tmpfname)\n\n        subprocess.check_call(command)\n\n        if tmpdir:\n            shutil.move(tmpfname, infile)\n    finally:\n        if tmpdir:\n            shutil.rmtree(tmpdir)\n\n\ndef yui_compressor(infile):\n    yuicompressor = False\n    try:\n        subprocess.call('yui-compressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))\n        yuicompressor = 'yui-compressor'\n    except Exception:\n        pass\n    if not yuicompressor:\n        try:\n            subprocess.call('yuicompressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))\n            yuicompressor = 'yuicompressor'\n        except:\n            raise Exception(\"yui-compressor is not installed.\")\n            return False\n\n    return runinplace(r'{} --nomunge %1 -o %2'.format(yuicompressor), infile)\n\n\ndef optipng(infile):\n    return runinplace(r\"optipng -preserve -o2 -quiet %1\", infile)\n\n\ndef jpegoptim(infile):\n    return runinplace(r\"jpegoptim -p --strip-all -q %1\", infile)\n\n\ndef tidy(inplace):\n    # Google site verifcation files are not HTML\n    if re.match(r\"google[a-f0-9]+.html\", os.path.basename(inplace)) \\\n            and open(inplace).readline().startswith(\n                \"google-site-verification:\"):\n        return\n\n    # Tidy will give error exits, that we will ignore.\n    output = subprocess.check_output(\n        \"tidy -m -w 90 --indent no --quote-marks\"\n        \"no --keep-time yes --tidy-mark no \"\n        \"--force-output yes '{0}'; exit 0\".format(inplace), stderr=subprocess.STDOUT, shell=True)\n\n    for line in output.split(\"\\n\"):\n        if \"Warning:\" in line:\n            if '<meta> proprietary attribute \"charset\"' in line:\n                # We want to set it though.\n                continue\n            elif '<meta> lacks \"content\" attribute' in line:\n                # False alarm to me.\n                continue\n            elif '<div> anchor' in line and 'already defined' in line:\n                # Some seeming problem with JavaScript terminators.\n                continue\n            elif '<img> lacks \"alt\" attribute' in line:\n                # Happens in gallery code, probably can be tolerated.\n                continue\n            elif '<table> lacks \"summary\" attribute' in line:\n                # Happens for tables, TODO: Check this is normal.\n                continue\n            elif 'proprietary attribute \"data-toggle\"' in line or \\\n                 'proprietary attribute \"data-target\"':\n                # Some of our own tricks\n                continue\n            else:\n                assert False, (inplace, line)\n        elif \"Error:\" in line:\n            if '<time> is not recognized' in line:\n                # False alarm, time is proper HTML5.\n                continue\n            else:\n                assert False, line\n\n\n@apply_to_text_file\ndef typogrify(data):\n    if typo is None:\n        req_missing(['typogrify'], 'use the typogrify filter')\n\n    data = typo.amp(data)\n    data = typo.widont(data)\n    data = typo.smartypants(data)\n    # Disabled because of typogrify bug where it breaks <title>\n    # data = typo.caps(data)\n    data = typo.initial_quotes(data)\n    return data\n", "path": "nikola/filters.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2014 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Utility functions to help you run filters on files.\"\"\"\n\nfrom .utils import req_missing\nfrom functools import wraps\nimport os\nimport codecs\nimport shutil\nimport subprocess\nimport tempfile\nimport shlex\n\ntry:\n    import typogrify.filters as typo\nexcept ImportError:\n    typo = None  # NOQA\n\n\ndef apply_to_binary_file(f):\n    \"\"\"Take a function f that transforms a data argument, and returns\n    a function that takes a filename and applies f to the contents,\n    in place.  Reads files in binary mode.\"\"\"\n    @wraps(f)\n    def f_in_file(fname):\n        with open(fname, 'rb') as inf:\n            data = inf.read()\n        data = f(data)\n        with open(fname, 'wb+') as outf:\n            outf.write(data)\n\n    return f_in_file\n\n\ndef apply_to_text_file(f):\n    \"\"\"Take a function f that transforms a data argument, and returns\n    a function that takes a filename and applies f to the contents,\n    in place.  Reads files in UTF-8.\"\"\"\n    @wraps(f)\n    def f_in_file(fname):\n        with codecs.open(fname, 'r', 'utf-8') as inf:\n            data = inf.read()\n        data = f(data)\n        with codecs.open(fname, 'w+', 'utf-8') as outf:\n            outf.write(data)\n\n    return f_in_file\n\n\ndef list_replace(the_list, find, replacement):\n    \"Replace all occurrences of ``find`` with ``replacement`` in ``the_list``\"\n    for i, v in enumerate(the_list):\n        if v == find:\n            the_list[i] = replacement\n\n\ndef runinplace(command, infile):\n    \"\"\"Run a command in-place on a file.\n\n    command is a string of the form: \"commandname %1 %2\" and\n    it will be execed with infile as %1 and a temporary file\n    as %2. Then, that temporary file will be moved over %1.\n\n    Example usage:\n\n    runinplace(\"yui-compressor %1 -o %2\", \"myfile.css\")\n\n    That will replace myfile.css with a minified version.\n\n    You can also supply command as a list.\n    \"\"\"\n\n    if not isinstance(command, list):\n        command = shlex.split(command)\n\n    tmpdir = None\n\n    if \"%2\" in command:\n        tmpdir = tempfile.mkdtemp(prefix=\"nikola\")\n        tmpfname = os.path.join(tmpdir, os.path.basename(infile))\n\n    try:\n        list_replace(command, \"%1\", infile)\n        if tmpdir:\n            list_replace(command, \"%2\", tmpfname)\n\n        subprocess.check_call(command)\n\n        if tmpdir:\n            shutil.move(tmpfname, infile)\n    finally:\n        if tmpdir:\n            shutil.rmtree(tmpdir)\n\n\ndef yui_compressor(infile):\n    yuicompressor = False\n    try:\n        subprocess.call('yui-compressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))\n        yuicompressor = 'yui-compressor'\n    except Exception:\n        pass\n    if not yuicompressor:\n        try:\n            subprocess.call('yuicompressor', stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))\n            yuicompressor = 'yuicompressor'\n        except:\n            raise Exception(\"yui-compressor is not installed.\")\n            return False\n\n    return runinplace(r'{} --nomunge %1 -o %2'.format(yuicompressor), infile)\n\n\ndef optipng(infile):\n    return runinplace(r\"optipng -preserve -o2 -quiet %1\", infile)\n\n\ndef jpegoptim(infile):\n    return runinplace(r\"jpegoptim -p --strip-all -q %1\", infile)\n\n\n@apply_to_text_file\ndef typogrify(data):\n    if typo is None:\n        req_missing(['typogrify'], 'use the typogrify filter')\n\n    data = typo.amp(data)\n    data = typo.widont(data)\n    data = typo.smartypants(data)\n    # Disabled because of typogrify bug where it breaks <title>\n    # data = typo.caps(data)\n    data = typo.initial_quotes(data)\n    return data\n", "path": "nikola/filters.py"}]}