We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ValueError: data must be bytes, but is str
Hi , 
    When i use 'e' to edit form , sometimes  i get this .

```
➜  ~ mitmproxy -b 192.168.1.2 -p 8080
Traceback (most recent call last):
  File "mitmproxy/tools/console/master.py", line 292, in run
  File "site-packages/urwid/main_loop.py", line 278, in run
  File "site-packages/urwid/main_loop.py", line 376, in _run
  File "site-packages/urwid/main_loop.py", line 682, in run
  File "site-packages/urwid/main_loop.py", line 719, in _loop
  File "site-packages/urwid/raw_display.py", line 393, in <lambda>
  File "site-packages/urwid/raw_display.py", line 493, in parse_input
  File "site-packages/urwid/main_loop.py", line 403, in _update
  File "site-packages/urwid/main_loop.py", line 503, in process_input
  File "mitmproxy/tools/console/window.py", line 84, in keypress
  File "site-packages/urwid/container.py", line 1116, in keypress
  File "mitmproxy/tools/console/statusbar.py", line 155, in keypress
  File "mitmproxy/tools/console/statusbar.py", line 108, in keypress
  File "mitmproxy/tools/console/statusbar.py", line 133, in prompt_execute
  File "mitmproxy/tools/console/statusbar.py", line 31, in __call__
  File "mitmproxy/tools/console/flowview.py", line 415, in edit
  File "mitmproxy/tools/console/flowview.py", line 351, in edit_form
  File "mitmproxy/tools/console/master.py", line 352, in view_grideditor
  File "site-packages/blinker/base.py", line 267, in send
  File "site-packages/blinker/base.py", line 267, in <listcomp>
  File "mitmproxy/tools/console/master.py", line 144, in sig_push_view_state
  File "site-packages/urwid/main_loop.py", line 578, in draw_screen
  File "site-packages/urwid/widget.py", line 141, in cached_render
  File "site-packages/urwid/container.py", line 1083, in render
  File "site-packages/urwid/widget.py", line 141, in cached_render
  File "site-packages/urwid/decoration.py", line 225, in render
  File "site-packages/urwid/widget.py", line 141, in cached_render
  File "site-packages/urwid/widget.py", line 1750, in render
  File "site-packages/urwid/widget.py", line 141, in cached_render
  File "site-packages/urwid/container.py", line 1083, in render
  File "site-packages/urwid/widget.py", line 141, in cached_render
  File "site-packages/urwid/listbox.py", line 455, in render
  File "site-packages/urwid/listbox.py", line 337, in calculate_visible
  File "site-packages/urwid/listbox.py", line 702, in _set_focus_complete
  File "site-packages/urwid/listbox.py", line 672, in _set_focus_first_selectable
  File "site-packages/urwid/listbox.py", line 340, in calculate_visible
  File "mitmproxy/tools/console/grideditor/base.py", line 223, in get_focus
  File "mitmproxy/tools/console/grideditor/base.py", line 77, in __init__
  File "mitmproxy/tools/console/grideditor/col_bytes.py", line 33, in Display
  File "mitmproxy/tools/console/grideditor/col_bytes.py", line 73, in __init__
  File "mitmproxy/utils/strutils.py", line 72, in bytes_to_escaped_str
ValueError: data must be bytes, but is str

mitmproxy has crashed!
Please lodge a bug report at:
	https://github.com/mitmproxy/mitmproxy
Shutting down...

```
systeminfo:
Mitmproxy version: 1.0.0
Python version: 3.5.2
Platform: Darwin-15.6.0-x86_64-i386-64bit
SSL version: OpenSSL 1.0.2j  26 Sep 2016
Mac version: 10.11.6 ('', '', '') x86_64


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mitmproxy/tools/console/grideditor/editors.py`
Content:
```
1 import re
2 import urwid
3 from mitmproxy import exceptions
4 from mitmproxy import flowfilter
5 from mitmproxy.addons import script
6 from mitmproxy.tools.console import common
7 from mitmproxy.tools.console.grideditor import base
8 from mitmproxy.tools.console.grideditor import col_text
9 from mitmproxy.tools.console.grideditor import col_bytes
10 from mitmproxy.tools.console.grideditor import col_subgrid
11 from mitmproxy.tools.console import signals
12 from mitmproxy.net.http import user_agents
13 
14 
15 class QueryEditor(base.GridEditor):
16     title = "Editing query"
17     columns = [
18         col_text.Column("Key"),
19         col_text.Column("Value")
20     ]
21 
22 
23 class HeaderEditor(base.GridEditor):
24     title = "Editing headers"
25     columns = [
26         col_bytes.Column("Key"),
27         col_bytes.Column("Value")
28     ]
29 
30     def make_help(self):
31         h = super().make_help()
32         text = [
33             urwid.Text([("text", "Special keys:\n")])
34         ]
35         keys = [
36             ("U", "add User-Agent header"),
37         ]
38         text.extend(
39             common.format_keyvals(keys, key="key", val="text", indent=4)
40         )
41         text.append(urwid.Text([("text", "\n")]))
42         text.extend(h)
43         return text
44 
45     def set_user_agent(self, k):
46         ua = user_agents.get_by_shortcut(k)
47         if ua:
48             self.walker.add_value(
49                 [
50                     b"User-Agent",
51                     ua[2].encode()
52                 ]
53             )
54 
55     def handle_key(self, key):
56         if key == "U":
57             signals.status_prompt_onekey.send(
58                 prompt="Add User-Agent header:",
59                 keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],
60                 callback=self.set_user_agent,
61             )
62             return True
63 
64 
65 class URLEncodedFormEditor(base.GridEditor):
66     title = "Editing URL-encoded form"
67     columns = [
68         col_bytes.Column("Key"),
69         col_bytes.Column("Value")
70     ]
71 
72 
73 class ReplaceEditor(base.GridEditor):
74     title = "Editing replacement patterns"
75     columns = [
76         col_text.Column("Filter"),
77         col_text.Column("Regex"),
78         col_text.Column("Replacement"),
79     ]
80 
81     def is_error(self, col, val):
82         if col == 0:
83             if not flowfilter.parse(val):
84                 return "Invalid filter specification."
85         elif col == 1:
86             try:
87                 re.compile(val)
88             except re.error:
89                 return "Invalid regular expression."
90         return False
91 
92 
93 class SetHeadersEditor(base.GridEditor):
94     title = "Editing header set patterns"
95     columns = [
96         col_text.Column("Filter"),
97         col_text.Column("Header"),
98         col_text.Column("Value"),
99     ]
100 
101     def is_error(self, col, val):
102         if col == 0:
103             if not flowfilter.parse(val):
104                 return "Invalid filter specification"
105         return False
106 
107     def make_help(self):
108         h = super().make_help()
109         text = [
110             urwid.Text([("text", "Special keys:\n")])
111         ]
112         keys = [
113             ("U", "add User-Agent header"),
114         ]
115         text.extend(
116             common.format_keyvals(keys, key="key", val="text", indent=4)
117         )
118         text.append(urwid.Text([("text", "\n")]))
119         text.extend(h)
120         return text
121 
122     def set_user_agent(self, k):
123         ua = user_agents.get_by_shortcut(k)
124         if ua:
125             self.walker.add_value(
126                 [
127                     ".*",
128                     b"User-Agent",
129                     ua[2].encode()
130                 ]
131             )
132 
133     def handle_key(self, key):
134         if key == "U":
135             signals.status_prompt_onekey.send(
136                 prompt="Add User-Agent header:",
137                 keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],
138                 callback=self.set_user_agent,
139             )
140             return True
141 
142 
143 class PathEditor(base.GridEditor):
144     # TODO: Next row on enter?
145 
146     title = "Editing URL path components"
147     columns = [
148         col_text.Column("Component"),
149     ]
150 
151     def data_in(self, data):
152         return [[i] for i in data]
153 
154     def data_out(self, data):
155         return [i[0] for i in data]
156 
157 
158 class ScriptEditor(base.GridEditor):
159     title = "Editing scripts"
160     columns = [
161         col_text.Column("Command"),
162     ]
163 
164     def is_error(self, col, val):
165         try:
166             script.parse_command(val)
167         except exceptions.OptionsError as e:
168             return str(e)
169 
170 
171 class HostPatternEditor(base.GridEditor):
172     title = "Editing host patterns"
173     columns = [
174         col_text.Column("Regex (matched on hostname:port / ip:port)")
175     ]
176 
177     def is_error(self, col, val):
178         try:
179             re.compile(val, re.IGNORECASE)
180         except re.error as e:
181             return "Invalid regex: %s" % str(e)
182 
183     def data_in(self, data):
184         return [[i] for i in data]
185 
186     def data_out(self, data):
187         return [i[0] for i in data]
188 
189 
190 class CookieEditor(base.GridEditor):
191     title = "Editing request Cookie header"
192     columns = [
193         col_text.Column("Name"),
194         col_text.Column("Value"),
195     ]
196 
197 
198 class CookieAttributeEditor(base.GridEditor):
199     title = "Editing Set-Cookie attributes"
200     columns = [
201         col_text.Column("Name"),
202         col_text.Column("Value"),
203     ]
204 
205     def data_in(self, data):
206         return [(k, v or "") for k, v in data]
207 
208     def data_out(self, data):
209         ret = []
210         for i in data:
211             if not i[1]:
212                 ret.append([i[0], None])
213             else:
214                 ret.append(i)
215         return ret
216 
217 
218 class SetCookieEditor(base.GridEditor):
219     title = "Editing response SetCookie header"
220     columns = [
221         col_text.Column("Name"),
222         col_text.Column("Value"),
223         col_subgrid.Column("Attributes", CookieAttributeEditor),
224     ]
225 
226     def data_in(self, data):
227         flattened = []
228         for key, (value, attrs) in data:
229             flattened.append([key, value, attrs.items(multi=True)])
230         return flattened
231 
232     def data_out(self, data):
233         vals = []
234         for key, value, attrs in data:
235             vals.append(
236                 [
237                     key,
238                     (value, attrs)
239                 ]
240             )
241         return vals
242
```
--- 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/mitmproxy/tools/console/grideditor/editors.py b/mitmproxy/tools/console/grideditor/editors.py
--- a/mitmproxy/tools/console/grideditor/editors.py
+++ b/mitmproxy/tools/console/grideditor/editors.py
@@ -65,8 +65,8 @@
 class URLEncodedFormEditor(base.GridEditor):
     title = "Editing URL-encoded form"
     columns = [
-        col_bytes.Column("Key"),
-        col_bytes.Column("Value")
+        col_text.Column("Key"),
+        col_text.Column("Value")
     ]

{"golden_diff": "diff --git a/mitmproxy/tools/console/grideditor/editors.py b/mitmproxy/tools/console/grideditor/editors.py\n--- a/mitmproxy/tools/console/grideditor/editors.py\n+++ b/mitmproxy/tools/console/grideditor/editors.py\n@@ -65,8 +65,8 @@\n class URLEncodedFormEditor(base.GridEditor):\n     title = \"Editing URL-encoded form\"\n     columns = [\n-        col_bytes.Column(\"Key\"),\n-        col_bytes.Column(\"Value\")\n+        col_text.Column(\"Key\"),\n+        col_text.Column(\"Value\")\n     ]\n", "issue": "ValueError: data must be bytes, but is str\nHi , \r\n    When i use 'e' to edit form , sometimes  i get this .\r\n\r\n```\r\n\u279c  ~ mitmproxy -b 192.168.1.2 -p 8080\r\nTraceback (most recent call last):\r\n  File \"mitmproxy/tools/console/master.py\", line 292, in run\r\n  File \"site-packages/urwid/main_loop.py\", line 278, in run\r\n  File \"site-packages/urwid/main_loop.py\", line 376, in _run\r\n  File \"site-packages/urwid/main_loop.py\", line 682, in run\r\n  File \"site-packages/urwid/main_loop.py\", line 719, in _loop\r\n  File \"site-packages/urwid/raw_display.py\", line 393, in <lambda>\r\n  File \"site-packages/urwid/raw_display.py\", line 493, in parse_input\r\n  File \"site-packages/urwid/main_loop.py\", line 403, in _update\r\n  File \"site-packages/urwid/main_loop.py\", line 503, in process_input\r\n  File \"mitmproxy/tools/console/window.py\", line 84, in keypress\r\n  File \"site-packages/urwid/container.py\", line 1116, in keypress\r\n  File \"mitmproxy/tools/console/statusbar.py\", line 155, in keypress\r\n  File \"mitmproxy/tools/console/statusbar.py\", line 108, in keypress\r\n  File \"mitmproxy/tools/console/statusbar.py\", line 133, in prompt_execute\r\n  File \"mitmproxy/tools/console/statusbar.py\", line 31, in __call__\r\n  File \"mitmproxy/tools/console/flowview.py\", line 415, in edit\r\n  File \"mitmproxy/tools/console/flowview.py\", line 351, in edit_form\r\n  File \"mitmproxy/tools/console/master.py\", line 352, in view_grideditor\r\n  File \"site-packages/blinker/base.py\", line 267, in send\r\n  File \"site-packages/blinker/base.py\", line 267, in <listcomp>\r\n  File \"mitmproxy/tools/console/master.py\", line 144, in sig_push_view_state\r\n  File \"site-packages/urwid/main_loop.py\", line 578, in draw_screen\r\n  File \"site-packages/urwid/widget.py\", line 141, in cached_render\r\n  File \"site-packages/urwid/container.py\", line 1083, in render\r\n  File \"site-packages/urwid/widget.py\", line 141, in cached_render\r\n  File \"site-packages/urwid/decoration.py\", line 225, in render\r\n  File \"site-packages/urwid/widget.py\", line 141, in cached_render\r\n  File \"site-packages/urwid/widget.py\", line 1750, in render\r\n  File \"site-packages/urwid/widget.py\", line 141, in cached_render\r\n  File \"site-packages/urwid/container.py\", line 1083, in render\r\n  File \"site-packages/urwid/widget.py\", line 141, in cached_render\r\n  File \"site-packages/urwid/listbox.py\", line 455, in render\r\n  File \"site-packages/urwid/listbox.py\", line 337, in calculate_visible\r\n  File \"site-packages/urwid/listbox.py\", line 702, in _set_focus_complete\r\n  File \"site-packages/urwid/listbox.py\", line 672, in _set_focus_first_selectable\r\n  File \"site-packages/urwid/listbox.py\", line 340, in calculate_visible\r\n  File \"mitmproxy/tools/console/grideditor/base.py\", line 223, in get_focus\r\n  File \"mitmproxy/tools/console/grideditor/base.py\", line 77, in __init__\r\n  File \"mitmproxy/tools/console/grideditor/col_bytes.py\", line 33, in Display\r\n  File \"mitmproxy/tools/console/grideditor/col_bytes.py\", line 73, in __init__\r\n  File \"mitmproxy/utils/strutils.py\", line 72, in bytes_to_escaped_str\r\nValueError: data must be bytes, but is str\r\n\r\nmitmproxy has crashed!\r\nPlease lodge a bug report at:\r\n\thttps://github.com/mitmproxy/mitmproxy\r\nShutting down...\r\n\r\n```\r\nsysteminfo:\r\nMitmproxy version: 1.0.0\r\nPython version: 3.5.2\r\nPlatform: Darwin-15.6.0-x86_64-i386-64bit\r\nSSL version: OpenSSL 1.0.2j  26 Sep 2016\r\nMac version: 10.11.6 ('', '', '') x86_64\r\n\n", "before_files": [{"content": "import re\nimport urwid\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy.addons import script\nfrom mitmproxy.tools.console import common\nfrom mitmproxy.tools.console.grideditor import base\nfrom mitmproxy.tools.console.grideditor import col_text\nfrom mitmproxy.tools.console.grideditor import col_bytes\nfrom mitmproxy.tools.console.grideditor import col_subgrid\nfrom mitmproxy.tools.console import signals\nfrom mitmproxy.net.http import user_agents\n\n\nclass QueryEditor(base.GridEditor):\n    title = \"Editing query\"\n    columns = [\n        col_text.Column(\"Key\"),\n        col_text.Column(\"Value\")\n    ]\n\n\nclass HeaderEditor(base.GridEditor):\n    title = \"Editing headers\"\n    columns = [\n        col_bytes.Column(\"Key\"),\n        col_bytes.Column(\"Value\")\n    ]\n\n    def make_help(self):\n        h = super().make_help()\n        text = [\n            urwid.Text([(\"text\", \"Special keys:\\n\")])\n        ]\n        keys = [\n            (\"U\", \"add User-Agent header\"),\n        ]\n        text.extend(\n            common.format_keyvals(keys, key=\"key\", val=\"text\", indent=4)\n        )\n        text.append(urwid.Text([(\"text\", \"\\n\")]))\n        text.extend(h)\n        return text\n\n    def set_user_agent(self, k):\n        ua = user_agents.get_by_shortcut(k)\n        if ua:\n            self.walker.add_value(\n                [\n                    b\"User-Agent\",\n                    ua[2].encode()\n                ]\n            )\n\n    def handle_key(self, key):\n        if key == \"U\":\n            signals.status_prompt_onekey.send(\n                prompt=\"Add User-Agent header:\",\n                keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],\n                callback=self.set_user_agent,\n            )\n            return True\n\n\nclass URLEncodedFormEditor(base.GridEditor):\n    title = \"Editing URL-encoded form\"\n    columns = [\n        col_bytes.Column(\"Key\"),\n        col_bytes.Column(\"Value\")\n    ]\n\n\nclass ReplaceEditor(base.GridEditor):\n    title = \"Editing replacement patterns\"\n    columns = [\n        col_text.Column(\"Filter\"),\n        col_text.Column(\"Regex\"),\n        col_text.Column(\"Replacement\"),\n    ]\n\n    def is_error(self, col, val):\n        if col == 0:\n            if not flowfilter.parse(val):\n                return \"Invalid filter specification.\"\n        elif col == 1:\n            try:\n                re.compile(val)\n            except re.error:\n                return \"Invalid regular expression.\"\n        return False\n\n\nclass SetHeadersEditor(base.GridEditor):\n    title = \"Editing header set patterns\"\n    columns = [\n        col_text.Column(\"Filter\"),\n        col_text.Column(\"Header\"),\n        col_text.Column(\"Value\"),\n    ]\n\n    def is_error(self, col, val):\n        if col == 0:\n            if not flowfilter.parse(val):\n                return \"Invalid filter specification\"\n        return False\n\n    def make_help(self):\n        h = super().make_help()\n        text = [\n            urwid.Text([(\"text\", \"Special keys:\\n\")])\n        ]\n        keys = [\n            (\"U\", \"add User-Agent header\"),\n        ]\n        text.extend(\n            common.format_keyvals(keys, key=\"key\", val=\"text\", indent=4)\n        )\n        text.append(urwid.Text([(\"text\", \"\\n\")]))\n        text.extend(h)\n        return text\n\n    def set_user_agent(self, k):\n        ua = user_agents.get_by_shortcut(k)\n        if ua:\n            self.walker.add_value(\n                [\n                    \".*\",\n                    b\"User-Agent\",\n                    ua[2].encode()\n                ]\n            )\n\n    def handle_key(self, key):\n        if key == \"U\":\n            signals.status_prompt_onekey.send(\n                prompt=\"Add User-Agent header:\",\n                keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],\n                callback=self.set_user_agent,\n            )\n            return True\n\n\nclass PathEditor(base.GridEditor):\n    # TODO: Next row on enter?\n\n    title = \"Editing URL path components\"\n    columns = [\n        col_text.Column(\"Component\"),\n    ]\n\n    def data_in(self, data):\n        return [[i] for i in data]\n\n    def data_out(self, data):\n        return [i[0] for i in data]\n\n\nclass ScriptEditor(base.GridEditor):\n    title = \"Editing scripts\"\n    columns = [\n        col_text.Column(\"Command\"),\n    ]\n\n    def is_error(self, col, val):\n        try:\n            script.parse_command(val)\n        except exceptions.OptionsError as e:\n            return str(e)\n\n\nclass HostPatternEditor(base.GridEditor):\n    title = \"Editing host patterns\"\n    columns = [\n        col_text.Column(\"Regex (matched on hostname:port / ip:port)\")\n    ]\n\n    def is_error(self, col, val):\n        try:\n            re.compile(val, re.IGNORECASE)\n        except re.error as e:\n            return \"Invalid regex: %s\" % str(e)\n\n    def data_in(self, data):\n        return [[i] for i in data]\n\n    def data_out(self, data):\n        return [i[0] for i in data]\n\n\nclass CookieEditor(base.GridEditor):\n    title = \"Editing request Cookie header\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n    ]\n\n\nclass CookieAttributeEditor(base.GridEditor):\n    title = \"Editing Set-Cookie attributes\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n    ]\n\n    def data_in(self, data):\n        return [(k, v or \"\") for k, v in data]\n\n    def data_out(self, data):\n        ret = []\n        for i in data:\n            if not i[1]:\n                ret.append([i[0], None])\n            else:\n                ret.append(i)\n        return ret\n\n\nclass SetCookieEditor(base.GridEditor):\n    title = \"Editing response SetCookie header\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n        col_subgrid.Column(\"Attributes\", CookieAttributeEditor),\n    ]\n\n    def data_in(self, data):\n        flattened = []\n        for key, (value, attrs) in data:\n            flattened.append([key, value, attrs.items(multi=True)])\n        return flattened\n\n    def data_out(self, data):\n        vals = []\n        for key, value, attrs in data:\n            vals.append(\n                [\n                    key,\n                    (value, attrs)\n                ]\n            )\n        return vals\n", "path": "mitmproxy/tools/console/grideditor/editors.py"}], "after_files": [{"content": "import re\nimport urwid\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy.addons import script\nfrom mitmproxy.tools.console import common\nfrom mitmproxy.tools.console.grideditor import base\nfrom mitmproxy.tools.console.grideditor import col_text\nfrom mitmproxy.tools.console.grideditor import col_bytes\nfrom mitmproxy.tools.console.grideditor import col_subgrid\nfrom mitmproxy.tools.console import signals\nfrom mitmproxy.net.http import user_agents\n\n\nclass QueryEditor(base.GridEditor):\n    title = \"Editing query\"\n    columns = [\n        col_text.Column(\"Key\"),\n        col_text.Column(\"Value\")\n    ]\n\n\nclass HeaderEditor(base.GridEditor):\n    title = \"Editing headers\"\n    columns = [\n        col_bytes.Column(\"Key\"),\n        col_bytes.Column(\"Value\")\n    ]\n\n    def make_help(self):\n        h = super().make_help()\n        text = [\n            urwid.Text([(\"text\", \"Special keys:\\n\")])\n        ]\n        keys = [\n            (\"U\", \"add User-Agent header\"),\n        ]\n        text.extend(\n            common.format_keyvals(keys, key=\"key\", val=\"text\", indent=4)\n        )\n        text.append(urwid.Text([(\"text\", \"\\n\")]))\n        text.extend(h)\n        return text\n\n    def set_user_agent(self, k):\n        ua = user_agents.get_by_shortcut(k)\n        if ua:\n            self.walker.add_value(\n                [\n                    b\"User-Agent\",\n                    ua[2].encode()\n                ]\n            )\n\n    def handle_key(self, key):\n        if key == \"U\":\n            signals.status_prompt_onekey.send(\n                prompt=\"Add User-Agent header:\",\n                keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],\n                callback=self.set_user_agent,\n            )\n            return True\n\n\nclass URLEncodedFormEditor(base.GridEditor):\n    title = \"Editing URL-encoded form\"\n    columns = [\n        col_text.Column(\"Key\"),\n        col_text.Column(\"Value\")\n    ]\n\n\nclass ReplaceEditor(base.GridEditor):\n    title = \"Editing replacement patterns\"\n    columns = [\n        col_text.Column(\"Filter\"),\n        col_text.Column(\"Regex\"),\n        col_text.Column(\"Replacement\"),\n    ]\n\n    def is_error(self, col, val):\n        if col == 0:\n            if not flowfilter.parse(val):\n                return \"Invalid filter specification.\"\n        elif col == 1:\n            try:\n                re.compile(val)\n            except re.error:\n                return \"Invalid regular expression.\"\n        return False\n\n\nclass SetHeadersEditor(base.GridEditor):\n    title = \"Editing header set patterns\"\n    columns = [\n        col_text.Column(\"Filter\"),\n        col_text.Column(\"Header\"),\n        col_text.Column(\"Value\"),\n    ]\n\n    def is_error(self, col, val):\n        if col == 0:\n            if not flowfilter.parse(val):\n                return \"Invalid filter specification\"\n        return False\n\n    def make_help(self):\n        h = super().make_help()\n        text = [\n            urwid.Text([(\"text\", \"Special keys:\\n\")])\n        ]\n        keys = [\n            (\"U\", \"add User-Agent header\"),\n        ]\n        text.extend(\n            common.format_keyvals(keys, key=\"key\", val=\"text\", indent=4)\n        )\n        text.append(urwid.Text([(\"text\", \"\\n\")]))\n        text.extend(h)\n        return text\n\n    def set_user_agent(self, k):\n        ua = user_agents.get_by_shortcut(k)\n        if ua:\n            self.walker.add_value(\n                [\n                    \".*\",\n                    b\"User-Agent\",\n                    ua[2].encode()\n                ]\n            )\n\n    def handle_key(self, key):\n        if key == \"U\":\n            signals.status_prompt_onekey.send(\n                prompt=\"Add User-Agent header:\",\n                keys=[(i[0], i[1]) for i in user_agents.UASTRINGS],\n                callback=self.set_user_agent,\n            )\n            return True\n\n\nclass PathEditor(base.GridEditor):\n    # TODO: Next row on enter?\n\n    title = \"Editing URL path components\"\n    columns = [\n        col_text.Column(\"Component\"),\n    ]\n\n    def data_in(self, data):\n        return [[i] for i in data]\n\n    def data_out(self, data):\n        return [i[0] for i in data]\n\n\nclass ScriptEditor(base.GridEditor):\n    title = \"Editing scripts\"\n    columns = [\n        col_text.Column(\"Command\"),\n    ]\n\n    def is_error(self, col, val):\n        try:\n            script.parse_command(val)\n        except exceptions.OptionsError as e:\n            return str(e)\n\n\nclass HostPatternEditor(base.GridEditor):\n    title = \"Editing host patterns\"\n    columns = [\n        col_text.Column(\"Regex (matched on hostname:port / ip:port)\")\n    ]\n\n    def is_error(self, col, val):\n        try:\n            re.compile(val, re.IGNORECASE)\n        except re.error as e:\n            return \"Invalid regex: %s\" % str(e)\n\n    def data_in(self, data):\n        return [[i] for i in data]\n\n    def data_out(self, data):\n        return [i[0] for i in data]\n\n\nclass CookieEditor(base.GridEditor):\n    title = \"Editing request Cookie header\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n    ]\n\n\nclass CookieAttributeEditor(base.GridEditor):\n    title = \"Editing Set-Cookie attributes\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n    ]\n\n    def data_in(self, data):\n        return [(k, v or \"\") for k, v in data]\n\n    def data_out(self, data):\n        ret = []\n        for i in data:\n            if not i[1]:\n                ret.append([i[0], None])\n            else:\n                ret.append(i)\n        return ret\n\n\nclass SetCookieEditor(base.GridEditor):\n    title = \"Editing response SetCookie header\"\n    columns = [\n        col_text.Column(\"Name\"),\n        col_text.Column(\"Value\"),\n        col_subgrid.Column(\"Attributes\", CookieAttributeEditor),\n    ]\n\n    def data_in(self, data):\n        flattened = []\n        for key, (value, attrs) in data:\n            flattened.append([key, value, attrs.items(multi=True)])\n        return flattened\n\n    def data_out(self, data):\n        vals = []\n        for key, value, attrs in data:\n            vals.append(\n                [\n                    key,\n                    (value, attrs)\n                ]\n            )\n        return vals\n", "path": "mitmproxy/tools/console/grideditor/editors.py"}]}