diff --git a/README.md b/README.md index f66fadd..34ee48b 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ operators like sets do. OrderedSet(['r', 'x', 's', 'h', 'z', 'm']) The `__getitem__()` and `index()` methods have been extended to accept any -iterable except a string, returning a list, to perform NumPy-like "fancy -indexing". +iterable, but not hashable (string, tuple, frozenset) instances, returning a +list, to perform NumPy-like "fancy indexing". >>> letters = OrderedSet('abracadabra') diff --git a/ordered_set/__init__.py b/ordered_set/__init__.py index ccd1cbf..adb6ece 100644 --- a/ordered_set/__init__.py +++ b/ordered_set/__init__.py @@ -9,6 +9,7 @@ from typing import ( Any, Dict, + Hashable, Iterable, Iterator, List, @@ -33,26 +34,8 @@ OrderedSetInitializer = Union[AbstractSet[T], Sequence[T], Iterable[T]] -def _is_atomic(obj: object) -> bool: - """ - Returns True for objects which are iterable but should not be iterated in - the context of indexing an OrderedSet. - - When we index by an iterable, usually that means we're being asked to look - up a list of things. - - However, in the case of the .index() method, we shouldn't handle strings - and tuples like other iterables. They're not sequences of things to look - up, they're the single, atomic thing we're trying to find. - - As an example, oset.index('hello') should give the index of 'hello' in an - OrderedSet of strings. It shouldn't give the indexes of each individual - character. - """ - return isinstance(obj, (str, tuple)) - - class OrderedSet(MutableSet[T], Sequence[T]): + __slots__ = ("items", "map") """ An OrderedSet is a custom MutableSet that remembers its order, so that every entry has an index that can be looked up. @@ -232,7 +215,7 @@ def index(self, key): Get the index of a given entry, raising an IndexError if it's not present. - `key` can be an iterable of entries that is not a string, in which case + `key` can be an iterable of entries that is not a hashable (string, tuple, frozenset), in which case this returns a list of indices. Example: @@ -240,7 +223,7 @@ def index(self, key): >>> oset.index(2) 1 """ - if isinstance(key, Iterable) and not _is_atomic(key): + if isinstance(key, Iterable) and not isinstance(key, Hashable): return [self.index(subkey) for subkey in key] return self.map[key] diff --git a/test/test_ordered_set.py b/test/test_ordered_set.py index 6efe0a9..eb75a7b 100644 --- a/test/test_ordered_set.py +++ b/test/test_ordered_set.py @@ -54,6 +54,14 @@ def test_indexing(): with pytest.raises(KeyError): set1.index("br") + set2 = OrderedSet((("a", "b"), frozenset(("c", "d")), "efg")) + assert set2.index(("a", "b"))==0 + assert set2.index(frozenset(("c", "d")))==1 + assert set2.index("efg")==2 + assert set2.index([frozenset(("c", "d")), ("a", "b")])==[1, 0] + assert set2.index(OrderedSet([frozenset(("c", "d")), ("a", "b")]))==[1, 0] + with pytest.raises(KeyError): + set2.index(["a", "b"]) class FancyIndexTester: """