Skip to content

Commit

Permalink
Allowing banning duplicate items in ImmutableSet initializer
Browse files Browse the repository at this point in the history
Closes #49
  • Loading branch information
qpwo authored and Ryan Gabbard committed Jun 10, 2019
1 parent 6985a25 commit 17f722e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 3 deletions.
6 changes: 5 additions & 1 deletion immutablecollections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@

from immutablecollections.immutablecollection import ImmutableCollection
from immutablecollections._immutabledict import immutabledict, ImmutableDict
from immutablecollections._immutableset import immutableset, ImmutableSet
from immutablecollections._immutableset import (
immutableset,
immutableset_from_unique_elements,
ImmutableSet,
)
from immutablecollections._immutablemultidict import (
ImmutableSetMultiDict,
ImmutableListMultiDict,
Expand Down
24 changes: 23 additions & 1 deletion immutablecollections/_immutableset.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@


def immutableset(
iterable: Optional[Iterable[T]] = None, *, disable_order_check: bool = False
iterable: Optional[Iterable[T]] = None,
*,
disable_order_check: bool = False,
forbid_duplicate_elements: bool = False,
) -> "ImmutableSet[T]":
"""
Create an immutable set with the given contents.
Expand All @@ -48,6 +51,9 @@ def immutableset(
could be removed in the future and should not be relied upon. This check may be disabled
by setting *disable_order_check* to ``True``.
If *forbid_duplicate_elements* is ``True`` and one item occurs twice in *iterable*, then
a ``ValueError`` will be thrown.
If *iterable* is already an ``ImmutableSet``, *iterable* itself will be returned.
"""
# immutableset() should return an empty set
Expand Down Expand Up @@ -92,6 +98,10 @@ def immutableset(
if value not in containment_set:
containment_set.add(value)
iteration_order.append(value)
elif forbid_duplicate_elements:
raise ValueError(
"Input collection has duplicate items and forbid_duplicate_elements=False"
)

if iteration_order:
if len(iteration_order) == 1:
Expand All @@ -102,6 +112,18 @@ def immutableset(
return _EMPTY


def immutableset_from_unique_elements(
iterable: Optional[Iterable[T]] = None, *, disable_order_check: bool = False
):
"""
Create an immutableset from *iterable*. If one item occurs twice in *iterable*, then
a ``ValueError`` will be thrown. More information in ``immutablecollections.immutableset``.
"""
return immutableset(
iterable, disable_order_check=disable_order_check, forbid_duplicate_elements=True
)


# typing.AbstractSet matches collections.abc.Set
class ImmutableSet( # pylint: disable=duplicate-bases
Generic[T],
Expand Down
16 changes: 15 additions & 1 deletion tests/test_immutableset.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
from unittest import TestCase
from unittest.mock import patch

from immutablecollections import ImmutableSet, immutableset
from immutablecollections import (
ImmutableSet,
immutableset,
immutableset_from_unique_elements,
)


class TestImmutableSet(TestCase):
Expand Down Expand Up @@ -280,3 +284,13 @@ def test_subtract_from_other_set_types(self):
# frozensets on LHS
self.assertEqual({5, 6}, frozenset([4, 5, 6]) - immutableset([2, 3, 4]))
self.assertEqual({"a"}, frozenset(["a", "b"]) - immutableset(["b", "c"]))

def test_forbid_duplicate_elements(self):
with self.assertRaises(ValueError):
immutableset([4, 6, 7, 9, 7], forbid_duplicate_elements=True)
immutableset([3, 7, 5, 9], forbid_duplicate_elements=True)

def test_immutableset_from_unique_elements(self):
with self.assertRaises(ValueError):
immutableset_from_unique_elements([4, 6, 7, 9, 7])
immutableset_from_unique_elements([3, 7, 5, 9])

0 comments on commit 17f722e

Please sign in to comment.