prompt: 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()
  
  ```
  
golden_diff: 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)
  
verification_info: {"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"}]}