Repository: ManiacalLabs/BiblioPixel
Pull request #1086 (2018-11-29 14:05:01)

Set Animation.top_level correctly
This is a much better way of doing it.

I also audited the code to see if this bug appears elsewhere - if there are any other features that are only enabled by the project.  It turns out that it's only Controls that are enabled - and Controls make no sense without a project, since they relying on using Addresses.

I have to go out for a bit, so I don't have a chance to test this with the hardwarez this second... but I will before I pull it.


Patch:
diff --git a/bibliopixel/animation/animation.py b/bibliopixel/animation/animation.py
index 2b85a63..0371686 100644
--- a/bibliopixel/animation/animation.py
+++ b/bibliopixel/animation/animation.py
@@ -9,7 +9,7 @@ class Animation(object):
     free_run = False
     pre_recursion = fields.default_converter
     subframes = 1
-    top_level = False
+    top_level = True
 
     if deprecated.allowed():
         _step = 0
diff --git a/bibliopixel/animation/collection.py b/bibliopixel/animation/collection.py
index 09526c2..9d2917b 100644
--- a/bibliopixel/animation/collection.py
+++ b/bibliopixel/animation/collection.py
@@ -72,6 +72,8 @@ class Collection(animation.Animation):
         super().__init__(layout, **kwds)
         self.animations = _AnimationList(animations or [])
         self.internal_delay = 0  # never wait
+        for a in self.animations:
+            a.top_level = False
 
     # Override to handle all the animations
     def cleanup(self, clean_layout=True):
diff --git a/bibliopixel/layout/matrix.py b/bibliopixel/layout/matrix.py
index 6fc8eb1..0e8463e 100644
--- a/bibliopixel/layout/matrix.py
+++ b/bibliopixel/layout/matrix.py
@@ -45,8 +45,8 @@ class Matrix(MultiLayout):
         if self.rotation != rot_mod:
             log.warning(ROTATION_WARNING, rotation, self.rotation)
 
-        self.width = width or getattr(self.drivers[0], 'width') or 32
-        self.height = height or getattr(self.drivers[0], 'height') or 32
+        self.width = width or getattr(self.drivers[0], 'width') or 0
+        self.height = height or getattr(self.drivers[0], 'height') or 0
         self.vert_flip = vert_flip
         self.y_flip = y_flip
         self.serpentine = serpentine
@@ -54,7 +54,7 @@ class Matrix(MultiLayout):
         pw, ph = self.pixelSize
 
         # If both are 0, try to assume it's a square display.
-        if self.width == 0 and self.height == 0:
+        if not (self.width or self.height):
             square = int(math.sqrt(self.numLEDs))
             if (square * square) == self.numLEDs:
                 self.width = self.height = square
diff --git a/bibliopixel/project/load.py b/bibliopixel/project/load.py
index 627bc70..2d3d40b 100644
--- a/bibliopixel/project/load.py
+++ b/bibliopixel/project/load.py
@@ -1,5 +1,5 @@
 from . import aliases
-import loady, os
+import loady, os, platform
 from .. util import data_file, log
 
 guess_name = loady.importer.guess_name
@@ -26,10 +26,7 @@ def module(name, python_path=None):
 
 
 def extender(path):
-    parts = [os.getcwd()]
-    if path:
-        parts.extend(path.split(':'))
-
+    parts = [os.getcwd()] + _split_path(path)
     missing = [p for p in parts if not os.path.exists(p)]
     if missing:
         msg = ('This "path" entry does not exist' if len(missing) == 1
@@ -47,3 +44,15 @@ def load_if_filename(s):
             s = os.path.join(os.path.dirname(ROOT_FILE), s)
 
         return data_file.load(s)
+
+
+def _split_path(path):
+    if not path:
+        return []
+
+    p = path.split(';')
+    if platform.system() == 'Windows':
+        return p
+
+    # Also split on : for backwards compatibility
+    return [j for i in p for j in i.split(':')]
diff --git a/bibliopixel/project/project.py b/bibliopixel/project/project.py
index 3fa3369..db31155 100644
--- a/bibliopixel/project/project.py
+++ b/bibliopixel/project/project.py
@@ -56,7 +56,6 @@ class Project:
             self.layout = self.construct_child('layout', **layout)
 
         self.animation = create(animation, 'animation')
-        self.animation.top_level = True
         self.running = False
         self.clock = time
 


Test patch:
diff --git a/test/bibliopixel/project/load_test.py b/test/bibliopixel/project/load_test.py
new file mode 100644
index 0000000..03381e2
--- /dev/null
+++ b/test/bibliopixel/project/load_test.py
@@ -0,0 +1,21 @@
+import unittest
+from unittest.mock import patch
+from bibliopixel.project import load
+
+
+class LoadTest(unittest.TestCase):
+    @patch('platform.system', autospec=True)
+    def test_split_path(self, platform):
+        platform.return_value = 'Darwin'
+        to_split = 'abc;def:ghi;jkl:mn'
+        actual = load._split_path(to_split)
+        expected = ['abc', 'def', 'ghi', 'jkl', 'mn']
+        self.assertEqual(actual, expected)
+
+    @patch('platform.system', autospec=True)
+    def test_split_path(self, platform):
+        platform.return_value = 'Windows'
+        to_split = 'abc;def:ghi;jkl:mn'
+        actual = load._split_path(to_split)
+        expected = ['abc', 'def:ghi', 'jkl:mn']
+        self.assertEqual(actual, expected)
diff --git a/test/bibliopixel/project/project_test.py b/test/bibliopixel/project/project_test.py
index 387adeb..1f9aadb 100644
--- a/test/bibliopixel/project/project_test.py
+++ b/test/bibliopixel/project/project_test.py
@@ -55,9 +55,6 @@ class ProjectTest(unittest.TestCase):
     def test_multi(self):
         animation = make(PROJECT_MULTI)
         k = [d._kwds for d in animation.layout.drivers]
-        self.assertEqual(k[0]['width'], 128)
-        self.assertEqual(k[1]['width'], 128)
-        self.assertEqual(k[2]['width'], 128)
         self.assertEqual(k[0]['device_id'], 10)
         self.assertEqual(k[1]['device_id'], 11)
         self.assertEqual(k[2]['device_id'], 12)
@@ -159,8 +156,6 @@ PROJECT_MULTI = """
 {
     "driver": {
         "typename": "dummy",
-        "width": 128,
-        "height": 32,
         "num": 4096
     },
 
@@ -173,6 +168,7 @@ PROJECT_MULTI = """
     "layout": {
         "typename": "matrix",
         "width": 128,
+        "height": 32,
         "gen_coord_map": [
             {
               "dx": 32,