From fcc1e4888cb6e4b6f889e5b3ad0a7aef02950130 Mon Sep 17 00:00:00 2001
From: Matthias Diener <mdiener@illinois.edu>
Date: Mon, 24 Jun 2024 16:53:57 -0500
Subject: [PATCH] Unique improvements

---
 pytools/__init__.py          | 5 +++--
 pytools/test/test_pytools.py | 6 ++++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/pytools/__init__.py b/pytools/__init__.py
index a2c167c..25de926 100644
--- a/pytools/__init__.py
+++ b/pytools/__init__.py
@@ -2970,8 +2970,9 @@ def to_identifier(s: str) -> str:
 
 # {{{ unique
 
-def unique(seq: Sequence[T]) -> Iterator[T]:
-    """Yield unique elements in *seq*, removing all duplicates. See also
+def unique(seq: Iterable[T]) -> Iterator[T]:
+    """Yield unique elements in *seq*, removing all duplicates. The internal
+    order of the elements is preserved. See also
     :func:`itertools.groupby` (which removes consecutive duplicates)."""
     return iter(dict.fromkeys(seq))
 
diff --git a/pytools/test/test_pytools.py b/pytools/test/test_pytools.py
index 3ca30a4..9e393a7 100644
--- a/pytools/test/test_pytools.py
+++ b/pytools/test/test_pytools.py
@@ -805,6 +805,12 @@ def test_unique():
     assert next(unique([1, 2, 1, 3])) == 1
     assert next(unique([]), None) is None
 
+    # Also test strings since their ordering would be thrown off by
+    # set-based 'unique' implementations.
+    assert list(unique(["A", "B", "A"])) == ["A", "B"]
+    assert tuple(unique(("A", "B", "A"))) == ("A", "B")
+    assert next(unique(["A", "B", "A", "C"])) == "A"
+
 
 # This class must be defined globally to be picklable
 class SimpleRecord(Record):
-- 
GitLab