# Buggy code
def get_state(self):
    """
    Retrieve object state.
    """
    state = {}
    for attr, cls in self._stateobject_attributes.items():
        val = getattr(self, attr)
        if val is None:
            state[attr] = None
        elif hasattr(val, "get_state"):
            state[attr] = val.get_state()
        elif _is_list(cls):
            state[attr] = [x.get_state() for x in val]
        else:
            state[attr] = val
    return state


# Traceback (ValueError)
Traceback (most recent call last):
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/master.py", line 281, in run
self.loop.run()
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 278, in run
self._run()
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 376, in _run
self.event_loop.run()
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 682, in run
self._loop()
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 719, in _loop
self._watch_files[fd]()
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/raw_display.py", line 393, in <lambda>
event_loop, callback, self.get_available_raw_input())
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/raw_display.py", line 493, in parse_input
callback(processed, processed_codes)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 403, in _update
self.process_input(keys)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/main_loop.py", line 503, in process_input
k = self._topmost_widget.keypress(self.screen_size, k)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/window.py", line 84, in keypress
k = super().keypress(size, k)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/urwid/container.py", line 1116, in keypress
return self.footer.keypress((maxcol,),key)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/statusbar.py", line 155, in keypress
return self.master.ab.keypress(*args, **kwargs)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/statusbar.py", line 110, in keypress
self.prompt_execute(self._w.get_edit_text())
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/statusbar.py", line 133, in prompt_execute
msg = p(txt)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/statusbar.py", line 21, in __call__
return self.callback(pth, *self.args)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/master.py", line 388, in save_flows
return self._write_flows(path, self.view)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/tools/console/master.py", line 382, in _write_flows
fw.add(i)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/io.py", line 27, in add
tnetstring.dump(d, self.fo)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/contrib/tnetstring.py", line 66, in dump
file_handle.write(dumps(value))
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/contrib/tnetstring.py", line 57, in dumps
_rdumpq(q, 0, value)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/contrib/tnetstring.py", line 142, in _rdumpq
size = _rdumpq(q, size, v)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/contrib/tnetstring.py", line 142, in _rdumpq
size = _rdumpq(q, size, v)
File "/usr/local/Cellar/mitmproxy/2.0.0/libexec/lib/python3.6/site-packages/mitmproxy/contrib/tnetstring.py", line 149, in _rdumpq
raise ValueError("unserializable object: {} ({})".format(value, type(value)))
ValueError: unserializable object: <WebSocketFlow (69 messages)> (<class 'mitmproxy.websocket.WebSocketFlow'>)

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

# Fixed code
def get_state(self):
    """
    Retrieve object state.
    """
    state = {}
    for attr, cls in self._stateobject_attributes.items():
        val = getattr(self, attr)
        if val is None:
            state[attr] = None
        elif hasattr(val, "get_state"):
            state[attr] = val.get_state()
        elif _is_list(cls):
            state[attr] = [x.get_state() for x in val]
        elif isinstance(val, dict):
            s = {}
            for k, v in val.items():
                if hasattr(v, "get_state"):
                    s[k] = v.get_state()
                else:
                    s[k] = v
            state[attr] = s
        else:
            state[attr] = val
    return state