# Buggy code
def keypress(self, size, key):
    if self.walker.editing:
        if key == "enter":
            foc, idx = self.get_focus()
            v = self.walker.get_edit_text()
            try:
                d = self.master.options.parse_setval(foc.opt.name, v)
                self.master.options.update(**{foc.opt.name: d})
            except exceptions.OptionsError as v:
                signals.status_message.send(message=str(v))
            self.walker.stop_editing()
            return None
        elif key == "esc":
            self.walker.stop_editing()
            return None
    else:
        if key == "m_start":
            self.set_focus(0)
            self.walker._modified()
        elif key == "m_end":
            self.set_focus(len(self.walker.opts) - 1)
            self.walker._modified()
        elif key == "m_select":
            foc, idx = self.get_focus()
            if foc.opt.typespec == bool:
                self.master.options.toggler(foc.opt.name)()
                # Bust the focus widget cache
                self.set_focus(self.walker.index)
            elif can_edit_inplace(foc.opt):
                self.walker.start_editing()
                self.walker._modified()
            elif foc.opt.choices:
                self.master.overlay(
                    overlay.Chooser(
                        self.master,
                        foc.opt.name,
                        foc.opt.choices,
                        foc.opt.current(),
                        self.master.options.setter(foc.opt.name),
                    )
                )
            elif foc.opt.typespec == Sequence[str]:
                self.master.overlay(
                    overlay.OptionsOverlay(
                        self.master, foc.opt.name, foc.opt.current(), HELP_HEIGHT + 5
                    ),
                    valign="top",
                )
            else:
                raise NotImplementedError()
    return super().keypress(size, key)


# Traceback (AttributeError)
Traceback (most recent call last):
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/master.py", line 86, in run_loop
loop()
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/main_loop.py", line 286, in run
self._run()
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/main_loop.py", line 384, in _run
self.event_loop.run()
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/main_loop.py", line 1484, in run
reraise(*exc_info)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/compat.py", line 58, in reraise
raise value
File "/usr/lib/python3.6/asyncio/events.py", line 145, in _run
self._callback(*self._args)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/raw_display.py", line 404, in <lambda>
event_loop, callback, self.get_available_raw_input())
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/raw_display.py", line 502, in parse_input
callback(processed, processed_codes)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/main_loop.py", line 411, in _update
self.process_input(keys)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/main_loop.py", line 511, in process_input
k = self._topmost_widget.keypress(self.screen_size, k)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/tools/console/window.py", line 309, in keypress
k = super().keypress(size, k)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/container.py", line 1131, in keypress
return self.body.keypress( (maxcol, remaining), key )
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/tools/console/window.py", line 44, in keypress
ret = super().keypress(size, key)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/urwid/container.py", line 1131, in keypress
return self.body.keypress( (maxcol, remaining), key )
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/tools/console/options.py", line 283, in keypress
return self.focus_item.keypress(tsize, key)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/tools/console/options.py", line 177, in keypress
d = self.master.options.parse_setval(foc.opt.name, v)
File "/tmp/mitmproxy-crash/lib/python3.6/site-packages/mitmproxy/optmanager.py", line 332, in parse_setval
if o.typespec in (str, typing.Optional[str]):
AttributeError: 'str' object has no attribute 'typespec'

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

# Fixed code
def keypress(self, size, key):
    if self.walker.editing:
        if key == "enter":
            foc, idx = self.get_focus()
            v = self.walker.get_edit_text()
            try:
                d = self.master.options.parse_setval(foc.opt, v)
                self.master.options.update(**{foc.opt.name: d})
            except exceptions.OptionsError as v:
                signals.status_message.send(message=str(v))
            self.walker.stop_editing()
            return None
        elif key == "esc":
            self.walker.stop_editing()
            return None
    else:
        if key == "m_start":
            self.set_focus(0)
            self.walker._modified()
        elif key == "m_end":
            self.set_focus(len(self.walker.opts) - 1)
            self.walker._modified()
        elif key == "m_select":
            foc, idx = self.get_focus()
            if foc.opt.typespec == bool:
                self.master.options.toggler(foc.opt.name)()
                # Bust the focus widget cache
                self.set_focus(self.walker.index)
            elif can_edit_inplace(foc.opt):
                self.walker.start_editing()
                self.walker._modified()
            elif foc.opt.choices:
                self.master.overlay(
                    overlay.Chooser(
                        self.master,
                        foc.opt.name,
                        foc.opt.choices,
                        foc.opt.current(),
                        self.master.options.setter(foc.opt.name),
                    )
                )
            elif foc.opt.typespec == Sequence[str]:
                self.master.overlay(
                    overlay.OptionsOverlay(
                        self.master, foc.opt.name, foc.opt.current(), HELP_HEIGHT + 5
                    ),
                    valign="top",
                )
            else:
                raise NotImplementedError()
    return super().keypress(size, key)