datahold 4.0.0.dev31__tar.gz → 4.0.0.dev33__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.dev31 → datahold-4.0.0.dev33}/PKG-INFO +1 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/pyproject.toml +1 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold/__init__.py +126 -32
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/PKG-INFO +1 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenDictSlot.py +0 -41
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableDictSlot.py +321 -12
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableListSlot.py +219 -180
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableSetSlot.py +365 -32
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_abstractmethods.py +1 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_attributes.py +2 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_docs.py +4 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_generic.py +2 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_issubclass.py +8 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_metaclass.py +1 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_name.py +4 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_nested.py +15 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_sorted.py +2 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_variance.py +7 -1
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/testdata.toml +19 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/LICENSE.txt +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/MANIFEST.in +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/README.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v1.1.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v1.2.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.0.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.1.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.2.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.3.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v3.0.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v4.0.rst +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/run_tests.py +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/setup.cfg +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold/py.typed +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/SOURCES.txt +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/dependency_links.txt +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/requires.txt +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/top_level.txt +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenListSlot.py +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenSetSlot.py +0 -0
- {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_all.py +0 -0
|
@@ -33,15 +33,31 @@ __all__: list[str] = [
|
|
|
33
33
|
"SetLike",
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
+
import enum
|
|
36
37
|
from abc import ABCMeta, abstractmethod
|
|
37
38
|
from collections import abc
|
|
38
39
|
from contextlib import contextmanager
|
|
39
40
|
from types import NotImplementedType, TracebackType
|
|
40
|
-
from typing import
|
|
41
|
+
from typing import (
|
|
42
|
+
Any,
|
|
43
|
+
Never,
|
|
44
|
+
Protocol,
|
|
45
|
+
Self,
|
|
46
|
+
SupportsIndex,
|
|
47
|
+
overload,
|
|
48
|
+
runtime_checkable,
|
|
49
|
+
)
|
|
41
50
|
|
|
42
51
|
import setdoc
|
|
43
52
|
from frozendict import frozendict
|
|
44
53
|
|
|
54
|
+
### SENTINEL ###
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Missing(enum.Enum):
|
|
58
|
+
MISSING = enum.auto()
|
|
59
|
+
|
|
60
|
+
|
|
45
61
|
### PROTOCOLS ###
|
|
46
62
|
|
|
47
63
|
|
|
@@ -61,7 +77,8 @@ class ContextManager[Enter](Protocol):
|
|
|
61
77
|
) -> object: ...
|
|
62
78
|
|
|
63
79
|
|
|
64
|
-
|
|
80
|
+
@runtime_checkable
|
|
81
|
+
class SupportsKeysAndGetItem[Key, Value](Protocol):
|
|
65
82
|
"""Provide protocol supporting keys and __getitem__."""
|
|
66
83
|
|
|
67
84
|
@setdoc.basic
|
|
@@ -89,15 +106,17 @@ class SupportsAddAndDiscard[Item: abc.Hashable](Protocol):
|
|
|
89
106
|
class Mapping_Frozen[Key, Value](Collection_Frozen[Key], Protocol):
|
|
90
107
|
@setdoc.basic
|
|
91
108
|
def __getitem__(self: Self, key: Never, /) -> Value: ...
|
|
92
|
-
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class SupportsDelItemAndSetItem[Key, Value](
|
|
93
112
|
Protocol,
|
|
94
113
|
):
|
|
95
114
|
@setdoc.basic
|
|
96
|
-
def __delitem__(self: Self, key: Key
|
|
115
|
+
def __delitem__(self: Self, key: Key, /) -> object: ...
|
|
97
116
|
@setdoc.basic
|
|
98
|
-
def __setitem__(
|
|
99
|
-
|
|
100
|
-
|
|
117
|
+
def __setitem__(self: Self, key: Key, value: Value, /) -> object: ...
|
|
118
|
+
|
|
119
|
+
|
|
101
120
|
class Sequence_Frozen[Item](
|
|
102
121
|
Collection_Frozen[Item],
|
|
103
122
|
Protocol,
|
|
@@ -165,8 +184,9 @@ class MutableSequence_Mutable[Item](Protocol):
|
|
|
165
184
|
type Dict[Key, Value] = dict[Key | str, Value | None]
|
|
166
185
|
|
|
167
186
|
type Dict_Init[Key, Value] = (
|
|
168
|
-
|
|
169
|
-
|
|
|
187
|
+
SupportsKeysAndGetItem[Key, Value | None]
|
|
188
|
+
| SupportsKeysAndGetItem[str, Value | None]
|
|
189
|
+
| SupportsKeysAndGetItem[Key | str, Value | None]
|
|
170
190
|
| abc.Iterable[tuple[Key | str, Value | None]]
|
|
171
191
|
)
|
|
172
192
|
|
|
@@ -320,9 +340,11 @@ class SetLike[Item: abc.Hashable](Set[Item]):
|
|
|
320
340
|
@abstractmethod
|
|
321
341
|
@setdoc.basic
|
|
322
342
|
def __frozen__(self: Self, /) -> frozenset[Item]: ...
|
|
343
|
+
|
|
323
344
|
@abstractmethod
|
|
324
345
|
@setdoc.basic
|
|
325
346
|
def __init__(self: Self, other: abc.Iterable[Item] = (), /) -> None: ...
|
|
347
|
+
|
|
326
348
|
@setdoc.basic
|
|
327
349
|
def difference(self: Self, /, *others: abc.Iterable[abc.Hashable]) -> Self:
|
|
328
350
|
return type(self)(self.__frozen__().difference(*others))
|
|
@@ -481,11 +503,11 @@ class Mapping[Key: abc.Hashable, Value](
|
|
|
481
503
|
|
|
482
504
|
|
|
483
505
|
class MutableMapping[Key: abc.Hashable, Value](
|
|
484
|
-
Mapping[Key, Value],
|
|
506
|
+
Mapping[Key | str, Value | None],
|
|
485
507
|
abc.MutableMapping[Key | str, Value | None],
|
|
486
508
|
MutableObject[
|
|
487
509
|
Mapping_Frozen[Key | str, Value | None],
|
|
488
|
-
|
|
510
|
+
SupportsDelItemAndSetItem[Key | str, Value | None],
|
|
489
511
|
],
|
|
490
512
|
):
|
|
491
513
|
"""Provide abc for custom mutable mapping."""
|
|
@@ -504,13 +526,69 @@ class MutableMapping[Key: abc.Hashable, Value](
|
|
|
504
526
|
with self.__mutate__() as mutable:
|
|
505
527
|
mutable[key] = value
|
|
506
528
|
|
|
529
|
+
@overload
|
|
530
|
+
@setdoc.basic
|
|
531
|
+
def pop(self: Self, key: Key | str, /) -> Value: ...
|
|
532
|
+
@overload
|
|
533
|
+
@setdoc.basic
|
|
534
|
+
def pop[Value_](
|
|
535
|
+
self: Self, key: Key | str, default: Value_, /
|
|
536
|
+
) -> Value | Value_: ...
|
|
537
|
+
@setdoc.basic
|
|
538
|
+
def pop[Value_](
|
|
539
|
+
self: Self,
|
|
540
|
+
key: Key | str,
|
|
541
|
+
default: Missing | Value_ = Missing.MISSING,
|
|
542
|
+
/,
|
|
543
|
+
) -> Value | Value_ | None:
|
|
544
|
+
try:
|
|
545
|
+
value = self[key]
|
|
546
|
+
except KeyError:
|
|
547
|
+
if isinstance(default, Missing):
|
|
548
|
+
raise
|
|
549
|
+
return default
|
|
550
|
+
else:
|
|
551
|
+
del self[key]
|
|
552
|
+
return value
|
|
553
|
+
|
|
554
|
+
@setdoc.basic
|
|
555
|
+
def setdefault(
|
|
556
|
+
self: Self,
|
|
557
|
+
key: Key | str,
|
|
558
|
+
default: Value | None = None,
|
|
559
|
+
/,
|
|
560
|
+
) -> Value | None:
|
|
561
|
+
try:
|
|
562
|
+
return self[key]
|
|
563
|
+
except KeyError:
|
|
564
|
+
self[key] = default
|
|
565
|
+
return default
|
|
566
|
+
|
|
567
|
+
@setdoc.basic
|
|
568
|
+
def update(
|
|
569
|
+
self: Self,
|
|
570
|
+
other: Dict_Init[Key, Value] = (),
|
|
571
|
+
/,
|
|
572
|
+
**kwargs: Value | None,
|
|
573
|
+
) -> None:
|
|
574
|
+
key: Any
|
|
575
|
+
value: Value | None
|
|
576
|
+
if isinstance(other, SupportsKeysAndGetItem):
|
|
577
|
+
for key in other.keys():
|
|
578
|
+
self[key] = other[key]
|
|
579
|
+
else:
|
|
580
|
+
for key, value in other:
|
|
581
|
+
self[key] = value
|
|
582
|
+
for key, value in kwargs.items():
|
|
583
|
+
self[key] = value
|
|
584
|
+
|
|
507
585
|
|
|
508
586
|
### DICT-LIKE ###
|
|
509
587
|
|
|
510
588
|
|
|
511
589
|
class DictLike[Key: abc.Hashable, Value](
|
|
512
|
-
Mapping[Key
|
|
513
|
-
abc.Reversible[Key
|
|
590
|
+
Mapping[Key, Value],
|
|
591
|
+
abc.Reversible[Key],
|
|
514
592
|
):
|
|
515
593
|
"""Provide abc for custom dict-like."""
|
|
516
594
|
|
|
@@ -518,7 +596,7 @@ class DictLike[Key: abc.Hashable, Value](
|
|
|
518
596
|
|
|
519
597
|
@abstractmethod
|
|
520
598
|
@setdoc.basic
|
|
521
|
-
def __frozen__(self: Self, /) ->
|
|
599
|
+
def __frozen__(self: Self, /) -> frozendict[Key, Value]: ...
|
|
522
600
|
|
|
523
601
|
@abstractmethod
|
|
524
602
|
@setdoc.basic
|
|
@@ -528,38 +606,54 @@ class DictLike[Key: abc.Hashable, Value](
|
|
|
528
606
|
/,
|
|
529
607
|
**kwargs: Value,
|
|
530
608
|
): ...
|
|
609
|
+
|
|
531
610
|
@setdoc.basic
|
|
532
611
|
def __or__[Key_: abc.Hashable, Value_](
|
|
533
612
|
self: Self,
|
|
534
|
-
other:
|
|
613
|
+
other: DictLike[Key_, Value_],
|
|
535
614
|
/,
|
|
536
615
|
) -> DictLike[Key | Key_, Value | Value_]:
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
616
|
+
if isinstance(other, DictLike):
|
|
617
|
+
return type(self)( # type: ignore[return-value]
|
|
618
|
+
self.__frozen__() | other # type: ignore[arg-type]
|
|
619
|
+
)
|
|
620
|
+
else:
|
|
541
621
|
return NotImplemented
|
|
542
|
-
return type(self)( # type: ignore[return-value]
|
|
543
|
-
self.__frozen__() | other_
|
|
544
|
-
)
|
|
545
622
|
|
|
546
623
|
@setdoc.basic
|
|
547
|
-
def __reversed__(self: Self, /) -> abc.Iterator[Key
|
|
548
|
-
|
|
624
|
+
def __reversed__(self: Self, /) -> abc.Iterator[Key]:
|
|
625
|
+
return reversed(self.__frozen__())
|
|
549
626
|
|
|
627
|
+
@overload
|
|
550
628
|
@classmethod
|
|
551
629
|
@setdoc.basic
|
|
552
630
|
def fromkeys(
|
|
553
631
|
cls: type[Self],
|
|
554
|
-
iterable: abc.Iterable[Key
|
|
555
|
-
value: Value | None = None,
|
|
632
|
+
iterable: abc.Iterable[Key],
|
|
556
633
|
/,
|
|
557
|
-
) ->
|
|
634
|
+
) -> DictLike[Key, None]: ...
|
|
635
|
+
@overload
|
|
636
|
+
@classmethod
|
|
637
|
+
@setdoc.basic
|
|
638
|
+
def fromkeys(
|
|
639
|
+
cls: type[Self],
|
|
640
|
+
iterable: abc.Iterable[Key],
|
|
641
|
+
value: Value,
|
|
642
|
+
/,
|
|
643
|
+
) -> Self: ...
|
|
644
|
+
@classmethod
|
|
645
|
+
@setdoc.basic
|
|
646
|
+
def fromkeys(
|
|
647
|
+
cls: type[Self],
|
|
648
|
+
iterable: abc.Iterable[Key],
|
|
649
|
+
value: Any = None,
|
|
650
|
+
/,
|
|
651
|
+
) -> Any:
|
|
558
652
|
return cls(dict.fromkeys(iterable, value))
|
|
559
653
|
|
|
560
654
|
|
|
561
655
|
class FrozenDictLike[Key: abc.Hashable, Value](
|
|
562
|
-
FrozenObjectLike[
|
|
656
|
+
FrozenObjectLike[frozendict[Key, Value]],
|
|
563
657
|
DictLike[Key, Value],
|
|
564
658
|
):
|
|
565
659
|
"""Provide abc for custom frozen dict-like."""
|
|
@@ -568,7 +662,7 @@ class FrozenDictLike[Key: abc.Hashable, Value](
|
|
|
568
662
|
|
|
569
663
|
|
|
570
664
|
class MutableDictLike[Key: abc.Hashable, Value](
|
|
571
|
-
DictLike[Key, Value],
|
|
665
|
+
DictLike[Key | str, Value | None],
|
|
572
666
|
MutableObjectLike[FrozenDict[Key, Value], Dict[Key, Value]],
|
|
573
667
|
MutableMapping[Key, Value],
|
|
574
668
|
):
|
|
@@ -590,9 +684,9 @@ class MutableDictLike[Key: abc.Hashable, Value](
|
|
|
590
684
|
other: Dict_Init[Key, Value] = (),
|
|
591
685
|
/,
|
|
592
686
|
**kwargs: Value | None,
|
|
593
|
-
):
|
|
687
|
+
) -> None:
|
|
594
688
|
self.update(
|
|
595
|
-
other,
|
|
689
|
+
other,
|
|
596
690
|
**kwargs,
|
|
597
691
|
)
|
|
598
692
|
|
|
@@ -619,7 +713,7 @@ class MutableDictLike[Key: abc.Hashable, Value](
|
|
|
619
713
|
|
|
620
714
|
|
|
621
715
|
class FrozenDictSlot[Key: abc.Hashable, Value](
|
|
622
|
-
FrozenObjectSlot[
|
|
716
|
+
FrozenObjectSlot[frozendict[Key, Value]],
|
|
623
717
|
FrozenDictLike[Key, Value],
|
|
624
718
|
):
|
|
625
719
|
"""Provide slotted frozen dict-like."""
|
|
@@ -17,7 +17,6 @@ __all__: list[str] = [
|
|
|
17
17
|
"TestOperatorReversed",
|
|
18
18
|
"TestOperatorSubscription",
|
|
19
19
|
"TestOperatorTruth",
|
|
20
|
-
"TestOperatorUnion",
|
|
21
20
|
]
|
|
22
21
|
import unittest
|
|
23
22
|
from collections import abc
|
|
@@ -430,46 +429,6 @@ class TestOperatorInequality(unittest.TestCase):
|
|
|
430
429
|
self.assertFalse(value != {"a": 1})
|
|
431
430
|
|
|
432
431
|
|
|
433
|
-
class TestOperatorUnion(unittest.TestCase):
|
|
434
|
-
def test_disjoint_mappings(self: Self, /) -> None:
|
|
435
|
-
left: FrozenDictSlot[Any, Any]
|
|
436
|
-
result: Any
|
|
437
|
-
left = FrozenDictSlot({"a": 1})
|
|
438
|
-
result = left | {"b": 2}
|
|
439
|
-
self.assertEqual(result, {"a": 1, "b": 2})
|
|
440
|
-
|
|
441
|
-
def test_right_operand_overrides(self: Self, /) -> None:
|
|
442
|
-
left: FrozenDictSlot[Any, Any]
|
|
443
|
-
result: Any
|
|
444
|
-
left = FrozenDictSlot({"a": 1, "b": 2})
|
|
445
|
-
result = left | {"b": 20}
|
|
446
|
-
self.assertEqual(result, {"a": 1, "b": 20})
|
|
447
|
-
|
|
448
|
-
def test_union_with_empty_dictionary(self: Self, /) -> None:
|
|
449
|
-
left: FrozenDictSlot[Any, Any]
|
|
450
|
-
result: Any
|
|
451
|
-
left = FrozenDictSlot({"a": 1})
|
|
452
|
-
result = left | {}
|
|
453
|
-
self.assertEqual(result, {"a": 1})
|
|
454
|
-
|
|
455
|
-
def test_union_does_not_change_left_operand(self: Self, /) -> None:
|
|
456
|
-
answer: FrozenDictSlot[str, int]
|
|
457
|
-
left: FrozenDictSlot[str, int]
|
|
458
|
-
solution: FrozenDictSlot[str, int]
|
|
459
|
-
left = FrozenDictSlot({"a": 1})
|
|
460
|
-
answer = left | {"b": 2} # type: ignore[operator]
|
|
461
|
-
# this is the only mypy suppression
|
|
462
|
-
# that seemingly stems not from a faulty typeshed
|
|
463
|
-
# but from a fault in mypy itself
|
|
464
|
-
# FrozenDictSlot[str, int].__or__
|
|
465
|
-
# annotates SupportsKeyAndGetitem[str, int | None]
|
|
466
|
-
# which is covariant in the second parameter
|
|
467
|
-
# and therefore should work
|
|
468
|
-
solution = FrozenDictSlot({"a": 1, "b": 2})
|
|
469
|
-
self.assertEqual(answer, solution)
|
|
470
|
-
self.assertEqual(left, {"a": 1})
|
|
471
|
-
|
|
472
|
-
|
|
473
432
|
class TestOperatorLength(unittest.TestCase):
|
|
474
433
|
def test_empty_mapping(self: Self, /) -> None:
|
|
475
434
|
self.assertEqual(len(FrozenDictSlot({})), 0)
|