diff --git a/pipenv/utils/funktools.py b/pipenv/utils/funktools.py index edcfc78b..f1a682cc 100644 --- a/pipenv/utils/funktools.py +++ b/pipenv/utils/funktools.py @@ -70,3 +70,11 @@ def unnest(elem: Iterable) -> Any: yield sub else: yield el + + +def dedup(iterable: Iterable) -> Iterable: + # type: (Iterable) -> Iterable + """Deduplicate an iterable object like iter(set(iterable)) but order- + preserved.""" + + return iter(dict.fromkeys(iterable)) diff --git a/tests/unit/test_funktools.py b/tests/unit/test_funktools.py new file mode 100644 index 00000000..39c7b3ec --- /dev/null +++ b/tests/unit/test_funktools.py @@ -0,0 +1,50 @@ +import pytest + +from pipenv.utils.funktools import dedup, unnest, _is_iterable + + +def test_unnest(): + nested_iterable = ( + 1234, (3456, 4398345, (234234)), ( + 2396, ( + 928379, 29384, ( + 293759, 2347, ( + 2098, 7987, 27599 + ) + ) + ) + ) + ) + list(unnest(nested_iterable)) == [1234, 3456, 4398345, 234234, + 2396, 928379, 29384, 293759, + 2347, 2098, 7987, 27599] + + +@pytest.mark.parametrize( + "iterable, result", + [ + [["abc", "def"], True], + [("abc", "def"), True], + ["abcdef", True], + [None, False], + [1234, False], + ], +) +def test_is_iterable(iterable, result): + assert _is_iterable(iterable) is result + + +def test_unnest_none(): + assert list(unnest(None)) == [None] + + +def test_dedup(): + dup_strings = ["abcde", "fghij", "klmno", "pqrst", "abcde", "klmno"] + assert list(dedup(dup_strings)) == [ + "abcde", + "fghij", + "klmno", + "pqrst", + ] + dup_ints = (12345, 56789, 12345, 54321, 98765, 54321) + assert list(dedup(dup_ints)) == [12345, 56789, 54321, 98765]