Repository: ManiacalLabs/BiblioPixel
Pull request #1013 (2018-10-14 12:49:48)

Legacy palettes
Quick way for old BPA animations to use new-style palettes.


Patch:
diff --git a/bibliopixel/animation/animation.py b/bibliopixel/animation/animation.py
index 0cde915..6b911ea 100644
--- a/bibliopixel/animation/animation.py
+++ b/bibliopixel/animation/animation.py
@@ -3,6 +3,8 @@ from . import adaptor
 from . runner import Runner, STATE
 from .. util import deprecated, log
 from .. util.colors import palettes
+from .. util.colors.legacy_palette import pop_legacy_palette
+
 from .. util.threads.animation_threading import AnimationThreading
 from .. project import attributes, fields
 
@@ -35,7 +37,10 @@ class Animation(object):
         a.data = data
         return a
 
-    def __init__(self, layout, *, preclear=True, palette=None, **kwds):
+    def __init__(self, layout, *, preclear=True, **kwds):
+        self.palette = pop_legacy_palette(kwds)
+        self.palette.length = layout.numLEDs
+
         attributes.set_reserved(self, 'animation', **kwds)
         self.layout = layout
         assert layout
@@ -47,8 +52,6 @@ class Animation(object):
         self.runner = None
         self.time = time.time
         self.preframe_callbacks = []
-        self.palette = palette or palettes.get()
-        self.palette.length = layout.numLEDs
 
     def set_project(self, project):
         self.project = project
diff --git a/bibliopixel/project/fields.py b/bibliopixel/project/fields.py
index 22bd21f..ede5c35 100644
--- a/bibliopixel/project/fields.py
+++ b/bibliopixel/project/fields.py
@@ -8,6 +8,8 @@ FIELD_TYPES = {
     'c_order': channel_order,
     'channel_order': channel_order,
     'color': color,
+    'color1': color,
+    'color2': color,
     'colors': colors,
     'count': int_name,
     'duration': duration,
@@ -16,6 +18,8 @@ FIELD_TYPES = {
     'i': int_name,
     'ledtype': ledtype,
     'num': int_name,
+    'offColor': color,
+    'onColor': color,
     'palette': colors,
     'spi_interface': spi_interface,
     'time': duration,
diff --git a/bibliopixel/util/colors/legacy_palette.py b/bibliopixel/util/colors/legacy_palette.py
new file mode 100644
index 0000000..a2ae0b4
--- /dev/null
+++ b/bibliopixel/util/colors/legacy_palette.py
@@ -0,0 +1,43 @@
+from . import make, palettes
+from . names import COLORS
+
+LEGACY_FIELDS = (
+    ('color',),
+    ('color1', 'color2'),
+    ('onColor', 'offColor'),
+    ('colors',),
+    ('palette',),
+)
+
+
+def pop_legacy_palette(kwds):
+    """
+    Older animations in BPA and other areas use all sorts of different names for
+    what we are now representing with palettes.
+
+    This function mutates a kwds dictionary to remove these legacy fields and
+    extract a palette from it, which it returns.
+    """
+
+    cases = []
+    for fields in LEGACY_FIELDS:
+        if any(f in kwds for f in fields):
+            cases.append(fields)
+
+    if not cases:
+        return palettes.get()
+
+    if len(cases) > 1:
+        raise ValueError('Cannot set all of ' + ', '.join(sum(cases, [])))
+
+    first, *rest = cases[0]
+
+    a = kwds.pop(first, COLORS.Red)
+    if first == 'color':
+        return make.colors((a,))
+
+    if not rest:
+        return a
+
+    b = kwds.pop(rest[0], COLORS.Black)
+    return make.colors((a, b))
diff --git a/bibliopixel/util/colors/palette.py b/bibliopixel/util/colors/palette.py
index dc4acc4..a6536ea 100644
--- a/bibliopixel/util/colors/palette.py
+++ b/bibliopixel/util/colors/palette.py
@@ -112,3 +112,9 @@ class Palette(list):
         dr, dg, db = r2 - r1, g2 - g1, b2 - b1
 
         return r1 + fade * dr, g1 + fade * dg, b1 + fade * db
+
+    def __eq__(self, other):
+        return super().__eq__(other) and vars(self) == vars(other)
+
+    def __ne__(self, other):
+        return not (self == other)
diff --git a/projects/02-circle.yml b/projects/02-circle.yml
index 174a936..bac8083 100644
--- a/projects/02-circle.yml
+++ b/projects/02-circle.yml
@@ -8,15 +8,17 @@ layout:
 
 run:
   fps: 30
-  seconds: 12
+  seconds: 26
 
 aliases:
   bpa: BiblioPixelAnimations.circle
 
-
 animation:
   typename: sequence
+  length: 2
   animations:
+    - $bpa.fill.CircleFill
+    - $bpa.fill.CircleFillRainbow
     - $bpa.arc_clock
     - $bpa.arc_rotate
     - $bpa.bloom.CircleBloom


Test patch:
diff --git a/test/bibliopixel/util/colors/legacy_palette_test.py b/test/bibliopixel/util/colors/legacy_palette_test.py
new file mode 100644
index 0000000..02e873a
--- /dev/null
+++ b/test/bibliopixel/util/colors/legacy_palette_test.py
@@ -0,0 +1,31 @@
+import collections, unittest
+from bibliopixel.util.colors import palette, palettes
+from bibliopixel.colors import COLORS
+from bibliopixel.util.colors.legacy_palette import pop_legacy_palette
+
+
+class LegacyPaletteTest(unittest.TestCase):
+    def test_simple(self):
+        kwds = {}
+        pal = pop_legacy_palette(kwds)
+        self.assertFalse(kwds)
+        self.assertEqual(pal, palettes.get())
+
+    def test_palette(self):
+        pal = 'wombat'
+        for k in 'palette', 'colors':
+            kwds = {k: pal, 'other': 'stuff'}
+            self.assertIs(pal, pop_legacy_palette(kwds))
+            self.assertEqual(kwds, {'other': 'stuff'})
+
+    def test_color(self):
+        kwds = {'color': COLORS.yellow, 'other': 'stuff'}
+        pal = pop_legacy_palette(kwds)
+        self.assertEqual(kwds, {'other': 'stuff'})
+        self.assertEqual(pal, palette.Palette([COLORS.yellow]))
+
+    def test_color(self):
+        kwds = {'offColor': 'lime', 'other': 'stuff'}
+        pal = pop_legacy_palette(kwds)
+        self.assertEqual(kwds, {'other': 'stuff'})
+        self.assertEqual(pal, palette.Palette([COLORS.red, COLORS.lime]))
diff --git a/test/bibliopixel/util/colors/palette_test.py b/test/bibliopixel/util/colors/palette_test.py
index 1621076..360d7dd 100644
--- a/test/bibliopixel/util/colors/palette_test.py
+++ b/test/bibliopixel/util/colors/palette_test.py
@@ -203,3 +203,19 @@ class PaletteTest(unittest.TestCase):
         p.length = 256
         result = [p.get(32 * i) for i in range(10)]
         self.assertEqual(expected, result)
+
+    def test_equality(self):
+        colors = [Red, Green, Blue, White]
+        p = Palette(colors, autoscale=True)
+        q = Palette(colors, autoscale=True)
+
+        self.assertEqual(p, q)
+        self.assertFalse(p != q)
+
+        r = Palette(colors)
+        self.assertNotEqual(p, r)
+        self.assertFalse(p == r)
+
+        s = Palette(colors, serpentine=True)
+        t = Palette(colors[:3], serpentine=True)
+        self.assertNotEqual(s, t)