Repository: bokeh/bokeh

Issue:
Patch bug: patch slices must have positive (start, stop, step) values, got slice(0, 200, 50)
In [.../0.12.6/examples/howto/patch_app.py](https://github.com/bokeh/bokeh/blob/0.12.6/examples/howto/patch_app.py) at line 59, changing `slice(50, 151, 20)` to `slice(0, 200, 50)`generates the following error: `ValueError('Patch slices must have positive (start, stop, step) values, got slice(0, 200, 50)',)`. 

As far as I know, `0` is supposed to be a valid slice index. Only negative values are prohibited. 


Discussion:
right that might be worth changing, for now I would imagine `slice(None, 200, 50)` might work
right, `slice(None, 200, 50)` works
marking for `0.12.8` as there is a workaround (though if you'd like to look at it I am happy to advise)

Resolving patch:
diff --git a/bokeh/models/sources.py b/bokeh/models/sources.py
--- a/bokeh/models/sources.py
+++ b/bokeh/models/sources.py
@@ -589,10 +589,10 @@ def patch(self, patches, setter=None):
 def _check_slice(s):
     if (s.start is not None and s.stop is not None and s.start > s.stop):
         raise ValueError("Patch slices must have start < end, got %s" % s)
-    if (s.start is not None and s.start < 1) or \
-       (s.stop  is not None and s.stop < 1) or \
-       (s.step  is not None and s.step < 1):
-        raise ValueError("Patch slices must have positive (start, stop, step) values, got %s" % s)
+    if (s.start is not None and s.start < 0) or \
+       (s.stop  is not None and s.stop < 0) or \
+       (s.step  is not None and s.step < 0):
+        raise ValueError("Patch slices must have non-negative (start, stop, step) values, got %s" % s)
 
 class CDSView(Model):
     ''' A view into a ColumnDataSource that represents a row-wise subset.


Test patch:
diff --git a/bokeh/models/tests/test_sources.py b/bokeh/models/tests/test_sources.py
--- a/bokeh/models/tests/test_sources.py
+++ b/bokeh/models/tests/test_sources.py
@@ -390,7 +390,7 @@ def test_patch_bad_slice_indices(self):
         self.assertEqual(str(cm.exception), "Patch slices must have start < end, got slice(10, 1, None)")
         with self.assertRaises(ValueError) as cm:
             ds.patch(dict(a=[(slice(None, 10, -1), list(range(10)))]))
-        self.assertEqual(str(cm.exception), "Patch slices must have positive (start, stop, step) values, got slice(None, 10, -1)")
+        self.assertEqual(str(cm.exception), "Patch slices must have non-negative (start, stop, step) values, got slice(None, 10, -1)")
         with self.assertRaises(ValueError) as cm:
             ds.patch(dict(a=[(slice(10, 1, 1), list(range(10)))]))
         self.assertEqual(str(cm.exception), "Patch slices must have start < end, got slice(10, 1, 1)")
@@ -399,7 +399,7 @@ def test_patch_bad_slice_indices(self):
         self.assertEqual(str(cm.exception), "Patch slices must have start < end, got slice(10, 1, -1)")
         with self.assertRaises(ValueError) as cm:
             ds.patch(dict(a=[(slice(1, 10, -1), list(range(10)))]))
-        self.assertEqual(str(cm.exception), "Patch slices must have positive (start, stop, step) values, got slice(1, 10, -1)")
+        self.assertEqual(str(cm.exception), "Patch slices must have non-negative (start, stop, step) values, got slice(1, 10, -1)")
 
 
     def test_patch_good_slice_indices(self):
@@ -411,9 +411,9 @@ def mock(*args, **kw):
             stuff['args'] = args
             stuff['kw'] = kw
         ds.data._patch = mock
-        ds.patch(dict(a=[(slice(2), [100, 101]), (slice(3, 5), [100, 101])], b=[(slice(None, None, 2), [100, 101, 102])]), mock_setter)
+        ds.patch(dict(a=[(slice(2), [100, 101]), (slice(3, 5), [100, 101])], b=[(slice(0, None, 2), [100, 101, 102])]), mock_setter)
         self.assertEqual(stuff['args'],
-            ("doc", ds, dict(a=[(slice(2), [100, 101]), (slice(3, 5), [100, 101])], b=[(slice(None, None, 2), [100, 101, 102])]), mock_setter)
+            ("doc", ds, dict(a=[(slice(2), [100, 101]), (slice(3, 5), [100, 101])], b=[(slice(0, None, 2), [100, 101, 102])]), mock_setter)
         )
         self.assertEqual(stuff['kw'], {})