nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: vuejs/composition-api
Pull request #839 (2021-11-01 10:23:36)

fix(types): defineComponent object format with no props type

see https://github.com/vuejs/vue-next/blob/140f08991727d7c15db907eea5a101979fe390b2/packages/runtime-core/src/apiDefineComponent.ts#L95-L120

```ts
// overload 2: object format with no props
// (uses user defined props interface)
// return type is for Vetur and TSX support
export function defineComponent<
  Props = {},
  RawBindings = {},
  D = {},
  C extends ComputedOptions = {},
  M extends MethodOptions = {},
  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  E extends EmitsOptions = EmitsOptions,
  EE extends string = string
>(
  options: ComponentOptionsWithoutProps<
    Props,
    RawBindings,
    D,
    C,
    M,
    Mixin,
    Extends,
    E,
    EE
  >
): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>
```

Vue 3 use `{}` rather than `unknown` when object format with no props.



Patch:
diff --git a/src/component/componentOptions.ts b/src/component/componentOptions.ts
index 2108345..1030f30 100644
--- a/src/component/componentOptions.ts
+++ b/src/component/componentOptions.ts
@@ -88,7 +88,7 @@ export type ComponentOptionsWithArrayProps<
 } & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
 
 export type ComponentOptionsWithoutProps<
-  Props = unknown,
+  Props = {},
   RawBindings = Data,
   D = Data,
   C extends ComputedOptions = {},
diff --git a/src/component/defineComponent.ts b/src/component/defineComponent.ts
index 6a904f2..3635914 100644
--- a/src/component/defineComponent.ts
+++ b/src/component/defineComponent.ts
@@ -17,8 +17,8 @@ export function defineComponent<
   C extends ComputedOptions = {},
   M extends MethodOptions = {}
 >(
-  options: ComponentOptionsWithoutProps<unknown, RawBindings, D, C, M>
-): VueProxy<unknown, RawBindings, D, C, M>
+  options: ComponentOptionsWithoutProps<{}, RawBindings, D, C, M>
+): VueProxy<{}, RawBindings, D, C, M>
 
 // overload 2: object format with array props declaration
 // props inferred as { [key in PropNames]?: any }


