We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
decimal.Decimal cannot be sent across session
When trying to give data of type decimal.Decimal as data sources to plots, the BokehJSONEncoder does tries to serialise the Decimal object with the standard built-in JSON encoder. This causes an exception "Decimal('...') not JSON serializable". The solution is to edit BokehJSONEncoder.trasnform_python_types to account for this possibility. I have tested the solution and it works.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/protocol.py`
Content:
```
1 from __future__ import absolute_import
2 
3 import json
4 import logging
5 import time
6 import datetime as dt
7 import calendar
8 
9 import numpy as np
10 from six.moves import cPickle as pickle
11 
12 try:
13     import pandas as pd
14     is_pandas = True
15 except ImportError:
16     is_pandas = False
17 
18 try:
19     from dateutil.relativedelta import relativedelta
20     is_dateutil = True
21 except ImportError:
22     is_dateutil = False
23 
24 from .settings import settings
25 
26 log = logging.getLogger(__name__)
27 
28 millifactor = 10**6.0
29 
30 class BokehJSONEncoder(json.JSONEncoder):
31     def transform_series(self, obj):
32         """transform series
33         """
34         vals = obj.values
35         return self.transform_array(vals)
36 
37     # Check for astype failures (putative Numpy < 1.7)
38     dt2001 = np.datetime64('2001')
39     legacy_datetime64 = (dt2001.astype('int64') ==
40                          dt2001.astype('datetime64[ms]').astype('int64'))
41     def transform_array(self, obj):
42         """Transform arrays into lists of json safe types
43         also handles pandas series, and replacing
44         nans and infs with strings
45         """
46         ## not quite correct, truncates to ms..
47         if obj.dtype.kind == 'M':
48             if self.legacy_datetime64:
49                 if obj.dtype == np.dtype('datetime64[ns]'):
50                     return (obj.astype('int64') / millifactor).tolist()
51                 # else punt.
52             else:
53                 return obj.astype('datetime64[ms]').astype('int64').tolist()
54         elif obj.dtype.kind in ('u', 'i', 'f'):
55             return self.transform_numerical_array(obj)
56         return obj.tolist()
57 
58     def transform_numerical_array(self, obj):
59         """handles nans/inf conversion
60         """
61         if isinstance(obj, np.ma.MaskedArray):
62             obj = obj.filled(np.nan)  # Set masked values to nan
63         if not np.isnan(obj).any() and not np.isinf(obj).any():
64             return obj.tolist()
65         else:
66             transformed = obj.astype('object')
67             transformed[np.isnan(obj)] = 'NaN'
68             transformed[np.isposinf(obj)] = 'Infinity'
69             transformed[np.isneginf(obj)] = '-Infinity'
70             return transformed.tolist()
71 
72     def transform_python_types(self, obj):
73         """handle special scalars, default to default json encoder
74         """
75         # Pandas Timestamp
76         if is_pandas and isinstance(obj, pd.tslib.Timestamp):
77             return obj.value / millifactor  #nanosecond to millisecond
78         elif np.issubdtype(type(obj), np.float):
79             return float(obj)
80         elif np.issubdtype(type(obj), np.int):
81             return int(obj)
82         elif np.issubdtype(type(obj), np.bool_):
83             return bool(obj)
84         # Datetime, Date
85         elif isinstance(obj, (dt.datetime, dt.date)):
86             return calendar.timegm(obj.timetuple()) * 1000.
87         # Numpy datetime64
88         elif isinstance(obj, np.datetime64):
89             epoch_delta = obj - np.datetime64('1970-01-01T00:00:00Z')
90             return (epoch_delta / np.timedelta64(1, 'ms'))
91         # Time
92         elif isinstance(obj, dt.time):
93             return (obj.hour*3600 + obj.minute*60 + obj.second)*1000 + obj.microsecond / 1000.
94         elif is_dateutil and isinstance(obj, relativedelta):
95             return dict(years=obj.years, months=obj.months, days=obj.days, hours=obj.hours,
96                 minutes=obj.minutes, seconds=obj.seconds, microseconds=obj.microseconds)
97         else:
98             return super(BokehJSONEncoder, self).default(obj)
99 
100     def default(self, obj):
101         #argh! local import!
102         from .plot_object import PlotObject
103         from .properties import HasProps
104         from .colors import Color
105         ## array types
106         if is_pandas and isinstance(obj, (pd.Series, pd.Index)):
107             return self.transform_series(obj)
108         elif isinstance(obj, np.ndarray):
109             return self.transform_array(obj)
110         elif isinstance(obj, PlotObject):
111             return obj.ref
112         elif isinstance(obj, HasProps):
113             return obj.changed_properties_with_values()
114         elif isinstance(obj, Color):
115             return obj.to_css()
116         else:
117             return self.transform_python_types(obj)
118 
119 def serialize_json(obj, encoder=BokehJSONEncoder, **kwargs):
120     if settings.pretty(False):
121         kwargs["indent"] = 4
122     return json.dumps(obj, cls=encoder, **kwargs)
123 
124 deserialize_json = json.loads
125 
126 serialize_web = serialize_json
127 
128 deserialize_web = deserialize_json
129 
130 def status_obj(status):
131     return {'msgtype': 'status',
132             'status': status}
133 
134 def error_obj(error_msg):
135     return {
136         'msgtype': 'error',
137         'error_msg': error_msg}
138
```
--- 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/bokeh/protocol.py b/bokeh/protocol.py
--- a/bokeh/protocol.py
+++ b/bokeh/protocol.py
@@ -5,6 +5,7 @@
 import time
 import datetime as dt
 import calendar
+import decimal
 
 import numpy as np
 from six.moves import cPickle as pickle
@@ -94,6 +95,9 @@
         elif is_dateutil and isinstance(obj, relativedelta):
             return dict(years=obj.years, months=obj.months, days=obj.days, hours=obj.hours,
                 minutes=obj.minutes, seconds=obj.seconds, microseconds=obj.microseconds)
+        # Decimal
+        elif isinstance(obj, decimal.Decimal):
+            return float(obj)
         else:
             return super(BokehJSONEncoder, self).default(obj)

{"golden_diff": "diff --git a/bokeh/protocol.py b/bokeh/protocol.py\n--- a/bokeh/protocol.py\n+++ b/bokeh/protocol.py\n@@ -5,6 +5,7 @@\n import time\n import datetime as dt\n import calendar\n+import decimal\n \n import numpy as np\n from six.moves import cPickle as pickle\n@@ -94,6 +95,9 @@\n         elif is_dateutil and isinstance(obj, relativedelta):\n             return dict(years=obj.years, months=obj.months, days=obj.days, hours=obj.hours,\n                 minutes=obj.minutes, seconds=obj.seconds, microseconds=obj.microseconds)\n+        # Decimal\n+        elif isinstance(obj, decimal.Decimal):\n+            return float(obj)\n         else:\n             return super(BokehJSONEncoder, self).default(obj)\n", "issue": "decimal.Decimal cannot be sent across session\nWhen trying to give data of type decimal.Decimal as data sources to plots, the BokehJSONEncoder does tries to serialise the Decimal object with the standard built-in JSON encoder. This causes an exception \"Decimal('...') not JSON serializable\". The solution is to edit BokehJSONEncoder.trasnform_python_types to account for this possibility. I have tested the solution and it works.\n\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport json\nimport logging\nimport time\nimport datetime as dt\nimport calendar\n\nimport numpy as np\nfrom six.moves import cPickle as pickle\n\ntry:\n    import pandas as pd\n    is_pandas = True\nexcept ImportError:\n    is_pandas = False\n\ntry:\n    from dateutil.relativedelta import relativedelta\n    is_dateutil = True\nexcept ImportError:\n    is_dateutil = False\n\nfrom .settings import settings\n\nlog = logging.getLogger(__name__)\n\nmillifactor = 10**6.0\n\nclass BokehJSONEncoder(json.JSONEncoder):\n    def transform_series(self, obj):\n        \"\"\"transform series\n        \"\"\"\n        vals = obj.values\n        return self.transform_array(vals)\n\n    # Check for astype failures (putative Numpy < 1.7)\n    dt2001 = np.datetime64('2001')\n    legacy_datetime64 = (dt2001.astype('int64') ==\n                         dt2001.astype('datetime64[ms]').astype('int64'))\n    def transform_array(self, obj):\n        \"\"\"Transform arrays into lists of json safe types\n        also handles pandas series, and replacing\n        nans and infs with strings\n        \"\"\"\n        ## not quite correct, truncates to ms..\n        if obj.dtype.kind == 'M':\n            if self.legacy_datetime64:\n                if obj.dtype == np.dtype('datetime64[ns]'):\n                    return (obj.astype('int64') / millifactor).tolist()\n                # else punt.\n            else:\n                return obj.astype('datetime64[ms]').astype('int64').tolist()\n        elif obj.dtype.kind in ('u', 'i', 'f'):\n            return self.transform_numerical_array(obj)\n        return obj.tolist()\n\n    def transform_numerical_array(self, obj):\n        \"\"\"handles nans/inf conversion\n        \"\"\"\n        if isinstance(obj, np.ma.MaskedArray):\n            obj = obj.filled(np.nan)  # Set masked values to nan\n        if not np.isnan(obj).any() and not np.isinf(obj).any():\n            return obj.tolist()\n        else:\n            transformed = obj.astype('object')\n            transformed[np.isnan(obj)] = 'NaN'\n            transformed[np.isposinf(obj)] = 'Infinity'\n            transformed[np.isneginf(obj)] = '-Infinity'\n            return transformed.tolist()\n\n    def transform_python_types(self, obj):\n        \"\"\"handle special scalars, default to default json encoder\n        \"\"\"\n        # Pandas Timestamp\n        if is_pandas and isinstance(obj, pd.tslib.Timestamp):\n            return obj.value / millifactor  #nanosecond to millisecond\n        elif np.issubdtype(type(obj), np.float):\n            return float(obj)\n        elif np.issubdtype(type(obj), np.int):\n            return int(obj)\n        elif np.issubdtype(type(obj), np.bool_):\n            return bool(obj)\n        # Datetime, Date\n        elif isinstance(obj, (dt.datetime, dt.date)):\n            return calendar.timegm(obj.timetuple()) * 1000.\n        # Numpy datetime64\n        elif isinstance(obj, np.datetime64):\n            epoch_delta = obj - np.datetime64('1970-01-01T00:00:00Z')\n            return (epoch_delta / np.timedelta64(1, 'ms'))\n        # Time\n        elif isinstance(obj, dt.time):\n            return (obj.hour*3600 + obj.minute*60 + obj.second)*1000 + obj.microsecond / 1000.\n        elif is_dateutil and isinstance(obj, relativedelta):\n            return dict(years=obj.years, months=obj.months, days=obj.days, hours=obj.hours,\n                minutes=obj.minutes, seconds=obj.seconds, microseconds=obj.microseconds)\n        else:\n            return super(BokehJSONEncoder, self).default(obj)\n\n    def default(self, obj):\n        #argh! local import!\n        from .plot_object import PlotObject\n        from .properties import HasProps\n        from .colors import Color\n        ## array types\n        if is_pandas and isinstance(obj, (pd.Series, pd.Index)):\n            return self.transform_series(obj)\n        elif isinstance(obj, np.ndarray):\n            return self.transform_array(obj)\n        elif isinstance(obj, PlotObject):\n            return obj.ref\n        elif isinstance(obj, HasProps):\n            return obj.changed_properties_with_values()\n        elif isinstance(obj, Color):\n            return obj.to_css()\n        else:\n            return self.transform_python_types(obj)\n\ndef serialize_json(obj, encoder=BokehJSONEncoder, **kwargs):\n    if settings.pretty(False):\n        kwargs[\"indent\"] = 4\n    return json.dumps(obj, cls=encoder, **kwargs)\n\ndeserialize_json = json.loads\n\nserialize_web = serialize_json\n\ndeserialize_web = deserialize_json\n\ndef status_obj(status):\n    return {'msgtype': 'status',\n            'status': status}\n\ndef error_obj(error_msg):\n    return {\n        'msgtype': 'error',\n        'error_msg': error_msg}\n", "path": "bokeh/protocol.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nimport json\nimport logging\nimport time\nimport datetime as dt\nimport calendar\nimport decimal\n\nimport numpy as np\nfrom six.moves import cPickle as pickle\n\ntry:\n    import pandas as pd\n    is_pandas = True\nexcept ImportError:\n    is_pandas = False\n\ntry:\n    from dateutil.relativedelta import relativedelta\n    is_dateutil = True\nexcept ImportError:\n    is_dateutil = False\n\nfrom .settings import settings\n\nlog = logging.getLogger(__name__)\n\nmillifactor = 10**6.0\n\nclass BokehJSONEncoder(json.JSONEncoder):\n    def transform_series(self, obj):\n        \"\"\"transform series\n        \"\"\"\n        vals = obj.values\n        return self.transform_array(vals)\n\n    # Check for astype failures (putative Numpy < 1.7)\n    dt2001 = np.datetime64('2001')\n    legacy_datetime64 = (dt2001.astype('int64') ==\n                         dt2001.astype('datetime64[ms]').astype('int64'))\n    def transform_array(self, obj):\n        \"\"\"Transform arrays into lists of json safe types\n        also handles pandas series, and replacing\n        nans and infs with strings\n        \"\"\"\n        ## not quite correct, truncates to ms..\n        if obj.dtype.kind == 'M':\n            if self.legacy_datetime64:\n                if obj.dtype == np.dtype('datetime64[ns]'):\n                    return (obj.astype('int64') / millifactor).tolist()\n                # else punt.\n            else:\n                return obj.astype('datetime64[ms]').astype('int64').tolist()\n        elif obj.dtype.kind in ('u', 'i', 'f'):\n            return self.transform_numerical_array(obj)\n        return obj.tolist()\n\n    def transform_numerical_array(self, obj):\n        \"\"\"handles nans/inf conversion\n        \"\"\"\n        if isinstance(obj, np.ma.MaskedArray):\n            obj = obj.filled(np.nan)  # Set masked values to nan\n        if not np.isnan(obj).any() and not np.isinf(obj).any():\n            return obj.tolist()\n        else:\n            transformed = obj.astype('object')\n            transformed[np.isnan(obj)] = 'NaN'\n            transformed[np.isposinf(obj)] = 'Infinity'\n            transformed[np.isneginf(obj)] = '-Infinity'\n            return transformed.tolist()\n\n    def transform_python_types(self, obj):\n        \"\"\"handle special scalars, default to default json encoder\n        \"\"\"\n        # Pandas Timestamp\n        if is_pandas and isinstance(obj, pd.tslib.Timestamp):\n            return obj.value / millifactor  #nanosecond to millisecond\n        elif np.issubdtype(type(obj), np.float):\n            return float(obj)\n        elif np.issubdtype(type(obj), np.int):\n            return int(obj)\n        elif np.issubdtype(type(obj), np.bool_):\n            return bool(obj)\n        # Datetime, Date\n        elif isinstance(obj, (dt.datetime, dt.date)):\n            return calendar.timegm(obj.timetuple()) * 1000.\n        # Numpy datetime64\n        elif isinstance(obj, np.datetime64):\n            epoch_delta = obj - np.datetime64('1970-01-01T00:00:00Z')\n            return (epoch_delta / np.timedelta64(1, 'ms'))\n        # Time\n        elif isinstance(obj, dt.time):\n            return (obj.hour*3600 + obj.minute*60 + obj.second)*1000 + obj.microsecond / 1000.\n        elif is_dateutil and isinstance(obj, relativedelta):\n            return dict(years=obj.years, months=obj.months, days=obj.days, hours=obj.hours,\n                minutes=obj.minutes, seconds=obj.seconds, microseconds=obj.microseconds)\n        # Decimal\n        elif isinstance(obj, decimal.Decimal):\n            return float(obj)\n        else:\n            return super(BokehJSONEncoder, self).default(obj)\n\n    def default(self, obj):\n        #argh! local import!\n        from .plot_object import PlotObject\n        from .properties import HasProps\n        from .colors import Color\n        ## array types\n        if is_pandas and isinstance(obj, (pd.Series, pd.Index)):\n            return self.transform_series(obj)\n        elif isinstance(obj, np.ndarray):\n            return self.transform_array(obj)\n        elif isinstance(obj, PlotObject):\n            return obj.ref\n        elif isinstance(obj, HasProps):\n            return obj.changed_properties_with_values()\n        elif isinstance(obj, Color):\n            return obj.to_css()\n        else:\n            return self.transform_python_types(obj)\n\ndef serialize_json(obj, encoder=BokehJSONEncoder, **kwargs):\n    if settings.pretty(False):\n        kwargs[\"indent\"] = 4\n    return json.dumps(obj, cls=encoder, **kwargs)\n\ndeserialize_json = json.loads\n\nserialize_web = serialize_json\n\ndeserialize_web = deserialize_json\n\ndef status_obj(status):\n    return {'msgtype': 'status',\n            'status': status}\n\ndef error_obj(error_msg):\n    return {\n        'msgtype': 'error',\n        'error_msg': error_msg}\n", "path": "bokeh/protocol.py"}]}