DataSource.patch triggering TypeError: 'tuple' object does not support item assignment

I have working code old older Bokeh/Python versions and am trying to update using Bokeh 2.2.3 and Python 3.8.

When I try to patch a DataSource i get the error:

TypeError: ‘tuple’ object does not support item assignment

Please see sample below…

ceokey = ‘CTX:David Reeves’
print(type(ds))
idx = sectorsource.data[‘ceo’].index(ceokey)

patches = {‘color’ : }
save_colour = sectorsource.data[‘color’][idx]

patches[‘color’].append((idx, ‘#471568’))
print(‘Patches:’,patches[‘color’])

ds.patch(patches)

This trips as follows:…

TypeError Traceback (most recent call last)
in
9 print(‘Patches:’,patches[‘color’])
10
—> 11 ds.patch(patches)

~/opt/anaconda3/lib/python3.8/site-packages/bokeh/models/sources.py in patch(self, patches, setter)
682 raise ValueError(“Invalid patch index: %s” % ind)
683
–> 684 self.data._patch(self.document, self, patches, setter)
685
686 class CDSView(Model):

~/opt/anaconda3/lib/python3.8/site-packages/bokeh/core/property/wrappers.py in _patch(self, doc, source, patches, setter)
461 for ind, value in patch:
462 if isinstance(ind, (int, slice)):
–> 463 self[name][ind] = value
464 else:
465 shape = self[name][ind[0]][tuple(ind[1:])].shape

TypeError: ‘tuple’ object does not support item assignment

Has anyone else seen this?

Just for giggles I made the following (very clunky) change to wrapper.py at line 462:

            if isinstance(ind, (int, slice)):
                as_list = list(self[name])
                #self[name][ind] = value
                as_list[ind] = value
                self[name] = tuple(as_list)

which seemed to fix the problem - I appreciate this may a very bad thing but just putting it out there…

The purpose of patch is to efficiently update without copying. If you want to patch, then your columns must be mutable (i.e. an array or list, not a tuple) If it ever worked with a tuple in the past, that was a bug.

Bryan,

The ColumnDataSournce is based ona dictionary of lists…

grp_list = [x for x in df['ceokey'].unique()]
xs = [df.loc[df['ceokey'] == i].Years for i in grp_list]
ys = [df.loc[df['ceokey'] == i].Relative for i in grp_list]
    
source = ColumnDataSource(data=dict(
    x = xs,
    y = ys,
    color = viridis(len(grp_list)),
    ceo = grp_list
    ))

Pretty standard stuff. The tach list is a single tuple (index, value) but that is used to do the patch and complies with the docs - am puzzled why it is now deemed to be updating a tuple rather than a lit item.

Bryan

I suspect I upgraded from older version of Bokeh along the way - viridis used to return a list, now returns a tuple.

If I listify the returned tuple before loading into the ColumnDataSource that should be fine.

@andrew.waites all the palettes were indeed converted to be tuples, in order to be able to discard a bunch of hacky code that mutable palettes had necessitated. I’d say it’s pretty unusual to set a palette as a CDS column value (palettes are usually inputs to colormappers) so listifying is the appropriate solution on he user side in those rare cases.