Test patch:
diff --git a/test/types/defineComponent.spec.ts b/test/types/defineComponent.spec.ts
index c41e08b..57b58db 100644
--- a/test/types/defineComponent.spec.ts
+++ b/test/types/defineComponent.spec.ts
@@ -137,7 +137,7 @@ describe('defineComponent', () => {
     const App = defineComponent({
       setup(props, ctx) {
         isTypeEqual<SetupContext, typeof ctx>(true)
-        isTypeEqual<unknown, typeof props>(true)
+        isTypeEqual<{}, typeof props>(true)
         return () => null
       },
     })
Repository: vuejs/composition-api
Pull request #859 (2021-11-24 14:58:12)

fix(toRef): issue #855
Proposal to fix issue #855 


Patch:
diff --git a/src/reactivity/ref.ts b/src/reactivity/ref.ts
index 87b0ad7..a7a73a4 100644
--- a/src/reactivity/ref.ts
+++ b/src/reactivity/ref.ts
@@ -2,6 +2,7 @@ import { RefKey } from '../utils/symbols'
 import { proxy, isPlainObject, warn, def } from '../utils'
 import { reactive, isReactive, shallowReactive } from './reactive'
 import { readonlySet } from '../utils/sets'
+import { set } from './set'
 
 declare const _refBrand: unique symbol
 export interface Ref<T = any> {
@@ -154,6 +155,7 @@ export function toRef<T extends object, K extends keyof T>(
   object: T,
   key: K
 ): Ref<T[K]> {
+  if (!(key in object)) set(object, key, undefined)
   const v = object[key]
   if (isRef<T[K]>(v)) return v
 


Test patch:
diff --git a/test/apis/computed.spec.js b/test/apis/computed.spec.js
index af0ce83..da7c830 100644
--- a/test/apis/computed.spec.js
+++ b/test/apis/computed.spec.js
@@ -1,5 +1,12 @@
 const Vue = require('vue/dist/vue.common.js')
-const { ref, computed, isReadonly, reactive, isRef } = require('../../src')
+const {
+  ref,
+  computed,
+  isReadonly,
+  reactive,
+  isRef,
+  toRef,
+} = require('../../src')
 
 describe('Hooks computed', () => {
   beforeEach(() => {
@@ -195,6 +202,26 @@ describe('Hooks computed', () => {
     expect(app.$children[1].example).toBe('B')
   })
 
+  it('should watch a reactive property created via toRef', (done) => {
+    const spy = jest.fn()
+    const vm = new Vue({
+      setup() {
+        const a = reactive({})
+        const b = toRef(a, 'b')
+
+        return {
+          a,
+          b,
+        }
+      },
+    })
+    vm.$watch('b', spy)
+    vm.b = 2
+    waitForUpdate(() => {
+      expect(spy).toHaveBeenCalledWith(2, undefined)
+    }).then(done)
+  })
+
   it('should be readonly', () => {
     let a = { a: 1 }
     const x = computed(() => a)
Repository: vue-a11y/eslint-plugin-vuejs-accessibility
Pull request #61 (2020-09-08 16:59:18)

Handle conditional expressions in :is
Solves #60 ish


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6086b0e..37ed095 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ## [Unreleased]
 
+### Changed
+
+- When you pass a conditional expression into an `:is`, then `getElementType` would not be able to handle it. It doesn't truly handle it now, as it just ends up returning `null` for the value of the `:is` expression, but at least now it doesn't break.
+
 ## [0.5.0] - 2020-09-05
 
 ### Changed
diff --git a/src/utils/getAttributeValue.js b/src/utils/getAttributeValue.js
index 0d3299f..5a19827 100644
--- a/src/utils/getAttributeValue.js
+++ b/src/utils/getAttributeValue.js
@@ -10,7 +10,16 @@ const getAttributeValue = (node) => {
   }
 
   if (key.name.name === "bind" && value.expression) {
-    return value.type === "Literal" ? value.expression.value : value.expression;
+    // <div :height="100" />
+    if (value.expression.type === "Literal") {
+      return value.expression.value;
+    }
+
+    // TODO we're effectively using this as just a placeholder to let rules know
+    // that a value has been passed in for this attribute. We should replace
+    // this with a stronger API to either explicitly handel all of the different
+    // types of values or just return a special symbol or something else.
+    return value.expression;
   }
 
   return null;
diff --git a/src/utils/getElementType.js b/src/utils/getElementType.js
index f376b38..e588557 100644
--- a/src/utils/getElementType.js
+++ b/src/utils/getElementType.js
@@ -1,7 +1,17 @@
 const getElementAttributeValue = require("./getElementAttributeValue");
 const makeKebabCase = require("./makeKebabCase");
 
-const getElementType = (node) =>
-  makeKebabCase(getElementAttributeValue(node, "is") || node.rawName);
+const getElementType = (node) => {
+  let is = getElementAttributeValue(node, "is");
+
+  // If we could not parse the `is` value into a simple literal, we're going to
+  // have to ignore it because we're not smart enough to handle multiple values
+  // yet.
+  if (typeof is !== "string") {
+    is = null;
+  }
+
+  return makeKebabCase(is || node.rawName);
+};
 
 module.exports = getElementType;


Test patch:
diff --git a/src/rules/__tests__/interactive-supports-focus.test.js b/src/rules/__tests__/interactive-supports-focus.test.js
index 204ec9d..3895385 100644
--- a/src/rules/__tests__/interactive-supports-focus.test.js
+++ b/src/rules/__tests__/interactive-supports-focus.test.js
@@ -60,7 +60,8 @@ makeRuleTester("interactive-supports-focus", rule, {
     "<div role='textbox' tabindex='0' @click='void 0' />",
     "<div role='textbox' aria-disabled='true' @click='void 0' />",
     "<Foo.Bar @click='void 0' aria-hidden='false' />",
-    "<Input @click='void 0' type='hidden' />"
+    "<Input @click='void 0' type='hidden' />",
+    `<component role="button" :is="foo ? 'a' : 'button'" />`
   ],
   invalid: [
     ...rule.interactiveRoles.flatMap((role) =>
Repository: ManiacalLabs/BiblioPixel
Pull request #361 (2017-08-12 17:03:03)

Merge in default project dictionaries.

adammhaile: +1

Patch:
diff --git a/bibliopixel/project/aliases.py b/bibliopixel/project/aliases.py
index 560ba2e..6c3e734 100644
--- a/bibliopixel/project/aliases.py
+++ b/bibliopixel/project/aliases.py
@@ -27,9 +27,8 @@ def resolve(value):
         typename, value = value, {}
     else:
         typename = value.get('typename')
-
-    if not typename:
-        raise ValueError('"typename" is not present or empty')
+        if not typename:
+            return value
 
     alias = alias_lists.get_alias(typename, ISOLATE)
 
diff --git a/bibliopixel/project/project.py b/bibliopixel/project/project.py
index 868b003..f83f782 100644
--- a/bibliopixel/project/project.py
+++ b/bibliopixel/project/project.py
@@ -54,15 +54,18 @@ def project_to_animation(desc, default=None):
     default = default or {}
 
     def get(name):
-        return project.pop(name, default.get(name))
+        pr = aliases.resolve(project.pop(name, {}))
+        de = aliases.resolve(default.get(name, {}))
+        return dict(de, **pr)
 
     animation = get('animation')
     driver = get('driver')
-    drivers = get('drivers')
     layout = get('layout')
-    maker = get('maker')
-    path = get('path')
-    run = get('run')
+
+    drivers = project.pop('drivers', [])
+    maker = project.pop('maker', {})
+    path = project.pop('path', default.get('path'))
+    run = project.pop('run', {})
 
     raise_if_unknown(project, 'section', 'project')
 


Test patch:
diff --git a/test/bibliopixel/project/aliases_test.py b/test/bibliopixel/project/aliases_test.py
index 349f046..1e3bd3b 100644
--- a/test/bibliopixel/project/aliases_test.py
+++ b/test/bibliopixel/project/aliases_test.py
@@ -4,8 +4,7 @@ from bibliopixel.project import aliases
 
 class AliasTest(unittest.TestCase):
     def test_empty(self):
-        with self.assertRaises(ValueError):
-            aliases.resolve({})
+        self.assertEqual(aliases.resolve({}), {})
 
     def test_simple(self):
         d = {'typename': 'bibliopixel.layout.circle.Circle'}
Repository: ManiacalLabs/BiblioPixel
Pull request #391 (2017-08-22 19:09:19)

New colors type for projects

adammhaile: Comment was just a question, but I trust it works... merging.

Patch:
diff --git a/bibliopixel/project/types/colors.py b/bibliopixel/project/types/colors.py
new file mode 100644
index 0000000..825c2b5
--- /dev/null
+++ b/bibliopixel/project/types/colors.py
@@ -0,0 +1,22 @@
+import functools
+from . import color
+
+USAGE = """Colors is a list of colors.  Each color can be:
+
+* A list of three numbers: [0, 0, 0] or [255, 0, 255].
+* A single number which represents a brightness/gray level: 0, 255, 127
+* A string:  "red", "yellow", "gold" naming a color from ...colors.COLORS.
+
+All numbers must be in the range [0, 256) - 0 <= x < 256
+"""
+
+
+@functools.singledispatch
+def make(c):
+    raise ValueError("Don't understand type %s" % type(c), USAGE)
+
+
+@make.register(tuple)
+@make.register(list)
+def _(c):
+    return [color.make(i) for i in c]
diff --git a/bibliopixel/project/types/defaults.py b/bibliopixel/project/types/defaults.py
index faf3388..8aa574a 100644
--- a/bibliopixel/project/types/defaults.py
+++ b/bibliopixel/project/types/defaults.py
@@ -1,8 +1,9 @@
-from . import channel_order, color, duration, gamma, ledtype, rotation
+from . import channel_order, color, colors, duration, gamma, ledtype, rotation
 
 FIELD_TYPES = {
     'c_order': channel_order,
     'color': color,
+    'colors': colors,
     'duration': duration,
     'gamma': gamma,
     'ledtype': ledtype,


Test patch:
diff --git a/test/bibliopixel/project/types/colors_test.py b/test/bibliopixel/project/types/colors_test.py
new file mode 100644
index 0000000..9aba350
--- /dev/null
+++ b/test/bibliopixel/project/types/colors_test.py
@@ -0,0 +1,14 @@
+from . base import TypesBaseTest
+from bibliopixel import colors
+
+
+class ColorTypesTest(TypesBaseTest):
+    def test_empty(self):
+        self.make('colors', [], [])
+
+    def test_single(self):
+        self.make('colors', ['red'], [(255, 0, 0)])
+
+    def test_many(self):
+        self.make('colors', ['red', [0, 255, 0], 127],
+                  [(255, 0, 0), (0, 255, 0), (127, 127, 127)])
Repository: ManiacalLabs/BiblioPixel
Pull request #659 (2018-03-11 17:06:32)

Fix crashing bug with projects with dimensions section
Oops.  Luckily I found this before anyone else...!


Patch:
diff --git a/bibliopixel/project/cleanup.py b/bibliopixel/project/cleanup.py
index 7c2fa14..b846176 100644
--- a/bibliopixel/project/cleanup.py
+++ b/bibliopixel/project/cleanup.py
@@ -77,7 +77,7 @@ def cleanup_shape(desc):
     if dimensions:
         util.deprecate.deprecate('Project section "dimensions"')
 
-    shape = desc.pop('shape', dimensions)
+    shape = desc.pop('shape', None) or dimensions
     if not shape:
         return desc
 
@@ -89,7 +89,8 @@ def cleanup_shape(desc):
     except:
         d = list(shape)
 
-    ldesc = construct.to_type_constructor(desc.get('layout') or {})
+    ldesc = construct.to_type_constructor(desc.get('layout') or {},
+                                          python_path='bibliopixel.layout')
     driver = desc['drivers'][0]
 
     if len(d) == 1:
diff --git a/bibliopixel/project/merge.py b/bibliopixel/project/merge.py
index a2c9c6e..fcdf779 100644
--- a/bibliopixel/project/merge.py
+++ b/bibliopixel/project/merge.py
@@ -22,7 +22,7 @@ DEFAULT_PROJECT = collections.OrderedDict((
 PROJECT_SECTIONS = tuple(DEFAULT_PROJECT.keys())
 
 NOT_MERGEABLE = (
-    'controls', 'datatype', 'shape', 'drivers', 'numbers', 'path',
+    'controls', 'datatype', 'dimensions', 'shape', 'drivers', 'numbers', 'path',
     'typename')
 
 SECTION_ISNT_DICT_ERROR = 'Project section "%s" is %s, should be dictionary'


Test patch:
diff --git a/test/bibliopixel/project/project_test.py b/test/bibliopixel/project/project_test.py
index 2bda4b2..acd3936 100644
--- a/test/bibliopixel/project/project_test.py
+++ b/test/bibliopixel/project/project_test.py
@@ -72,11 +72,8 @@ class ProjectTest(unittest.TestCase):
 
 PROJECT = """
 {
-    "driver": {
-        "typename": "dummy",
-        "num": 12
-    },
-
+    "driver": "dummy",
+    "dimensions": 12,
     "layout": "strip",
     "animation": "strip_test",
     "run": {
@@ -89,8 +86,6 @@ PROJECT_TYPES = """
 {
     "driver": {
         "typename": "dummy",
-        "num": 12,
-
         "c_order": "GBR",
         "color": "green",
         "duration": "1 hour, 2 minutes",
@@ -99,6 +94,7 @@ PROJECT_TYPES = """
         "ledtype": "GENERIC"
     },
 
+    "shape": 12,
     "layout": "strip",
     "animation": "strip_test",
     "run": {
Repository: ManiacalLabs/BiblioPixel
Pull request #831 (2018-05-25 13:17:43)

Improve handling of tuple assignment in Address
* A new unit test
* Fix bug with number parsing that testing revealed
* See #830


Patch:
diff --git a/bibliopixel/control/address.py b/bibliopixel/control/address.py
index afa21bf..ed8051e 100644
--- a/bibliopixel/control/address.py
+++ b/bibliopixel/control/address.py
@@ -78,6 +78,8 @@ class Address:
             return
 
         self.name, *assignment = name.split('=', 1)
+        assignment = assignment and assignment[0].strip()
+
         self.name = self.name.strip()
 
         try:
@@ -88,16 +90,25 @@ class Address:
         if not self.segments:
             raise ValueError('Empty Addresses are not allowed')
 
-        if assignment:
-            if not self.segments:
-                raise ValueError('Cannot assign to an empty address')
-            if isinstance(self.segments[-1], Address.Call):
-                raise ValueError('Cannot assign to a call operation')
-            assignment = [s.strip() for s in assignment[0].split(',')]
-            assignment = [int(s) if s.isnumeric() else s for s in assignment]
-            self.assignment = tuple(assignment)
-        else:
+        if not assignment:
             self.assignment = ()
+            return
+
+        if isinstance(self.segments[-1], Address.Call):
+            raise ValueError('Cannot assign to a call operation')
+
+        def number(s):
+            try:
+                return int(s)
+            except ValueError:
+                pass
+            try:
+                return float(s)
+            except ValueError:
+                pass
+            return s
+
+        self.assignment = tuple(number(s) for s in assignment.split(','))
 
     def __bool__(self):
         return bool(self.segments)


Test patch:
diff --git a/test/bibliopixel/control/address_test.py b/test/bibliopixel/control/address_test.py
index ddba904..c323b48 100644
--- a/test/bibliopixel/control/address_test.py
+++ b/test/bibliopixel/control/address_test.py
@@ -108,3 +108,7 @@ class AddressTest(unittest.TestCase):
         self.attr = None
         Address('.attr = 1').set(self)
         self.assertEqual(self.attr, 1)
+
+        self.attr = None
+        Address('.attr = 1, 2.5, 3').set(self)
+        self.assertEqual(self.attr, (1, 2.5, 3))
Repository: ManiacalLabs/BiblioPixel
Pull request #859 (2018-06-29 11:40:34)

Use safe loading and dumping with yaml


Patch:
diff --git a/bibliopixel/util/data_file.py b/bibliopixel/util/data_file.py
index b978796..2b5982f 100644
--- a/bibliopixel/util/data_file.py
+++ b/bibliopixel/util/data_file.py
@@ -6,11 +6,6 @@ open = __builtins__['open']
 ALWAYS_LOAD_YAML, ALWAYS_DUMP_YAML = True, True
 
 
-def _dump_yaml(data, default_flow_style=True, **kwds):
-    ordered = collections.OrderedDict(sorted(data.items()))
-    return yaml.dump(ordered, default_flow_style=default_flow_style, **kwds)
-
-
 def dumps(data, use_yaml=None, **kwds):
     """
     Dumps data into a nicely formatted JSON string.
@@ -24,7 +19,7 @@ def dumps(data, use_yaml=None, **kwds):
         use_yaml = ALWAYS_DUMP_YAML
 
     if use_yaml:
-        return _dump_yaml(data, **kwds)
+        return yaml.safe_dump(data, canonical=True, **kwds)
     else:
         return json.dumps(data, indent=4, sort_keys=True, **kwds)
 
@@ -42,7 +37,7 @@ def dump(data, file=sys.stdout, use_yaml=None, **kwds):
 
     def dump(fp):
         if use_yaml:
-            _dump_yaml(data, stream=fp, **kwds)
+            yaml.safe_dump(data, stream=fp, canonical=True, **kwds)
         else:
             json.dump(data, fp, indent=4, sort_keys=True, **kwds)
 
@@ -73,7 +68,7 @@ def loads(s, use_yaml=None, filename=''):
         assert isinstance(d, (int, float, bool, str))
         return d
 
-    return fix(yaml.load(s))
+    return fix(yaml.safe_load(s))
 
 
 def load(file, use_yaml=None):
diff --git a/bibliopixel/util/persistent_dict.py b/bibliopixel/util/persistent_dict.py
index 460c6b8..80c0d28 100644
--- a/bibliopixel/util/persistent_dict.py
+++ b/bibliopixel/util/persistent_dict.py
@@ -47,4 +47,5 @@ class PersistentDict(dict):
         self.__write()
 
     def __write(self):
-        data_file.dump(self, self.__filename)
+        ordered = dict(sorted(self.items()))
+        data_file.dump(ordered, self.__filename)


Test patch:
diff --git a/test/bibliopixel/util/data_file_test.py b/test/bibliopixel/util/data_file_test.py
index 70b76f3..4385779 100644
--- a/test/bibliopixel/util/data_file_test.py
+++ b/test/bibliopixel/util/data_file_test.py
@@ -20,7 +20,7 @@ controls:
 """
 
 
-class Data_fileTest(unittest.TestCase):
+class DataFileTest(unittest.TestCase):
     def test_yaml_keys(self):
         result = data_file.loads(DATA, 'test.yml')
         routing = result['controls'][0]['routing']
Repository: ManiacalLabs/BiblioPixel
Pull request #899 (2018-07-29 11:08:41)

Fix a crashing bug for numpy arrays
I keep forgetting that you cannot say `if array:` when `array` is a numpy array.  There's a good reason for it, but it's still a drag...

The fix makes the code smaller than before, but I wrote a unit test for this untested function.


Patch:
diff --git a/bibliopixel/util/color_list.py b/bibliopixel/util/color_list.py
index 143a9eb..87a841d 100644
--- a/bibliopixel/util/color_list.py
+++ b/bibliopixel/util/color_list.py
@@ -94,11 +94,10 @@ def to_triplets(colors):
     elements beyond a multiple of three.
     """
     try:
-        colors and colors[0][0]
-    except TypeError:
-        pass
-    else:
+        colors[0][0]
         return colors
+    except:
+        pass
 
     # It's a 1-dimensional list
     extra = len(colors) % 3


Test patch:
diff --git a/test/bibliopixel/util/color_list_test.py b/test/bibliopixel/util/color_list_test.py
index 3435260..dfc5d3a 100644
--- a/test/bibliopixel/util/color_list_test.py
+++ b/test/bibliopixel/util/color_list_test.py
@@ -1,7 +1,7 @@
-import numpy, unittest
+import numpy, numpy.testing, unittest
 
 from bibliopixel.util import colors, color_list, log
-from bibliopixel.util.color_list import ListMath, NumpyMath
+from bibliopixel.util.color_list import ListMath, NumpyMath, to_triplets
 
 COLORS1 = [colors.Red, colors.Green, colors.Blue, colors.White]
 COLORS2 = [colors.Black, colors.Blue, colors.Red, colors.Black]
@@ -154,3 +154,29 @@ class MixerTest(unittest.TestCase, TestBase):
             [make_numpy(COLORS2), make_numpy(WHITES), make_numpy(BLACKS)])
         self.do_test(mixer,
                      [(85, 85, 85), (85, 85, 170), (170, 85, 85), (85, 85, 85)])
+
+
+class ToTripletsTest(unittest.TestCase):
+    def test_simple(self):
+        self.assertEqual(to_triplets(COLORS1), COLORS1)
+
+    def test_numpy(self):
+        cl = make_numpy(COLORS1)
+        numpy.testing.assert_array_equal(to_triplets(cl), cl)
+
+    def test_exact_count(self):
+        cl = list(sum(COLORS1, ()))
+        self.assertEqual(to_triplets(cl), COLORS1)
+
+    def test_overage(self):
+        cl = list(sum(COLORS1, ()))
+        self.assertEqual(to_triplets(cl), COLORS1)
+
+        cl.append(255)
+        self.assertEqual(to_triplets(cl), COLORS1)
+
+        cl.append(0)
+        self.assertEqual(to_triplets(cl), COLORS1)
+
+        cl.append(0)
+        self.assertEqual(to_triplets(cl), COLORS1 + [colors.Red])
Repository: ManiacalLabs/BiblioPixel
Pull request #1087 (2018-11-29 14:26:23)

Fix path splitting in Windows
Well, I ended up waiting longer than I thought to go out.  :-)


Patch:
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(':')]


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)