# Buggy code
def add_periodic_callback(
    self, callback, period=500, count=None, timeout=None, start=True
):
    """
    Schedules a periodic callback to be run at an interval set by
    the period. Returns a PeriodicCallback object with the option
    to stop and start the callback.

    Arguments
    ---------
    callback: callable
      Callable function to be executed at periodic interval.
    period: int
      Interval in milliseconds at which callback will be executed.
    count: int
      Maximum number of times callback will be invoked.
    timeout: int
      Timeout in seconds when the callback should be stopped.
    start: boolean (default=True)
      Whether to start callback immediately.

    Returns
    -------
    Return a PeriodicCallback object with start and stop methods.
    """
    cb = PeriodicCallback(
        callback=callback, period=period, count=count, timeout=timeout
    )
    if start:
        cb.start()
    return cb


# Traceback (RuntimeError)
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-15-da8b0df4fb70> in <module>
----> 1 color_mapper.update(high=100)

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/has_props.py in update(self, **kwargs)
368         '''
369         for k,v in kwargs.items():
--> 370             setattr(self, k, v)
371
372     def update_from_json(self, json_attributes, models=None, setter=None):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/has_props.py in __setattr__(self, name, value)
272
273         if name in props or (descriptor is not None and descriptor.fset is not None):
--> 274             super().__setattr__(name, value)
275         else:
276             matches, text = difflib.get_close_matches(name.lower(), props), "similar"

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/property/descriptors.py in __set__(self, obj, value, setter)
537             raise RuntimeError("%s.%s is a readonly property" % (obj.__class__.__name__, self.name))
538
--> 539         self._internal_set(obj, value, setter=setter)
540
541     def __delete__(self, obj):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/property/descriptors.py in _internal_set(self, obj, value, hint, setter)
761
762         old = self.__get__(obj, obj.__class__)
--> 763         self._real_set(obj, old, value, hint=hint, setter=setter)
764
765     def _real_set(self, obj, old, value, hint=None, setter=None):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/property/descriptors.py in _real_set(self, obj, old, value, hint, setter)
830
831         # for notification purposes, "old" should be the logical old
--> 832         self._trigger(obj, old, value, hint=hint, setter=setter)
833
834     # called when a container is mutated "behind our back" and

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/core/property/descriptors.py in _trigger(self, obj, old, value, hint, setter)
907         '''
908         if hasattr(obj, 'trigger'):
--> 909             obj.trigger(self.name, old, value, hint, setter)
910
911

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/model.py in trigger(self, attr, old, new, hint, setter)
659                     self._document._invalidate_all_models()
660         # chain up to invoke callbacks
--> 661         super().trigger(attr, old, new, hint=hint, setter=setter)
662
663     def _attach_document(self, doc):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/util/callback_manager.py in trigger(self, attr, old, new, hint, setter)
155                     callback(attr, old, new)
156         if hasattr(self, '_document') and self._document is not None:
--> 157             self._document._notify_change(self, attr, old, new, hint, setter, invoke)
158         else:
159             invoke()

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/document.py in _notify_change(self, model, attr, old, new, hint, setter, callback_invoker)
1040
1041         event = ModelChangedEvent(self, model, attr, old, new, serializable_new, hint, setter, callback_invoker)
-> 1042         self._trigger_on_change(event)
1043
1044     def _push_all_models_freeze(self):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/document.py in _trigger_on_change(self, event)
1135             for cb in self._callbacks.values():
1136                 cb(event)
-> 1137         self._with_self_as_curdoc(invoke_callbacks)
1138
1139     def _with_self_as_curdoc(self, f):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/document.py in _with_self_as_curdoc(self, f)
1148             else:
1149                 set_curdoc(self)
-> 1150             return f()
1151         finally:
1152             set_curdoc(old_doc)

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/document.py in invoke_callbacks()
1134         def invoke_callbacks():
1135             for cb in self._callbacks.values():
-> 1136                 cb(event)
1137         self._with_self_as_curdoc(invoke_callbacks)
1138

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/document.py in <lambda>(event)
702     def on_change_dispatch_to(self, receiver):
703         if not receiver in self._callbacks:
--> 704             self._callbacks[receiver] = lambda event: event.dispatch(receiver)
705
706     def on_session_destroyed(self, *callbacks):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/events.py in dispatch(self, receiver)
267
268         '''
--> 269         super().dispatch(receiver)
270         if hasattr(receiver, '_document_model_changed'):
271             receiver._document_model_changed(self)

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/document/events.py in dispatch(self, receiver)
122         super().dispatch(receiver)
123         if hasattr(receiver, '_document_patched'):
--> 124             receiver._document_patched(self)
125
126     def generate(self, references, buffers):

~/miniconda3/envs/PyX/lib/python3.7/site-packages/bokeh/server/session.py in _document_patched(self, event)
216
217         if self._pending_writes is None:
--> 218             raise RuntimeError("_pending_writes should be non-None when we have a document lock, and we should have the lock when the document changes")
219
220         # TODO (havocp): our "change sync" protocol is flawed because if both

RuntimeError: _pending_writes should be non-None when we have a document lock, and we should have the lock when the document changes

# Fixed code
def add_periodic_callback(
    self, callback, period=500, count=None, timeout=None, start=True
):
    """
    Schedules a periodic callback to be run at an interval set by
    the period. Returns a PeriodicCallback object with the option
    to stop and start the callback.

    Arguments
    ---------
    callback: callable
      Callable function to be executed at periodic interval.
    period: int
      Interval in milliseconds at which callback will be executed.
    count: int
      Maximum number of times callback will be invoked.
    timeout: int
      Timeout in seconds when the callback should be stopped.
    start: boolean (default=True)
      Whether to start callback immediately.

    Returns
    -------
    Return a PeriodicCallback object with start and stop methods.
    """
    self.param.warning(
        "Calling add_periodic_callback on a Panel component is "
        "deprecated and will be removed in the next minor release. "
        "Use the pn.state.add_periodic_callback API instead."
    )
    cb = PeriodicCallback(
        callback=callback, period=period, count=count, timeout=timeout
    )
    if start:
        cb.start()
    return cb