Skip to content

Commit 9b81d9a

Browse files
committed
Add OrderedSet to preserve plugin load order
1 parent f8ed965 commit 9b81d9a

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

‎paths_cli/tests/test_utils.py‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from paths_cli.utils import *
2+
3+
class TestOrderedSet:
4+
def setup(self):
5+
self.set = OrderedSet(['a', 'b', 'a', 'c', 'd', 'c', 'd'])
6+
7+
def test_len(self):
8+
assert len(self.set) == 4
9+
10+
def test_order(self):
11+
for truth, beauty in zip("abcd", self.set):
12+
assert truth == beauty
13+
14+
def test_add_existing(self):
15+
assert len(self.set) == 4
16+
self.set.add('a')
17+
assert len(self.set) == 4
18+
assert list(self.set) == ['a', 'b', 'c', 'd']
19+
20+
def test_contains(self):
21+
assert 'a' in self.set
22+
assert not 'q' in self.set
23+
24+
def test_discard(self):
25+
self.set.discard('a')
26+
assert list(self.set) == ['b', 'c', 'd']
27+
28+
def test_discard_add_order(self):
29+
assert list(self.set) == ['a', 'b', 'c', 'd']
30+
self.set.discard('a')
31+
self.set.add('a')
32+
assert list(self.set) == ['b', 'c', 'd', 'a']
33+

‎paths_cli/utils.py‎

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,49 @@
11
import importlib
22
import pathlib
3+
from collections import abc
34
import click
45
from .plugin_management import FilePluginLoader, NamespacePluginLoader
56

7+
8+
class OrderedSet(abc.MutableSet):
9+
"""Set-like object with ordered iterator (insertion order).
10+
11+
This is used to ensure that only one copy of each plugin is loaded
12+
(set-like behavior) while retaining the insertion order.
13+
14+
Parameters
15+
----------
16+
iterable : Iterable
17+
iterable of objects to initialize with
18+
"""
19+
def __init__(self, iterable=None):
20+
self._set = set([])
21+
self._list = []
22+
if iterable is None:
23+
iterable = []
24+
for item in iterable:
25+
self.add(item)
26+
27+
def __contains__(self, item):
28+
return item in self._set
29+
30+
def __len__(self):
31+
return len(self._set)
32+
33+
def __iter__(self):
34+
return iter(self._list)
35+
36+
def add(self, item):
37+
if item in self._set:
38+
return
39+
self._set.add(item)
40+
self._list.append(item)
41+
42+
def discard(self, item):
43+
self._list.remove(item)
44+
self._set.discard(item)
45+
46+
647
def tag_final_result(result, storage, tag='final_conditions'):
748
"""Save results to a tag in storage.
849
@@ -41,5 +82,5 @@ def get_installed_plugins(default_loader, plugin_types):
4182
NamespacePluginLoader('paths_cli_plugins', plugin_types)
4283

4384
]
44-
plugins = set(sum([loader() for loader in loaders], []))
85+
plugins = OrderedSet(sum([loader() for loader in loaders], []))
4586
return list(plugins)

0 commit comments

Comments
 (0)