datahold 4.0.0.dev28__tar.gz → 4.0.0.dev29__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/PKG-INFO +1 -1
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/pyproject.toml +1 -1
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold/__init__.py +79 -48
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold.egg-info/PKG-INFO +1 -1
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold.egg-info/SOURCES.txt +1 -0
- datahold-4.0.0.dev29/tests/test_FrozenDictSlot.py +271 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_FrozenSetSlot.py +243 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_MutableDictSlot.py +1 -2
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/testdata.toml +4 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/LICENSE.txt +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/MANIFEST.in +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/README.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v1.1.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v1.2.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v2.0.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v2.1.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v2.2.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v2.3.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v3.0.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/docs/v4.0.rst +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/run_tests.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/setup.cfg +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold/py.typed +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold.egg-info/dependency_links.txt +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold.egg-info/requires.txt +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/src/datahold.egg-info/top_level.txt +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_FrozenListSlot.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_MutableListSlot.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_MutableSetSlot.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_abstractmethods.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_all.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_attributes.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_docs.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_generic.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_issubclass.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_metaclass.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_name.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_nested.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_sorted.py +0 -0
- {datahold-4.0.0.dev28 → datahold-4.0.0.dev29}/tests/test_variance.py +0 -0
|
@@ -9,6 +9,7 @@ __all__: list[str] = [
|
|
|
9
9
|
"FrozenDictSlot",
|
|
10
10
|
"FrozenListLike",
|
|
11
11
|
"FrozenListSlot",
|
|
12
|
+
"FrozenObjectLike",
|
|
12
13
|
"FrozenObjectSlot",
|
|
13
14
|
"FrozenSetLike",
|
|
14
15
|
"FrozenSetSlot",
|
|
@@ -95,7 +96,7 @@ class MutableSet_Mutable[Item: abc.Hashable](Protocol):
|
|
|
95
96
|
|
|
96
97
|
class Mapping_Frozen[Key, Value](Collection_Frozen[Key], Protocol):
|
|
97
98
|
@setdoc.basic
|
|
98
|
-
def __getitem__(self: Self, key:
|
|
99
|
+
def __getitem__(self: Self, key: Never, /) -> Value: ...
|
|
99
100
|
class MutableMapping_Mutable[Key_, Value_](
|
|
100
101
|
Protocol,
|
|
101
102
|
):
|
|
@@ -171,7 +172,7 @@ class MutableSequence_Mutable[Item](Protocol):
|
|
|
171
172
|
|
|
172
173
|
type Dict[Key, Value] = dict[Key | str, Optional[Value]]
|
|
173
174
|
|
|
174
|
-
type
|
|
175
|
+
type Dict_Init[Key, Value] = (
|
|
175
176
|
SupportsKeysAndGetitem[Key | str, Optional[Value]]
|
|
176
177
|
| abc.Iterable[tuple[Key | str, Optional[Value]]]
|
|
177
178
|
)
|
|
@@ -205,6 +206,19 @@ class MutableObject[Frozen, Mutable](Object[Frozen]):
|
|
|
205
206
|
### OBJECT-LIKE ###
|
|
206
207
|
|
|
207
208
|
|
|
209
|
+
class FrozenObjectLike[Frozen: abc.Hashable](
|
|
210
|
+
Object[Frozen],
|
|
211
|
+
abc.Hashable,
|
|
212
|
+
):
|
|
213
|
+
"""Provide abc for custom frozen object-like."""
|
|
214
|
+
|
|
215
|
+
__slots__ = ()
|
|
216
|
+
|
|
217
|
+
@setdoc.basic
|
|
218
|
+
def __hash__(self: Self, /) -> int:
|
|
219
|
+
return hash(self.__frozen__())
|
|
220
|
+
|
|
221
|
+
|
|
208
222
|
class MutableObjectLike[Frozen, Mutable](
|
|
209
223
|
MutableObject[Frozen, Mutable],
|
|
210
224
|
):
|
|
@@ -232,7 +246,8 @@ class ObjectSlot[Frozen](
|
|
|
232
246
|
_slot: Frozen
|
|
233
247
|
|
|
234
248
|
|
|
235
|
-
class FrozenObjectSlot[Frozen](
|
|
249
|
+
class FrozenObjectSlot[Frozen: abc.Hashable](
|
|
250
|
+
FrozenObjectLike[Frozen],
|
|
236
251
|
ObjectSlot[Frozen],
|
|
237
252
|
):
|
|
238
253
|
"""Provide slotted abc for custom frozen object-like."""
|
|
@@ -314,7 +329,7 @@ class SetLike[Item: abc.Hashable](Set[Item]):
|
|
|
314
329
|
def __frozen__(self: Self, /) -> frozenset[Item]: ...
|
|
315
330
|
@abstractmethod
|
|
316
331
|
@setdoc.basic
|
|
317
|
-
def __init__(self: Self,
|
|
332
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None: ...
|
|
318
333
|
@setdoc.basic
|
|
319
334
|
def difference(self: Self, /, *others: abc.Iterable[abc.Hashable]) -> Self:
|
|
320
335
|
return type(self)(self.__frozen__().difference(*others))
|
|
@@ -342,15 +357,14 @@ class SetLike[Item: abc.Hashable](Set[Item]):
|
|
|
342
357
|
return type(self)(self.__frozen__().union(*others))
|
|
343
358
|
|
|
344
359
|
|
|
345
|
-
class FrozenSetLike[Item: abc.Hashable](
|
|
360
|
+
class FrozenSetLike[Item: abc.Hashable](
|
|
361
|
+
FrozenObjectLike[frozenset[Item]],
|
|
362
|
+
SetLike[Item],
|
|
363
|
+
):
|
|
346
364
|
"""Provide abc for custom frozen set-like."""
|
|
347
365
|
|
|
348
366
|
__slots__ = ()
|
|
349
367
|
|
|
350
|
-
@setdoc.basic
|
|
351
|
-
def __hash__(self: Self, /) -> int:
|
|
352
|
-
return hash(self.__frozen__())
|
|
353
|
-
|
|
354
368
|
|
|
355
369
|
class MutableSetLike[Item: abc.Hashable](
|
|
356
370
|
SetLike[Item],
|
|
@@ -367,9 +381,9 @@ class MutableSetLike[Item: abc.Hashable](
|
|
|
367
381
|
return frozenset(mutable)
|
|
368
382
|
|
|
369
383
|
@setdoc.basic
|
|
370
|
-
def __init__(self: Self,
|
|
384
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None:
|
|
371
385
|
with self.__mutate__() as mutable:
|
|
372
|
-
mutable.update(
|
|
386
|
+
mutable.update(other)
|
|
373
387
|
|
|
374
388
|
@setdoc.basic
|
|
375
389
|
def difference_update(
|
|
@@ -410,8 +424,8 @@ class FrozenSetSlot[Item](
|
|
|
410
424
|
__slots__ = ()
|
|
411
425
|
|
|
412
426
|
@setdoc.basic
|
|
413
|
-
def __init__(self: Self,
|
|
414
|
-
self._slot = frozenset(
|
|
427
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None:
|
|
428
|
+
self._slot = frozenset(other)
|
|
415
429
|
|
|
416
430
|
|
|
417
431
|
class MutableSetSlot[Item](
|
|
@@ -428,10 +442,10 @@ class MutableSetSlot[Item](
|
|
|
428
442
|
self: Self,
|
|
429
443
|
/,
|
|
430
444
|
) -> abc.Generator[set[Item], None, None]:
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
yield
|
|
434
|
-
self._slot = frozenset(
|
|
445
|
+
mutable: set[Item]
|
|
446
|
+
mutable = set(getattr(self, "_slot", ()))
|
|
447
|
+
yield mutable
|
|
448
|
+
self._slot = frozenset(mutable)
|
|
435
449
|
|
|
436
450
|
|
|
437
451
|
### MAPPING ###
|
|
@@ -449,8 +463,26 @@ class Mapping[Key: abc.Hashable, Value](
|
|
|
449
463
|
@setdoc.basic
|
|
450
464
|
def __frozen__(self: Self, /) -> Mapping_Frozen[Key, Value]: ...
|
|
451
465
|
@setdoc.basic
|
|
452
|
-
def __getitem__(self: Self, key:
|
|
453
|
-
|
|
466
|
+
def __getitem__(self: Self, key: object, /) -> Value:
|
|
467
|
+
try:
|
|
468
|
+
return self.__frozen__()[key] # type: ignore[index]
|
|
469
|
+
except TypeError:
|
|
470
|
+
raise KeyError(key) from None
|
|
471
|
+
|
|
472
|
+
@overload
|
|
473
|
+
def get(self, key: object) -> Optional[Value]: ...
|
|
474
|
+
@overload
|
|
475
|
+
def get[Value_](self, key: object, default: Value_) -> Value | Value_: ...
|
|
476
|
+
@setdoc.basic
|
|
477
|
+
def get[Value_](
|
|
478
|
+
self: Self, key: object, default: Optional[Value_] = None
|
|
479
|
+
) -> Optional[Value | Value_]:
|
|
480
|
+
# this method is just as Mapping.get
|
|
481
|
+
# with the signature corrected
|
|
482
|
+
try:
|
|
483
|
+
return self[key]
|
|
484
|
+
except KeyError:
|
|
485
|
+
return default
|
|
454
486
|
|
|
455
487
|
|
|
456
488
|
class MutableMapping[Key: abc.Hashable, Value](
|
|
@@ -487,21 +519,20 @@ class DictLike[Key: abc.Hashable, Value](
|
|
|
487
519
|
|
|
488
520
|
@abstractmethod
|
|
489
521
|
@setdoc.basic
|
|
490
|
-
def __frozen__(self: Self, /) -> FrozenDict[Key, Value]:
|
|
491
|
-
...
|
|
522
|
+
def __frozen__(self: Self, /) -> FrozenDict[Key, Value]: ...
|
|
492
523
|
|
|
493
524
|
@abstractmethod
|
|
494
525
|
@setdoc.basic
|
|
495
526
|
def __init__(
|
|
496
527
|
self: Self,
|
|
497
|
-
|
|
528
|
+
other: Dict_Init[Key, Value] = (),
|
|
498
529
|
/,
|
|
499
530
|
**kwargs: Value,
|
|
500
531
|
): ...
|
|
501
532
|
@setdoc.basic
|
|
502
533
|
def __or__[Key_, Value_](
|
|
503
534
|
self: Self,
|
|
504
|
-
other:
|
|
535
|
+
other: Dict_Init[Key_, Value_],
|
|
505
536
|
/,
|
|
506
537
|
) -> DictLike[Key | Key_, Value | Value_]:
|
|
507
538
|
data: FrozenDict[Key, Value]
|
|
@@ -525,17 +556,13 @@ class DictLike[Key: abc.Hashable, Value](
|
|
|
525
556
|
|
|
526
557
|
|
|
527
558
|
class FrozenDictLike[Key: abc.Hashable, Value](
|
|
559
|
+
FrozenObjectLike[FrozenDict[Key, Value]],
|
|
528
560
|
DictLike[Key, Value],
|
|
529
|
-
abc.Hashable,
|
|
530
561
|
):
|
|
531
562
|
"""Provide abc for custom frozen dict-like."""
|
|
532
563
|
|
|
533
564
|
__slots__ = ()
|
|
534
565
|
|
|
535
|
-
@setdoc.basic
|
|
536
|
-
def __hash__(self: Self, /) -> int:
|
|
537
|
-
return hash(self.__frozen__())
|
|
538
|
-
|
|
539
566
|
|
|
540
567
|
class MutableDictLike[Key: abc.Hashable, Value](
|
|
541
568
|
DictLike[Key, Value],
|
|
@@ -547,7 +574,7 @@ class MutableDictLike[Key: abc.Hashable, Value](
|
|
|
547
574
|
__slots__ = ()
|
|
548
575
|
|
|
549
576
|
@setdoc.basic
|
|
550
|
-
def __frozen__(
|
|
577
|
+
def __frozen__(
|
|
551
578
|
self: Self,
|
|
552
579
|
/,
|
|
553
580
|
) -> FrozenDict[Key, Value]:
|
|
@@ -557,16 +584,16 @@ class MutableDictLike[Key: abc.Hashable, Value](
|
|
|
557
584
|
@setdoc.basic
|
|
558
585
|
def __init__(
|
|
559
586
|
self: Self,
|
|
560
|
-
|
|
587
|
+
other: Dict_Init[Key, Value] = (),
|
|
561
588
|
/,
|
|
562
589
|
**kwargs: Optional[Value],
|
|
563
590
|
):
|
|
564
|
-
self.update(
|
|
591
|
+
self.update(other, **kwargs)
|
|
565
592
|
|
|
566
593
|
@setdoc.basic
|
|
567
594
|
def __ior__( # type: ignore[override]
|
|
568
595
|
self: Self,
|
|
569
|
-
other:
|
|
596
|
+
other: Dict_Init[Key, Value],
|
|
570
597
|
/,
|
|
571
598
|
) -> Self:
|
|
572
599
|
with self.__mutate__() as mutable:
|
|
@@ -585,7 +612,7 @@ class MutableDictLike[Key: abc.Hashable, Value](
|
|
|
585
612
|
### DICT-SLOT ###
|
|
586
613
|
|
|
587
614
|
|
|
588
|
-
class FrozenDictSlot[Key: abc.Hashable, Value](
|
|
615
|
+
class FrozenDictSlot[Key: abc.Hashable, Value](
|
|
589
616
|
FrozenObjectSlot[FrozenDict[Key, Value]],
|
|
590
617
|
FrozenDictLike[Key, Value],
|
|
591
618
|
):
|
|
@@ -596,11 +623,11 @@ class FrozenDictSlot[Key: abc.Hashable, Value]( # type: ignore[misc]
|
|
|
596
623
|
@setdoc.basic
|
|
597
624
|
def __init__(
|
|
598
625
|
self: Self,
|
|
599
|
-
|
|
626
|
+
other: Dict_Init[Key, Value] = (),
|
|
600
627
|
/,
|
|
601
628
|
**kwargs: Optional[Value],
|
|
602
629
|
) -> None:
|
|
603
|
-
self._slot = frozendict(
|
|
630
|
+
self._slot = frozendict(other, **kwargs) # type: ignore[arg-type]
|
|
604
631
|
|
|
605
632
|
|
|
606
633
|
class MutableDictSlot[Key: abc.Hashable, Value](
|
|
@@ -617,10 +644,10 @@ class MutableDictSlot[Key: abc.Hashable, Value](
|
|
|
617
644
|
self: Self,
|
|
618
645
|
/,
|
|
619
646
|
) -> abc.Generator[Dict[Key, Value], None, None]:
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
yield
|
|
623
|
-
self._slot = frozendict(
|
|
647
|
+
mutable: Dict[Key, Value]
|
|
648
|
+
mutable = dict(getattr(self, "_slot", ()))
|
|
649
|
+
yield mutable
|
|
650
|
+
self._slot = frozendict(mutable)
|
|
624
651
|
|
|
625
652
|
|
|
626
653
|
### SEQUENCE ###
|
|
@@ -769,7 +796,7 @@ class ListLike[Item](Sequence[Item]):
|
|
|
769
796
|
|
|
770
797
|
@abstractmethod
|
|
771
798
|
@setdoc.basic
|
|
772
|
-
def __init__(self: Self,
|
|
799
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None: ...
|
|
773
800
|
|
|
774
801
|
@setdoc.basic
|
|
775
802
|
def __le__(self: Self, other: ListLike[Any], /) -> bool:
|
|
@@ -799,7 +826,10 @@ class ListLike[Item](Sequence[Item]):
|
|
|
799
826
|
return f"{type(self).__name__}({list(self)!r})"
|
|
800
827
|
|
|
801
828
|
|
|
802
|
-
class FrozenListLike[Item](
|
|
829
|
+
class FrozenListLike[Item](
|
|
830
|
+
FrozenObjectLike[tuple[Item, ...]],
|
|
831
|
+
ListLike[Item],
|
|
832
|
+
):
|
|
803
833
|
"""Provide abc for custom frozen list-like."""
|
|
804
834
|
|
|
805
835
|
__slots__ = ()
|
|
@@ -843,9 +873,9 @@ class MutableListLike[Item](
|
|
|
843
873
|
return self
|
|
844
874
|
|
|
845
875
|
@setdoc.basic
|
|
846
|
-
def __init__(self: Self,
|
|
876
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None:
|
|
847
877
|
with self.__mutate__() as mutable:
|
|
848
|
-
mutable.extend(
|
|
878
|
+
mutable.extend(other)
|
|
849
879
|
|
|
850
880
|
@overload
|
|
851
881
|
@setdoc.basic
|
|
@@ -894,8 +924,8 @@ class FrozenListSlot[Item](
|
|
|
894
924
|
__slots__ = ()
|
|
895
925
|
|
|
896
926
|
@setdoc.basic
|
|
897
|
-
def __init__(self: Self,
|
|
898
|
-
self._slot = tuple(
|
|
927
|
+
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None:
|
|
928
|
+
self._slot = tuple(other)
|
|
899
929
|
|
|
900
930
|
|
|
901
931
|
class MutableListSlot[Item](
|
|
@@ -909,6 +939,7 @@ class MutableListSlot[Item](
|
|
|
909
939
|
@contextmanager
|
|
910
940
|
@setdoc.basic
|
|
911
941
|
def __mutate__(self: Self, /) -> abc.Generator[list[Item], None, None]:
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
942
|
+
mutable: list[Item]
|
|
943
|
+
mutable = list(getattr(self, "_slot", ()))
|
|
944
|
+
yield mutable
|
|
945
|
+
self._slot = tuple(mutable)
|
|
@@ -19,6 +19,7 @@ src/datahold.egg-info/SOURCES.txt
|
|
|
19
19
|
src/datahold.egg-info/dependency_links.txt
|
|
20
20
|
src/datahold.egg-info/requires.txt
|
|
21
21
|
src/datahold.egg-info/top_level.txt
|
|
22
|
+
tests/test_FrozenDictSlot.py
|
|
22
23
|
tests/test_FrozenListSlot.py
|
|
23
24
|
tests/test_FrozenSetSlot.py
|
|
24
25
|
tests/test_MutableDictSlot.py
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from collections import abc
|
|
3
|
+
from typing import Any, Self
|
|
4
|
+
|
|
5
|
+
from datahold import FrozenDictSlot
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestFromKeysMethod(unittest.TestCase):
|
|
9
|
+
def test_fromkeys_uses_none_by_default(self: Self) -> None:
|
|
10
|
+
result: Any = FrozenDictSlot.fromkeys(["a", "b", "c"])
|
|
11
|
+
|
|
12
|
+
self.assertEqual(result, {"a": None, "b": None, "c": None})
|
|
13
|
+
|
|
14
|
+
def test_fromkeys_uses_provided_value(self: Self) -> None:
|
|
15
|
+
result: Any = FrozenDictSlot.fromkeys(["a", "b"], 10)
|
|
16
|
+
|
|
17
|
+
self.assertEqual(result, {"a": 10, "b": 10})
|
|
18
|
+
|
|
19
|
+
def test_fromkeys_uses_same_value_object_for_every_key(self: Self) -> None:
|
|
20
|
+
value: Any = []
|
|
21
|
+
result: Any = FrozenDictSlot.fromkeys(["a", "b"], value)
|
|
22
|
+
|
|
23
|
+
self.assertIs(result["a"], value)
|
|
24
|
+
self.assertIs(result["b"], value)
|
|
25
|
+
|
|
26
|
+
def test_fromkeys_removes_duplicate_keys(self: Self) -> None:
|
|
27
|
+
result: Any = FrozenDictSlot.fromkeys(
|
|
28
|
+
["a", "b", "a", "c", "b"],
|
|
29
|
+
1,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
self.assertEqual(list(result.keys()), ["a", "b", "c"])
|
|
33
|
+
self.assertEqual(result, {"a": 1, "b": 1, "c": 1})
|
|
34
|
+
|
|
35
|
+
def test_fromkeys_accepts_generator(self: Self) -> None:
|
|
36
|
+
keys: Any = (str(number) for number in range(3))
|
|
37
|
+
result: Any = FrozenDictSlot.fromkeys(keys, "value")
|
|
38
|
+
|
|
39
|
+
self.assertEqual(
|
|
40
|
+
result,
|
|
41
|
+
{"0": "value", "1": "value", "2": "value"},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def test_fromkeys_accepts_empty_iterable(self: Self) -> None:
|
|
45
|
+
self.assertEqual(FrozenDictSlot.fromkeys([], 1), {})
|
|
46
|
+
|
|
47
|
+
def test_fromkeys_returns_frozen_dict_slot(self: Self) -> None:
|
|
48
|
+
result: Any = FrozenDictSlot.fromkeys(["a"], 1)
|
|
49
|
+
|
|
50
|
+
self.assertIsInstance(result, FrozenDictSlot)
|
|
51
|
+
|
|
52
|
+
def test_fromkeys_rejects_unhashable_keys(self: Self) -> None:
|
|
53
|
+
with self.assertRaises(TypeError):
|
|
54
|
+
FrozenDictSlot.fromkeys([["unhashable"]], 1) # type: ignore
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class TestGetMethod(unittest.TestCase):
|
|
58
|
+
def test_get_returns_existing_value(self: Self) -> None:
|
|
59
|
+
mapping: Any = FrozenDictSlot({"a": 1, "b": 2})
|
|
60
|
+
|
|
61
|
+
self.assertEqual(mapping.get("a"), 1)
|
|
62
|
+
|
|
63
|
+
def test_get_returns_none_for_missing_key(self: Self) -> None:
|
|
64
|
+
mapping: Any = FrozenDictSlot({"a": 1})
|
|
65
|
+
|
|
66
|
+
self.assertIsNone(mapping.get("missing"))
|
|
67
|
+
|
|
68
|
+
def test_get_returns_default_for_missing_key(self: Self) -> None:
|
|
69
|
+
mapping: Any = FrozenDictSlot({"a": 1})
|
|
70
|
+
|
|
71
|
+
self.assertEqual(mapping.get("missing", 20), 20)
|
|
72
|
+
|
|
73
|
+
def test_get_returns_existing_value_instead_of_default(self: Self) -> None:
|
|
74
|
+
mapping: Any = FrozenDictSlot({"a": 1})
|
|
75
|
+
|
|
76
|
+
self.assertEqual(mapping.get("a", 20), 1)
|
|
77
|
+
|
|
78
|
+
def test_get_returns_exact_default_object(self: Self) -> None:
|
|
79
|
+
default: Any = []
|
|
80
|
+
mapping: Any = FrozenDictSlot()
|
|
81
|
+
|
|
82
|
+
self.assertIs(mapping.get("missing", default), default)
|
|
83
|
+
|
|
84
|
+
def test_get_accepts_different_hashable_key_types(self: Self) -> None:
|
|
85
|
+
mapping: FrozenDictSlot[abc.Hashable, str]
|
|
86
|
+
mapping = FrozenDictSlot(
|
|
87
|
+
{ # type: ignore
|
|
88
|
+
1: "integer",
|
|
89
|
+
(2, 3): "tuple",
|
|
90
|
+
None: "none",
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.assertEqual(mapping.get(1), "integer")
|
|
95
|
+
self.assertEqual(mapping.get((2, 3)), "tuple")
|
|
96
|
+
self.assertEqual(mapping.get(None), "none")
|
|
97
|
+
|
|
98
|
+
def test_get_rejects_unhashable_key(self: Self) -> None:
|
|
99
|
+
self.assertIsNone(FrozenDictSlot().get([]))
|
|
100
|
+
|
|
101
|
+
def test_get_rejects_too_many_arguments(self: Self) -> None:
|
|
102
|
+
with self.assertRaises(TypeError):
|
|
103
|
+
FrozenDictSlot().get("a", 1, 2) # type: ignore[call-overload]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class TestItemsMethod(unittest.TestCase):
|
|
107
|
+
def test_items_contains_all_key_value_pairs(self: Self) -> None:
|
|
108
|
+
mapping: Any = FrozenDictSlot({"a": 1, "b": 2})
|
|
109
|
+
|
|
110
|
+
self.assertEqual(
|
|
111
|
+
set(mapping.items()),
|
|
112
|
+
{("a", 1), ("b", 2)},
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def test_items_of_empty_mapping_is_empty(self: Self) -> None:
|
|
116
|
+
self.assertEqual(list(FrozenDictSlot().items()), [])
|
|
117
|
+
|
|
118
|
+
def test_items_preserves_insertion_order(self: Self) -> None:
|
|
119
|
+
mapping: Any = FrozenDictSlot(
|
|
120
|
+
[
|
|
121
|
+
("third", 3),
|
|
122
|
+
("first", 1),
|
|
123
|
+
("second", 2),
|
|
124
|
+
]
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
self.assertEqual(
|
|
128
|
+
list(mapping.items()),
|
|
129
|
+
[("third", 3), ("first", 1), ("second", 2)],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def test_items_supports_membership_testing(self: Self) -> None:
|
|
133
|
+
items: Any = FrozenDictSlot({"a": 1, "b": 2}).items()
|
|
134
|
+
|
|
135
|
+
self.assertIn(("a", 1), items)
|
|
136
|
+
self.assertNotIn(("a", 2), items)
|
|
137
|
+
|
|
138
|
+
def test_items_has_correct_length(self: Self) -> None:
|
|
139
|
+
items: Any = FrozenDictSlot(
|
|
140
|
+
{
|
|
141
|
+
"a": 1,
|
|
142
|
+
"b": 2,
|
|
143
|
+
"c": 3,
|
|
144
|
+
}
|
|
145
|
+
).items()
|
|
146
|
+
|
|
147
|
+
self.assertEqual(len(items), 3)
|
|
148
|
+
|
|
149
|
+
def test_items_can_be_iterated_multiple_times(self: Self) -> None:
|
|
150
|
+
items: Any = FrozenDictSlot({"a": 1, "b": 2}).items()
|
|
151
|
+
|
|
152
|
+
self.assertEqual(list(items), [("a", 1), ("b", 2)])
|
|
153
|
+
self.assertEqual(list(items), [("a", 1), ("b", 2)])
|
|
154
|
+
|
|
155
|
+
def test_items_rejects_arguments(self: Self) -> None:
|
|
156
|
+
with self.assertRaises(TypeError):
|
|
157
|
+
FrozenDictSlot({"a": 1}).items("unexpected") # type: ignore[call-arg]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class TestKeysMethod(unittest.TestCase):
|
|
161
|
+
def test_keys_contains_all_keys(self: Self) -> None:
|
|
162
|
+
mapping: Any = FrozenDictSlot({"a": 1, "b": 2, "c": 3})
|
|
163
|
+
|
|
164
|
+
self.assertEqual(set(mapping.keys()), {"a", "b", "c"})
|
|
165
|
+
|
|
166
|
+
def test_keys_of_empty_mapping_is_empty(self: Self) -> None:
|
|
167
|
+
self.assertEqual(list(FrozenDictSlot().keys()), [])
|
|
168
|
+
|
|
169
|
+
def test_keys_preserves_insertion_order(self: Self) -> None:
|
|
170
|
+
mapping: Any = FrozenDictSlot(
|
|
171
|
+
[
|
|
172
|
+
("third", 3),
|
|
173
|
+
("first", 1),
|
|
174
|
+
("second", 2),
|
|
175
|
+
]
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
self.assertEqual(
|
|
179
|
+
list(mapping.keys()),
|
|
180
|
+
["third", "first", "second"],
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def test_keys_supports_membership_testing(self: Self) -> None:
|
|
184
|
+
keys: Any = FrozenDictSlot({"a": 1, "b": 2}).keys()
|
|
185
|
+
|
|
186
|
+
self.assertIn("a", keys)
|
|
187
|
+
self.assertNotIn("missing", keys)
|
|
188
|
+
|
|
189
|
+
def test_keys_has_correct_length(self: Self) -> None:
|
|
190
|
+
keys: Any = FrozenDictSlot(
|
|
191
|
+
{
|
|
192
|
+
"a": 1,
|
|
193
|
+
"b": 2,
|
|
194
|
+
"c": 3,
|
|
195
|
+
}
|
|
196
|
+
).keys()
|
|
197
|
+
|
|
198
|
+
self.assertEqual(len(keys), 3)
|
|
199
|
+
|
|
200
|
+
def test_keys_supports_set_operations(self: Self) -> None:
|
|
201
|
+
keys: Any = FrozenDictSlot({"a": 1, "b": 2}).keys()
|
|
202
|
+
|
|
203
|
+
self.assertEqual(keys & {"b", "c"}, {"b"})
|
|
204
|
+
self.assertEqual(keys | {"c"}, {"a", "b", "c"})
|
|
205
|
+
|
|
206
|
+
def test_keys_rejects_arguments(self: Self) -> None:
|
|
207
|
+
with self.assertRaises(TypeError):
|
|
208
|
+
FrozenDictSlot({"a": 1}).keys("unexpected") # type: ignore[call-arg]
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class TestValuesMethod(unittest.TestCase):
|
|
212
|
+
def test_values_contains_all_values(self: Self) -> None:
|
|
213
|
+
mapping: Any = FrozenDictSlot({"a": 1, "b": 2, "c": 3})
|
|
214
|
+
|
|
215
|
+
self.assertEqual(list(mapping.values()), [1, 2, 3])
|
|
216
|
+
|
|
217
|
+
def test_values_of_empty_mapping_is_empty(self: Self) -> None:
|
|
218
|
+
self.assertEqual(list(FrozenDictSlot().values()), [])
|
|
219
|
+
|
|
220
|
+
def test_values_preserves_insertion_order(self: Self) -> None:
|
|
221
|
+
mapping: Any = FrozenDictSlot(
|
|
222
|
+
[
|
|
223
|
+
("third", 3),
|
|
224
|
+
("first", 1),
|
|
225
|
+
("second", 2),
|
|
226
|
+
]
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
self.assertEqual(list(mapping.values()), [3, 1, 2])
|
|
230
|
+
|
|
231
|
+
def test_values_preserves_duplicates(self: Self) -> None:
|
|
232
|
+
mapping: Any = FrozenDictSlot(
|
|
233
|
+
{
|
|
234
|
+
"a": 1,
|
|
235
|
+
"b": 1,
|
|
236
|
+
"c": 2,
|
|
237
|
+
}
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
self.assertEqual(list(mapping.values()), [1, 1, 2])
|
|
241
|
+
|
|
242
|
+
def test_values_supports_membership_testing(self: Self) -> None:
|
|
243
|
+
values: Any = FrozenDictSlot({"a": 1, "b": 2}).values()
|
|
244
|
+
|
|
245
|
+
self.assertIn(1, values)
|
|
246
|
+
self.assertNotIn(3, values)
|
|
247
|
+
|
|
248
|
+
def test_values_has_correct_length(self: Self) -> None:
|
|
249
|
+
values: Any = FrozenDictSlot(
|
|
250
|
+
{
|
|
251
|
+
"a": 1,
|
|
252
|
+
"b": 2,
|
|
253
|
+
"c": 3,
|
|
254
|
+
}
|
|
255
|
+
).values()
|
|
256
|
+
|
|
257
|
+
self.assertEqual(len(values), 3)
|
|
258
|
+
|
|
259
|
+
def test_values_can_be_iterated_multiple_times(self: Self) -> None:
|
|
260
|
+
values: Any = FrozenDictSlot({"a": 1, "b": 2}).values()
|
|
261
|
+
|
|
262
|
+
self.assertEqual(list(values), [1, 2])
|
|
263
|
+
self.assertEqual(list(values), [1, 2])
|
|
264
|
+
|
|
265
|
+
def test_values_rejects_arguments(self: Self) -> None:
|
|
266
|
+
with self.assertRaises(TypeError):
|
|
267
|
+
FrozenDictSlot({"a": 1}).values("unexpected") # type: ignore[call-arg]
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
if __name__ == "__main__":
|
|
271
|
+
unittest.main()
|
|
@@ -229,5 +229,248 @@ class TestNonMembershipOperator(unittest.TestCase):
|
|
|
229
229
|
self.assertFalse({1, 2} not in FrozenSetSlot({frozenset({1, 2})}))
|
|
230
230
|
|
|
231
231
|
|
|
232
|
+
class TestDifferenceMethod(unittest.TestCase):
|
|
233
|
+
def test_difference_with_overlapping_values(self: Self) -> None:
|
|
234
|
+
result = FrozenSetSlot({1, 2, 3}).difference({2, 3, 4})
|
|
235
|
+
|
|
236
|
+
self.assertEqual(result, frozenset({1}))
|
|
237
|
+
|
|
238
|
+
def test_difference_with_disjoint_values(self: Self) -> None:
|
|
239
|
+
result = FrozenSetSlot({1, 2}).difference({3, 4})
|
|
240
|
+
|
|
241
|
+
self.assertEqual(result, frozenset({1, 2}))
|
|
242
|
+
|
|
243
|
+
def test_difference_with_multiple_iterables(self: Self) -> None:
|
|
244
|
+
result = FrozenSetSlot({1, 2, 3, 4, 5}).difference(
|
|
245
|
+
{2, 3},
|
|
246
|
+
[4],
|
|
247
|
+
(5, 6),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
self.assertEqual(result, frozenset({1}))
|
|
251
|
+
|
|
252
|
+
def test_difference_without_arguments(self: Self) -> None:
|
|
253
|
+
result = FrozenSetSlot({1, 2}).difference()
|
|
254
|
+
|
|
255
|
+
self.assertEqual(result, frozenset({1, 2}))
|
|
256
|
+
|
|
257
|
+
def test_difference_returns_frozen_set_slot(self: Self) -> None:
|
|
258
|
+
result = FrozenSetSlot({1, 2, 3}).difference({3})
|
|
259
|
+
|
|
260
|
+
self.assertIsInstance(result, FrozenSetSlot)
|
|
261
|
+
|
|
262
|
+
def test_difference_rejects_non_iterable(self: Self) -> None:
|
|
263
|
+
with self.assertRaises(TypeError):
|
|
264
|
+
FrozenSetSlot({1, 2}).difference(3) # type: ignore[arg-type]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class TestIntersectionMethod(unittest.TestCase):
|
|
268
|
+
def test_intersection_with_overlapping_values(self: Self) -> None:
|
|
269
|
+
result = FrozenSetSlot({1, 2, 3}).intersection({2, 3, 4})
|
|
270
|
+
|
|
271
|
+
self.assertEqual(result, frozenset({2, 3}))
|
|
272
|
+
|
|
273
|
+
def test_intersection_with_disjoint_values(self: Self) -> None:
|
|
274
|
+
result = FrozenSetSlot({1, 2}).intersection({3, 4})
|
|
275
|
+
|
|
276
|
+
self.assertEqual(result, frozenset())
|
|
277
|
+
|
|
278
|
+
def test_intersection_with_multiple_iterables(self: Self) -> None:
|
|
279
|
+
result = FrozenSetSlot({1, 2, 3, 4}).intersection(
|
|
280
|
+
[2, 3, 4, 5],
|
|
281
|
+
(3, 4, 6),
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
self.assertEqual(result, frozenset({3, 4}))
|
|
285
|
+
|
|
286
|
+
def test_intersection_without_arguments(self: Self) -> None:
|
|
287
|
+
result = FrozenSetSlot({1, 2}).intersection()
|
|
288
|
+
|
|
289
|
+
self.assertEqual(result, frozenset({1, 2}))
|
|
290
|
+
|
|
291
|
+
def test_intersection_returns_frozen_set_slot(self: Self) -> None:
|
|
292
|
+
result = FrozenSetSlot({1, 2, 3}).intersection({2, 3})
|
|
293
|
+
|
|
294
|
+
self.assertIsInstance(result, FrozenSetSlot)
|
|
295
|
+
|
|
296
|
+
def test_intersection_accepts_generator(self: Self) -> None:
|
|
297
|
+
values = (value for value in range(2, 5))
|
|
298
|
+
result = FrozenSetSlot({1, 2, 3}).intersection(values)
|
|
299
|
+
|
|
300
|
+
self.assertEqual(result, frozenset({2, 3}))
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class TestIsDisjointMethod(unittest.TestCase):
|
|
304
|
+
def test_disjoint_iterables(self: Self) -> None:
|
|
305
|
+
result = FrozenSetSlot({1, 2}).isdisjoint({3, 4})
|
|
306
|
+
|
|
307
|
+
self.assertTrue(result)
|
|
308
|
+
|
|
309
|
+
def test_overlapping_iterables(self: Self) -> None:
|
|
310
|
+
result = FrozenSetSlot({1, 2, 3}).isdisjoint({3, 4})
|
|
311
|
+
|
|
312
|
+
self.assertFalse(result)
|
|
313
|
+
|
|
314
|
+
def test_empty_instance_is_disjoint(self: Self) -> None:
|
|
315
|
+
result = FrozenSetSlot().isdisjoint({1, 2})
|
|
316
|
+
|
|
317
|
+
self.assertTrue(result)
|
|
318
|
+
|
|
319
|
+
def test_is_disjoint_with_empty_iterable(self: Self) -> None:
|
|
320
|
+
result = FrozenSetSlot({1, 2}).isdisjoint([])
|
|
321
|
+
|
|
322
|
+
self.assertTrue(result)
|
|
323
|
+
|
|
324
|
+
def test_is_disjoint_accepts_generator(self: Self) -> None:
|
|
325
|
+
values = (value for value in range(3, 6))
|
|
326
|
+
result = FrozenSetSlot({1, 2, 3}).isdisjoint(values)
|
|
327
|
+
|
|
328
|
+
self.assertFalse(result)
|
|
329
|
+
|
|
330
|
+
def test_is_disjoint_rejects_non_iterable(self: Self) -> None:
|
|
331
|
+
with self.assertRaises(TypeError):
|
|
332
|
+
FrozenSetSlot({1, 2}).isdisjoint(3) # type: ignore[arg-type]
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
class TestIsSubsetMethod(unittest.TestCase):
|
|
336
|
+
def test_proper_subset(self: Self) -> None:
|
|
337
|
+
result = FrozenSetSlot({1, 2}).issubset({1, 2, 3})
|
|
338
|
+
|
|
339
|
+
self.assertTrue(result)
|
|
340
|
+
|
|
341
|
+
def test_equal_set_is_subset(self: Self) -> None:
|
|
342
|
+
result = FrozenSetSlot({1, 2}).issubset([2, 1])
|
|
343
|
+
|
|
344
|
+
self.assertTrue(result)
|
|
345
|
+
|
|
346
|
+
def test_non_subset(self: Self) -> None:
|
|
347
|
+
result = FrozenSetSlot({1, 2, 4}).issubset({1, 2, 3})
|
|
348
|
+
|
|
349
|
+
self.assertFalse(result)
|
|
350
|
+
|
|
351
|
+
def test_empty_instance_is_subset(self: Self) -> None:
|
|
352
|
+
result = FrozenSetSlot().issubset({1, 2})
|
|
353
|
+
|
|
354
|
+
self.assertTrue(result)
|
|
355
|
+
|
|
356
|
+
def test_nonempty_instance_is_not_subset_of_empty_iterable(
|
|
357
|
+
self: Self,
|
|
358
|
+
) -> None:
|
|
359
|
+
result = FrozenSetSlot({1}).issubset([])
|
|
360
|
+
|
|
361
|
+
self.assertFalse(result)
|
|
362
|
+
|
|
363
|
+
def test_is_subset_accepts_generator(self: Self) -> None:
|
|
364
|
+
values = (value for value in range(1, 4))
|
|
365
|
+
result = FrozenSetSlot({1, 2}).issubset(values)
|
|
366
|
+
|
|
367
|
+
self.assertTrue(result)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class TestIsSupersetMethod(unittest.TestCase):
|
|
371
|
+
def test_proper_superset(self: Self) -> None:
|
|
372
|
+
result = FrozenSetSlot({1, 2, 3}).issuperset({1, 2})
|
|
373
|
+
|
|
374
|
+
self.assertTrue(result)
|
|
375
|
+
|
|
376
|
+
def test_equal_set_is_superset(self: Self) -> None:
|
|
377
|
+
result = FrozenSetSlot({1, 2}).issuperset([2, 1])
|
|
378
|
+
|
|
379
|
+
self.assertTrue(result)
|
|
380
|
+
|
|
381
|
+
def test_non_superset(self: Self) -> None:
|
|
382
|
+
result = FrozenSetSlot({1, 2}).issuperset({1, 2, 3})
|
|
383
|
+
|
|
384
|
+
self.assertFalse(result)
|
|
385
|
+
|
|
386
|
+
def test_every_instance_is_superset_of_empty_iterable(self: Self) -> None:
|
|
387
|
+
result = FrozenSetSlot({1, 2}).issuperset([])
|
|
388
|
+
|
|
389
|
+
self.assertTrue(result)
|
|
390
|
+
|
|
391
|
+
def test_empty_instance_is_not_superset_of_nonempty_iterable(
|
|
392
|
+
self: Self,
|
|
393
|
+
) -> None:
|
|
394
|
+
result = FrozenSetSlot().issuperset({1})
|
|
395
|
+
|
|
396
|
+
self.assertFalse(result)
|
|
397
|
+
|
|
398
|
+
def test_is_superset_accepts_generator(self: Self) -> None:
|
|
399
|
+
values = (value for value in range(1, 3))
|
|
400
|
+
result = FrozenSetSlot({1, 2, 3}).issuperset(values)
|
|
401
|
+
|
|
402
|
+
self.assertTrue(result)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class TestSymmetricDifferenceMethod(unittest.TestCase):
|
|
406
|
+
def test_symmetric_difference_with_overlap(self: Self) -> None:
|
|
407
|
+
result = FrozenSetSlot({1, 2, 3}).symmetric_difference({3, 4})
|
|
408
|
+
|
|
409
|
+
self.assertEqual(result, frozenset({1, 2, 4}))
|
|
410
|
+
|
|
411
|
+
def test_symmetric_difference_with_disjoint_values(self: Self) -> None:
|
|
412
|
+
result = FrozenSetSlot({1, 2}).symmetric_difference([3, 4])
|
|
413
|
+
|
|
414
|
+
self.assertEqual(result, frozenset({1, 2, 3, 4}))
|
|
415
|
+
|
|
416
|
+
def test_symmetric_difference_with_equal_values(self: Self) -> None:
|
|
417
|
+
result = FrozenSetSlot({1, 2}).symmetric_difference((2, 1))
|
|
418
|
+
|
|
419
|
+
self.assertEqual(result, frozenset())
|
|
420
|
+
|
|
421
|
+
def test_symmetric_difference_with_empty_iterable(self: Self) -> None:
|
|
422
|
+
result = FrozenSetSlot({1, 2}).symmetric_difference([])
|
|
423
|
+
|
|
424
|
+
self.assertEqual(result, frozenset({1, 2}))
|
|
425
|
+
|
|
426
|
+
def test_symmetric_difference_returns_frozen_set_slot(self: Self) -> None:
|
|
427
|
+
result = FrozenSetSlot({1, 2}).symmetric_difference({2, 3})
|
|
428
|
+
|
|
429
|
+
self.assertIsInstance(result, FrozenSetSlot)
|
|
430
|
+
|
|
431
|
+
def test_symmetric_difference_rejects_multiple_arguments(
|
|
432
|
+
self: Self,
|
|
433
|
+
) -> None:
|
|
434
|
+
with self.assertRaises(TypeError):
|
|
435
|
+
FrozenSetSlot({1, 2}).symmetric_difference({2}, {3}) # type: ignore[call-arg]
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class TestUnionMethod(unittest.TestCase):
|
|
439
|
+
def test_union_with_overlapping_values(self: Self) -> None:
|
|
440
|
+
result = FrozenSetSlot({1, 2, 3}).union({3, 4})
|
|
441
|
+
|
|
442
|
+
self.assertEqual(result, frozenset({1, 2, 3, 4}))
|
|
443
|
+
|
|
444
|
+
def test_union_with_disjoint_values(self: Self) -> None:
|
|
445
|
+
result = FrozenSetSlot({1, 2}).union([3, 4])
|
|
446
|
+
|
|
447
|
+
self.assertEqual(result, frozenset({1, 2, 3, 4}))
|
|
448
|
+
|
|
449
|
+
def test_union_with_multiple_iterables(self: Self) -> None:
|
|
450
|
+
result = FrozenSetSlot({1}).union(
|
|
451
|
+
[2, 3],
|
|
452
|
+
(3, 4),
|
|
453
|
+
frozenset({5}),
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
self.assertEqual(result, frozenset({1, 2, 3, 4, 5}))
|
|
457
|
+
|
|
458
|
+
def test_union_without_arguments(self: Self) -> None:
|
|
459
|
+
result = FrozenSetSlot({1, 2}).union()
|
|
460
|
+
|
|
461
|
+
self.assertEqual(result, frozenset({1, 2}))
|
|
462
|
+
|
|
463
|
+
def test_union_returns_frozen_set_slot(self: Self) -> None:
|
|
464
|
+
result = FrozenSetSlot({1, 2}).union({3})
|
|
465
|
+
|
|
466
|
+
self.assertIsInstance(result, FrozenSetSlot)
|
|
467
|
+
|
|
468
|
+
def test_union_accepts_generator(self: Self) -> None:
|
|
469
|
+
values = (value for value in range(2, 5))
|
|
470
|
+
result = FrozenSetSlot({1, 2}).union(values)
|
|
471
|
+
|
|
472
|
+
self.assertEqual(result, frozenset({1, 2, 3, 4}))
|
|
473
|
+
|
|
474
|
+
|
|
232
475
|
if __name__ == "__main__":
|
|
233
476
|
unittest.main()
|
|
@@ -136,8 +136,7 @@ class TestGet(unittest.TestCase):
|
|
|
136
136
|
def test_get_rejects_unhashable_key(self: Self) -> None:
|
|
137
137
|
value: MutableDictSlot[Any, Any]
|
|
138
138
|
value = MutableDictSlot({"a": 1})
|
|
139
|
-
|
|
140
|
-
value.get([])
|
|
139
|
+
self.assertIsNone(value.get([]))
|
|
141
140
|
self.assertEqual(value, {"a": 1})
|
|
142
141
|
|
|
143
142
|
|
|
@@ -141,6 +141,10 @@ args = [
|
|
|
141
141
|
[datatypes.FrozenListSlot.varia]
|
|
142
142
|
generic = 1
|
|
143
143
|
|
|
144
|
+
[datatypes.FrozenObjectLike.issubclass]
|
|
145
|
+
"collections.abc.Hashable" = true
|
|
146
|
+
"datahold.Object" = true
|
|
147
|
+
|
|
144
148
|
[datatypes.FrozenObjectSlot.issubclass]
|
|
145
149
|
"datahold.ObjectSlot" = true
|
|
146
150
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|