We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
proxyauth option breaks flow state access in addons
##### Steps to reproduce the problem:

1. Create `test.py` addon
```py
from mitmproxy import ctx
class AuthTest:
    def response(self, flow):
        ctx.log.info('Getting flow state')
        flow.get_state()
        ctx.log.info('Got flow state')

addons = [
    AuthTest()
]
```
2. Start `mitmdump`, navigate to example.com and observe the log
```bash
mitmdump -s server/test.py
Loading script server/test.py
Proxy server listening at http://*:8080
...
[::1]:56410: GET http://example.com/
          << 200 OK 606b
Getting flow state
Got flow state
```
3. Re-start `mitmdump` with proxyauth applied and navigate to example.com again
```bash
mitmdump -s server/test.py --set proxyauth=foo:bar
Loading script server/test.py
Proxy server listening at http://*:8080
...
[::1]:56290: GET http://example.com/
          << 200 OK 606b
Getting flow state
Addon error: Traceback (most recent call last):
  File "server/test.py", line 5, in response
    flow.get_state()
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/flow.py", line 94, in get_state
    d = super().get_state()
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py", line 31, in get_state
    state[attr] = get_state(cls, val)
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py", line 94, in get_state
    return _process(typeinfo, val, False)
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py", line 77, in _process
    for k, v in val.items()
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py", line 77, in <dictcomp>
    for k, v in val.items()
  File "/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py", line 81, in _process
    assert isinstance(val, (int, str, bool, bytes))
AssertionError
```

##### Any other comments? What have you tried so far?

