We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Empty completion.timestamp_format crashes
After `:set completion.timestamp_format ''`:

```
17:26:29 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/completer.py", line 260, in _update_completion
    completion.set_pattern(pattern)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/completionwidget.py", line 320, in set_pattern
    self.model().set_pattern(pattern)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/completionmodel.py", line 185, in set_pattern
    cat.set_pattern(pattern)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/histcategory.py", line 85, in set_pattern
    .format(timestamp_format.replace("'", "`")))
AttributeError: 'NoneType' object has no attribute 'replace'
```

cc @rcorre and @erikdsjostrom who reported this

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qutebrowser/completion/models/histcategory.py`
Content:
```
1 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2 
3 # Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
4 #
5 # This file is part of qutebrowser.
6 #
7 # qutebrowser is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # qutebrowser is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
19 
20 """A completion category that queries the SQL History store."""
21 
22 from PyQt5.QtSql import QSqlQueryModel
23 
24 from qutebrowser.misc import sql
25 from qutebrowser.utils import debug
26 from qutebrowser.config import config
27 
28 
29 class HistoryCategory(QSqlQueryModel):
30 
31     """A completion category that queries the SQL History store."""
32 
33     def __init__(self, *, delete_func=None, parent=None):
34         """Create a new History completion category."""
35         super().__init__(parent=parent)
36         self.name = "History"
37         self._query = None
38 
39         # advertise that this model filters by URL and title
40         self.columns_to_filter = [0, 1]
41         self.delete_func = delete_func
42 
43     def _atime_expr(self):
44         """If max_items is set, return an expression to limit the query."""
45         max_items = config.val.completion.web_history_max_items
46         # HistoryCategory should not be added to the completion in that case.
47         assert max_items != 0
48 
49         if max_items < 0:
50             return ''
51 
52         min_atime = sql.Query(' '.join([
53             'SELECT min(last_atime) FROM',
54             '(SELECT last_atime FROM CompletionHistory',
55             'ORDER BY last_atime DESC LIMIT :limit)',
56         ])).run(limit=max_items).value()
57 
58         if not min_atime:
59             # if there are no history items, min_atime may be '' (issue #2849)
60             return ''
61 
62         return "AND last_atime >= {}".format(min_atime)
63 
64     def set_pattern(self, pattern):
65         """Set the pattern used to filter results.
66 
67         Args:
68             pattern: string pattern to filter by.
69         """
70         # escape to treat a user input % or _ as a literal, not a wildcard
71         pattern = pattern.replace('%', '\\%')
72         pattern = pattern.replace('_', '\\_')
73         words = ['%{}%'.format(w) for w in pattern.split(' ')]
74 
75         # build a where clause to match all of the words in any order
76         # given the search term "a b", the WHERE clause would be:
77         # ((url || title) LIKE '%a%') AND ((url || title) LIKE '%b%')
78         where_clause = ' AND '.join(
79             "(url || title) LIKE :{} escape '\\'".format(i)
80             for i in range(len(words)))
81 
82         # replace ' in timestamp-format to avoid breaking the query
83         timestamp_format = config.val.completion.timestamp_format
84         timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
85                    .format(timestamp_format.replace("'", "`")))
86 
87         if not self._query or len(words) != len(self._query.boundValues()):
88             # if the number of words changed, we need to generate a new query
89             # otherwise, we can reuse the prepared query for performance
90             self._query = sql.Query(' '.join([
91                 "SELECT url, title, {}".format(timefmt),
92                 "FROM CompletionHistory",
93                 # the incoming pattern will have literal % and _ escaped
94                 # we need to tell sql to treat '\' as an escape character
95                 'WHERE ({})'.format(where_clause),
96                 self._atime_expr(),
97                 "ORDER BY last_atime DESC",
98             ]), forward_only=False)
99 
100         with debug.log_time('sql', 'Running completion query'):
101             self._query.run(**{
102                 str(i): w for i, w in enumerate(words)})
103         self.setQuery(self._query)
104 
105     def removeRows(self, row, _count, _parent=None):
106         """Override QAbstractItemModel::removeRows to re-run sql query."""
107         # re-run query to reload updated table
108         with debug.log_time('sql', 'Re-running completion query post-delete'):
109             self._query.run()
110         self.setQuery(self._query)
111         while self.rowCount() < row:
112             self.fetchMore()
113         return True
114
```
--- 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/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py
--- a/qutebrowser/completion/models/histcategory.py
+++ b/qutebrowser/completion/models/histcategory.py
@@ -80,7 +80,7 @@
             for i in range(len(words)))
 
         # replace ' in timestamp-format to avoid breaking the query
-        timestamp_format = config.val.completion.timestamp_format
+        timestamp_format = config.val.completion.timestamp_format or ''
         timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
                    .format(timestamp_format.replace("'", "`")))