There's a FIXME [right near the code that's breaking](https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/stateobject.py#L80), but I think it's a red herring. My best guess is that proxy auth adds something to the flow state that isn't in the list of allowed types `int, str, bool, bytes`—possibly a `dict`.

##### System information

```bash
mitmdump --version
Mitmproxy: 4.0.1
Python:    3.6.5
OpenSSL:   OpenSSL 1.0.2o  27 Mar 2018
Platform:  Darwin-17.5.0-x86_64-i386-64bit
```

<!-- Please use the mitmproxy forums (https://discourse.mitmproxy.org/) for support/how-to questions. Thanks! :) -->


--- 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/stateobject.py`
Content:
```
1 import typing
2 from typing import Any  # noqa
3 from typing import MutableMapping  # noqa
4 
5 from mitmproxy.coretypes import serializable
6 from mitmproxy.utils import typecheck
7 
8 
9 class StateObject(serializable.Serializable):
10     """
11     An object with serializable state.
12 
13     State attributes can either be serializable types(str, tuple, bool, ...)
14     or StateObject instances themselves.
15     """
16 
17     _stateobject_attributes: MutableMapping[str, Any] = None
18     """
19     An attribute-name -> class-or-type dict containing all attributes that
20     should be serialized. If the attribute is a class, it must implement the
21     Serializable protocol.
22     """
23 
24     def get_state(self):
25         """
26         Retrieve object state.
27         """
28         state = {}
29         for attr, cls in self._stateobject_attributes.items():
30             val = getattr(self, attr)
31             state[attr] = get_state(cls, val)
32         return state
33 
34     def set_state(self, state):
35         """
36         Load object state from data returned by a get_state call.
37         """
38         state = state.copy()
39         for attr, cls in self._stateobject_attributes.items():
40             val = state.pop(attr)
41             if val is None:
42                 setattr(self, attr, val)
43             else:
44                 curr = getattr(self, attr)
45                 if hasattr(curr, "set_state"):
46                     curr.set_state(val)
47                 else:
48                     setattr(self, attr, make_object(cls, val))
49         if state:
50             raise RuntimeWarning("Unexpected State in __setstate__: {}".format(state))
51 
52 
53 def _process(typeinfo: typecheck.Type, val: typing.Any, make: bool) -> typing.Any:
54     if val is None:
55         return None
56     elif make and hasattr(typeinfo, "from_state"):
57         return typeinfo.from_state(val)
58     elif not make and hasattr(val, "get_state"):
59         return val.get_state()
60 
61     typename = str(typeinfo)
62 
63     if typename.startswith("typing.List"):
64         T = typecheck.sequence_type(typeinfo)
65         return [_process(T, x, make) for x in val]
66     elif typename.startswith("typing.Tuple"):
67         Ts = typecheck.tuple_types(typeinfo)
68         if len(Ts) != len(val):
69             raise ValueError("Invalid data. Expected {}, got {}.".format(Ts, val))
70         return tuple(
71             _process(T, x, make) for T, x in zip(Ts, val)
72         )
73     elif typename.startswith("typing.Dict"):
74         k_cls, v_cls = typecheck.mapping_types(typeinfo)
75         return {
76             _process(k_cls, k, make): _process(v_cls, v, make)
77             for k, v in val.items()
78         }
79     elif typename.startswith("typing.Any"):
80         # FIXME: Remove this when we remove flow.metadata
81         assert isinstance(val, (int, str, bool, bytes))
82         return val
83     else:
84         return typeinfo(val)
85 
86 
87 def make_object(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:
88     """Create an object based on the state given in val."""
89     return _process(typeinfo, val, True)
90 
91 
92 def get_state(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:
93     """Get the state of the object given as val."""
94     return _process(typeinfo, val, False)
95
```
--- 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/stateobject.py b/mitmproxy/stateobject.py
--- a/mitmproxy/stateobject.py
+++ b/mitmproxy/stateobject.py
@@ -1,6 +1,7 @@
 import typing
 from typing import Any  # noqa
 from typing import MutableMapping  # noqa
+import json
 
 from mitmproxy.coretypes import serializable
 from mitmproxy.utils import typecheck
@@ -77,8 +78,14 @@
             for k, v in val.items()
         }
     elif typename.startswith("typing.Any"):
-        # FIXME: Remove this when we remove flow.metadata
-        assert isinstance(val, (int, str, bool, bytes))
+        # This requires a bit of explanation. We can't import our IO layer here,
+        # because it causes a circular import. Rather than restructuring the
+        # code for this, we use JSON serialization, which has similar primitive
+        # type restrictions as tnetstring, to check for conformance.
+        try:
+            json.dumps(val)
+        except TypeError:
+            raise ValueError(f"Data not serializable: {val}")
         return val
     else:
         return typeinfo(val)

{"golden_diff": "diff --git a/mitmproxy/stateobject.py b/mitmproxy/stateobject.py\n--- a/mitmproxy/stateobject.py\n+++ b/mitmproxy/stateobject.py\n@@ -1,6 +1,7 @@\n import typing\n from typing import Any  # noqa\n from typing import MutableMapping  # noqa\n+import json\n \n from mitmproxy.coretypes import serializable\n from mitmproxy.utils import typecheck\n@@ -77,8 +78,14 @@\n             for k, v in val.items()\n         }\n     elif typename.startswith(\"typing.Any\"):\n-        # FIXME: Remove this when we remove flow.metadata\n-        assert isinstance(val, (int, str, bool, bytes))\n+        # This requires a bit of explanation. We can't import our IO layer here,\n+        # because it causes a circular import. Rather than restructuring the\n+        # code for this, we use JSON serialization, which has similar primitive\n+        # type restrictions as tnetstring, to check for conformance.\n+        try:\n+            json.dumps(val)\n+        except TypeError:\n+            raise ValueError(f\"Data not serializable: {val}\")\n         return val\n     else:\n         return typeinfo(val)\n", "issue": "proxyauth option breaks flow state access in addons\n##### Steps to reproduce the problem:\r\n\r\n1. Create `test.py` addon\r\n```py\r\nfrom mitmproxy import ctx\r\nclass AuthTest:\r\n    def response(self, flow):\r\n        ctx.log.info('Getting flow state')\r\n        flow.get_state()\r\n        ctx.log.info('Got flow state')\r\n\r\naddons = [\r\n    AuthTest()\r\n]\r\n```\r\n2. Start `mitmdump`, navigate to example.com and observe the log\r\n```bash\r\nmitmdump -s server/test.py\r\nLoading script server/test.py\r\nProxy server listening at http://*:8080\r\n...\r\n[::1]:56410: GET http://example.com/\r\n          << 200 OK 606b\r\nGetting flow state\r\nGot flow state\r\n```\r\n3. Re-start `mitmdump` with proxyauth applied and navigate to example.com again\r\n```bash\r\nmitmdump -s server/test.py --set proxyauth=foo:bar\r\nLoading script server/test.py\r\nProxy server listening at http://*:8080\r\n...\r\n[::1]:56290: GET http://example.com/\r\n          << 200 OK 606b\r\nGetting flow state\r\nAddon error: Traceback (most recent call last):\r\n  File \"server/test.py\", line 5, in response\r\n    flow.get_state()\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/flow.py\", line 94, in get_state\r\n    d = super().get_state()\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py\", line 31, in get_state\r\n    state[attr] = get_state(cls, val)\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py\", line 94, in get_state\r\n    return _process(typeinfo, val, False)\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py\", line 77, in _process\r\n    for k, v in val.items()\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py\", line 77, in <dictcomp>\r\n    for k, v in val.items()\r\n  File \"/usr/local/Cellar/mitmproxy/4.0.1/libexec/lib/python3.6/site-packages/mitmproxy/stateobject.py\", line 81, in _process\r\n    assert isinstance(val, (int, str, bool, bytes))\r\nAssertionError\r\n```\r\n\r\n##### Any other comments? What have you tried so far?\r\n\r\nThere's a FIXME [right near the code that's breaking](https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/stateobject.py#L80), but I think it's a red herring. My best guess is that proxy auth adds something to the flow state that isn't in the list of allowed types `int, str, bool, bytes`\u2014possibly a `dict`.\r\n\r\n##### System information\r\n\r\n```bash\r\nmitmdump --version\r\nMitmproxy: 4.0.1\r\nPython:    3.6.5\r\nOpenSSL:   OpenSSL 1.0.2o  27 Mar 2018\r\nPlatform:  Darwin-17.5.0-x86_64-i386-64bit\r\n```\r\n\r\n<!-- Please use the mitmproxy forums (https://discourse.mitmproxy.org/) for support/how-to questions. Thanks! :) -->\r\n\n", "before_files": [{"content": "import typing\nfrom typing import Any  # noqa\nfrom typing import MutableMapping  # noqa\n\nfrom mitmproxy.coretypes import serializable\nfrom mitmproxy.utils import typecheck\n\n\nclass StateObject(serializable.Serializable):\n    \"\"\"\n    An object with serializable state.\n\n    State attributes can either be serializable types(str, tuple, bool, ...)\n    or StateObject instances themselves.\n    \"\"\"\n\n    _stateobject_attributes: MutableMapping[str, Any] = None\n    \"\"\"\n    An attribute-name -> class-or-type dict containing all attributes that\n    should be serialized. If the attribute is a class, it must implement the\n    Serializable protocol.\n    \"\"\"\n\n    def get_state(self):\n        \"\"\"\n        Retrieve object state.\n        \"\"\"\n        state = {}\n        for attr, cls in self._stateobject_attributes.items():\n            val = getattr(self, attr)\n            state[attr] = get_state(cls, val)\n        return state\n\n    def set_state(self, state):\n        \"\"\"\n        Load object state from data returned by a get_state call.\n        \"\"\"\n        state = state.copy()\n        for attr, cls in self._stateobject_attributes.items():\n            val = state.pop(attr)\n            if val is None:\n                setattr(self, attr, val)\n            else:\n                curr = getattr(self, attr)\n                if hasattr(curr, \"set_state\"):\n                    curr.set_state(val)\n                else:\n                    setattr(self, attr, make_object(cls, val))\n        if state:\n            raise RuntimeWarning(\"Unexpected State in __setstate__: {}\".format(state))\n\n\ndef _process(typeinfo: typecheck.Type, val: typing.Any, make: bool) -> typing.Any:\n    if val is None:\n        return None\n    elif make and hasattr(typeinfo, \"from_state\"):\n        return typeinfo.from_state(val)\n    elif not make and hasattr(val, \"get_state\"):\n        return val.get_state()\n\n    typename = str(typeinfo)\n\n    if typename.startswith(\"typing.List\"):\n        T = typecheck.sequence_type(typeinfo)\n        return [_process(T, x, make) for x in val]\n    elif typename.startswith(\"typing.Tuple\"):\n        Ts = typecheck.tuple_types(typeinfo)\n        if len(Ts) != len(val):\n            raise ValueError(\"Invalid data. Expected {}, got {}.\".format(Ts, val))\n        return tuple(\n            _process(T, x, make) for T, x in zip(Ts, val)\n        )\n    elif typename.startswith(\"typing.Dict\"):\n        k_cls, v_cls = typecheck.mapping_types(typeinfo)\n        return {\n            _process(k_cls, k, make): _process(v_cls, v, make)\n            for k, v in val.items()\n        }\n    elif typename.startswith(\"typing.Any\"):\n        # FIXME: Remove this when we remove flow.metadata\n        assert isinstance(val, (int, str, bool, bytes))\n        return val\n    else:\n        return typeinfo(val)\n\n\ndef make_object(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:\n    \"\"\"Create an object based on the state given in val.\"\"\"\n    return _process(typeinfo, val, True)\n\n\ndef get_state(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:\n    \"\"\"Get the state of the object given as val.\"\"\"\n    return _process(typeinfo, val, False)\n", "path": "mitmproxy/stateobject.py"}], "after_files": [{"content": "import typing\nfrom typing import Any  # noqa\nfrom typing import MutableMapping  # noqa\nimport json\n\nfrom mitmproxy.coretypes import serializable\nfrom mitmproxy.utils import typecheck\n\n\nclass StateObject(serializable.Serializable):\n    \"\"\"\n    An object with serializable state.\n\n    State attributes can either be serializable types(str, tuple, bool, ...)\n    or StateObject instances themselves.\n    \"\"\"\n\n    _stateobject_attributes: MutableMapping[str, Any] = None\n    \"\"\"\n    An attribute-name -> class-or-type dict containing all attributes that\n    should be serialized. If the attribute is a class, it must implement the\n    Serializable protocol.\n    \"\"\"\n\n    def get_state(self):\n        \"\"\"\n        Retrieve object state.\n        \"\"\"\n        state = {}\n        for attr, cls in self._stateobject_attributes.items():\n            val = getattr(self, attr)\n            state[attr] = get_state(cls, val)\n        return state\n\n    def set_state(self, state):\n        \"\"\"\n        Load object state from data returned by a get_state call.\n        \"\"\"\n        state = state.copy()\n        for attr, cls in self._stateobject_attributes.items():\n            val = state.pop(attr)\n            if val is None:\n                setattr(self, attr, val)\n            else:\n                curr = getattr(self, attr)\n                if hasattr(curr, \"set_state\"):\n                    curr.set_state(val)\n                else:\n                    setattr(self, attr, make_object(cls, val))\n        if state:\n            raise RuntimeWarning(\"Unexpected State in __setstate__: {}\".format(state))\n\n\ndef _process(typeinfo: typecheck.Type, val: typing.Any, make: bool) -> typing.Any:\n    if val is None:\n        return None\n    elif make and hasattr(typeinfo, \"from_state\"):\n        return typeinfo.from_state(val)\n    elif not make and hasattr(val, \"get_state\"):\n        return val.get_state()\n\n    typename = str(typeinfo)\n\n    if typename.startswith(\"typing.List\"):\n        T = typecheck.sequence_type(typeinfo)\n        return [_process(T, x, make) for x in val]\n    elif typename.startswith(\"typing.Tuple\"):\n        Ts = typecheck.tuple_types(typeinfo)\n        if len(Ts) != len(val):\n            raise ValueError(\"Invalid data. Expected {}, got {}.\".format(Ts, val))\n        return tuple(\n            _process(T, x, make) for T, x in zip(Ts, val)\n        )\n    elif typename.startswith(\"typing.Dict\"):\n        k_cls, v_cls = typecheck.mapping_types(typeinfo)\n        return {\n            _process(k_cls, k, make): _process(v_cls, v, make)\n            for k, v in val.items()\n        }\n    elif typename.startswith(\"typing.Any\"):\n        # This requires a bit of explanation. We can't import our IO layer here,\n        # because it causes a circular import. Rather than restructuring the\n        # code for this, we use JSON serialization, which has similar primitive\n        # type restrictions as tnetstring, to check for conformance.\n        try:\n            json.dumps(val)\n        except TypeError:\n            raise ValueError(f\"Data not serializable: {val}\")\n        return val\n    else:\n        return typeinfo(val)\n\n\ndef make_object(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:\n    \"\"\"Create an object based on the state given in val.\"\"\"\n    return _process(typeinfo, val, True)\n\n\ndef get_state(typeinfo: typecheck.Type, val: typing.Any) -> typing.Any:\n    \"\"\"Get the state of the object given as val.\"\"\"\n    return _process(typeinfo, val, False)\n", "path": "mitmproxy/stateobject.py"}]}