{"golden_diff": "diff --git a/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py\n--- a/qutebrowser/completion/models/histcategory.py\n+++ b/qutebrowser/completion/models/histcategory.py\n@@ -80,7 +80,7 @@\n             for i in range(len(words)))\n \n         # replace ' in timestamp-format to avoid breaking the query\n-        timestamp_format = config.val.completion.timestamp_format\n+        timestamp_format = config.val.completion.timestamp_format or ''\n         timefmt = (\"strftime('{}', last_atime, 'unixepoch', 'localtime')\"\n                    .format(timestamp_format.replace(\"'\", \"`\")))\n", "issue": "Empty completion.timestamp_format crashes\nAfter `:set completion.timestamp_format ''`:\r\n\r\n```\r\n17:26:29 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception\r\nTraceback (most recent call last):\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/completer.py\", line 260, in _update_completion\r\n    completion.set_pattern(pattern)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/completionwidget.py\", line 320, in set_pattern\r\n    self.model().set_pattern(pattern)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/completionmodel.py\", line 185, in set_pattern\r\n    cat.set_pattern(pattern)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/completion/models/histcategory.py\", line 85, in set_pattern\r\n    .format(timestamp_format.replace(\"'\", \"`\")))\r\nAttributeError: 'NoneType' object has no attribute 'replace'\r\n```\r\n\r\ncc @rcorre and @erikdsjostrom who reported this\n", "before_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"A completion category that queries the SQL History store.\"\"\"\n\nfrom PyQt5.QtSql import QSqlQueryModel\n\nfrom qutebrowser.misc import sql\nfrom qutebrowser.utils import debug\nfrom qutebrowser.config import config\n\n\nclass HistoryCategory(QSqlQueryModel):\n\n    \"\"\"A completion category that queries the SQL History store.\"\"\"\n\n    def __init__(self, *, delete_func=None, parent=None):\n        \"\"\"Create a new History completion category.\"\"\"\n        super().__init__(parent=parent)\n        self.name = \"History\"\n        self._query = None\n\n        # advertise that this model filters by URL and title\n        self.columns_to_filter = [0, 1]\n        self.delete_func = delete_func\n\n    def _atime_expr(self):\n        \"\"\"If max_items is set, return an expression to limit the query.\"\"\"\n        max_items = config.val.completion.web_history_max_items\n        # HistoryCategory should not be added to the completion in that case.\n        assert max_items != 0\n\n        if max_items < 0:\n            return ''\n\n        min_atime = sql.Query(' '.join([\n            'SELECT min(last_atime) FROM',\n            '(SELECT last_atime FROM CompletionHistory',\n            'ORDER BY last_atime DESC LIMIT :limit)',\n        ])).run(limit=max_items).value()\n\n        if not min_atime:\n            # if there are no history items, min_atime may be '' (issue #2849)\n            return ''\n\n        return \"AND last_atime >= {}\".format(min_atime)\n\n    def set_pattern(self, pattern):\n        \"\"\"Set the pattern used to filter results.\n\n        Args:\n            pattern: string pattern to filter by.\n        \"\"\"\n        # escape to treat a user input % or _ as a literal, not a wildcard\n        pattern = pattern.replace('%', '\\\\%')\n        pattern = pattern.replace('_', '\\\\_')\n        words = ['%{}%'.format(w) for w in pattern.split(' ')]\n\n        # build a where clause to match all of the words in any order\n        # given the search term \"a b\", the WHERE clause would be:\n        # ((url || title) LIKE '%a%') AND ((url || title) LIKE '%b%')\n        where_clause = ' AND '.join(\n            \"(url || title) LIKE :{} escape '\\\\'\".format(i)\n            for i in range(len(words)))\n\n        # replace ' in timestamp-format to avoid breaking the query\n        timestamp_format = config.val.completion.timestamp_format\n        timefmt = (\"strftime('{}', last_atime, 'unixepoch', 'localtime')\"\n                   .format(timestamp_format.replace(\"'\", \"`\")))\n\n        if not self._query or len(words) != len(self._query.boundValues()):\n            # if the number of words changed, we need to generate a new query\n            # otherwise, we can reuse the prepared query for performance\n            self._query = sql.Query(' '.join([\n                \"SELECT url, title, {}\".format(timefmt),\n                \"FROM CompletionHistory\",\n                # the incoming pattern will have literal % and _ escaped\n                # we need to tell sql to treat '\\' as an escape character\n                'WHERE ({})'.format(where_clause),\n                self._atime_expr(),\n                \"ORDER BY last_atime DESC\",\n            ]), forward_only=False)\n\n        with debug.log_time('sql', 'Running completion query'):\n            self._query.run(**{\n                str(i): w for i, w in enumerate(words)})\n        self.setQuery(self._query)\n\n    def removeRows(self, row, _count, _parent=None):\n        \"\"\"Override QAbstractItemModel::removeRows to re-run sql query.\"\"\"\n        # re-run query to reload updated table\n        with debug.log_time('sql', 'Re-running completion query post-delete'):\n            self._query.run()\n        self.setQuery(self._query)\n        while self.rowCount() < row:\n            self.fetchMore()\n        return True\n", "path": "qutebrowser/completion/models/histcategory.py"}], "after_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"A completion category that queries the SQL History store.\"\"\"\n\nfrom PyQt5.QtSql import QSqlQueryModel\n\nfrom qutebrowser.misc import sql\nfrom qutebrowser.utils import debug\nfrom qutebrowser.config import config\n\n\nclass HistoryCategory(QSqlQueryModel):\n\n    \"\"\"A completion category that queries the SQL History store.\"\"\"\n\n    def __init__(self, *, delete_func=None, parent=None):\n        \"\"\"Create a new History completion category.\"\"\"\n        super().__init__(parent=parent)\n        self.name = \"History\"\n        self._query = None\n\n        # advertise that this model filters by URL and title\n        self.columns_to_filter = [0, 1]\n        self.delete_func = delete_func\n\n    def _atime_expr(self):\n        \"\"\"If max_items is set, return an expression to limit the query.\"\"\"\n        max_items = config.val.completion.web_history_max_items\n        # HistoryCategory should not be added to the completion in that case.\n        assert max_items != 0\n\n        if max_items < 0:\n            return ''\n\n        min_atime = sql.Query(' '.join([\n            'SELECT min(last_atime) FROM',\n            '(SELECT last_atime FROM CompletionHistory',\n            'ORDER BY last_atime DESC LIMIT :limit)',\n        ])).run(limit=max_items).value()\n\n        if not min_atime:\n            # if there are no history items, min_atime may be '' (issue #2849)\n            return ''\n\n        return \"AND last_atime >= {}\".format(min_atime)\n\n    def set_pattern(self, pattern):\n        \"\"\"Set the pattern used to filter results.\n\n        Args:\n            pattern: string pattern to filter by.\n        \"\"\"\n        # escape to treat a user input % or _ as a literal, not a wildcard\n        pattern = pattern.replace('%', '\\\\%')\n        pattern = pattern.replace('_', '\\\\_')\n        words = ['%{}%'.format(w) for w in pattern.split(' ')]\n\n        # build a where clause to match all of the words in any order\n        # given the search term \"a b\", the WHERE clause would be:\n        # ((url || title) LIKE '%a%') AND ((url || title) LIKE '%b%')\n        where_clause = ' AND '.join(\n            \"(url || title) LIKE :{} escape '\\\\'\".format(i)\n            for i in range(len(words)))\n\n        # replace ' in timestamp-format to avoid breaking the query\n        timestamp_format = config.val.completion.timestamp_format or ''\n        timefmt = (\"strftime('{}', last_atime, 'unixepoch', 'localtime')\"\n                   .format(timestamp_format.replace(\"'\", \"`\")))\n\n        if not self._query or len(words) != len(self._query.boundValues()):\n            # if the number of words changed, we need to generate a new query\n            # otherwise, we can reuse the prepared query for performance\n            self._query = sql.Query(' '.join([\n                \"SELECT url, title, {}\".format(timefmt),\n                \"FROM CompletionHistory\",\n                # the incoming pattern will have literal % and _ escaped\n                # we need to tell sql to treat '\\' as an escape character\n                'WHERE ({})'.format(where_clause),\n                self._atime_expr(),\n                \"ORDER BY last_atime DESC\",\n            ]), forward_only=False)\n\n        with debug.log_time('sql', 'Running completion query'):\n            self._query.run(**{\n                str(i): w for i, w in enumerate(words)})\n        self.setQuery(self._query)\n\n    def removeRows(self, row, _count, _parent=None):\n        \"\"\"Override QAbstractItemModel::removeRows to re-run sql query.\"\"\"\n        # re-run query to reload updated table\n        with debug.log_time('sql', 'Re-running completion query post-delete'):\n            self._query.run()\n        self.setQuery(self._query)\n        while self.rowCount() < row:\n            self.fetchMore()\n        return True\n", "path": "qutebrowser/completion/models/histcategory.py"}]}