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.
Files changed (40) hide show
  1. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/PKG-INFO +1 -1
  2. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/pyproject.toml +1 -1
  3. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold/__init__.py +126 -32
  4. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/PKG-INFO +1 -1
  5. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenDictSlot.py +0 -41
  6. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableDictSlot.py +321 -12
  7. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableListSlot.py +219 -180
  8. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_MutableSetSlot.py +365 -32
  9. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_abstractmethods.py +1 -1
  10. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_attributes.py +2 -0
  11. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_docs.py +4 -0
  12. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_generic.py +2 -0
  13. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_issubclass.py +8 -1
  14. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_metaclass.py +1 -0
  15. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_name.py +4 -1
  16. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_nested.py +15 -1
  17. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_sorted.py +2 -0
  18. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_variance.py +7 -1
  19. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/testdata.toml +19 -0
  20. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/LICENSE.txt +0 -0
  21. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/MANIFEST.in +0 -0
  22. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/README.rst +0 -0
  23. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v1.1.rst +0 -0
  24. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v1.2.rst +0 -0
  25. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.0.rst +0 -0
  26. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.1.rst +0 -0
  27. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.2.rst +0 -0
  28. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v2.3.rst +0 -0
  29. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v3.0.rst +0 -0
  30. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/docs/v4.0.rst +0 -0
  31. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/run_tests.py +0 -0
  32. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/setup.cfg +0 -0
  33. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold/py.typed +0 -0
  34. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/SOURCES.txt +0 -0
  35. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/dependency_links.txt +0 -0
  36. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/requires.txt +0 -0
  37. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/src/datahold.egg-info/top_level.txt +0 -0
  38. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenListSlot.py +0 -0
  39. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_FrozenSetSlot.py +0 -0
  40. {datahold-4.0.0.dev31 → datahold-4.0.0.dev33}/tests/test_all.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 4.0.0.dev31
3
+ Version: 4.0.0.dev33
4
4
  Summary: This project wraps common mutable datastructures for inheritance with modification.
5
5
  Author-email: Johannes <johannes.programming@gmail.com>
6
6
  License-Expression: MIT
@@ -31,7 +31,7 @@ license-files = [
31
31
  name = "datahold"
32
32
  readme = "README.rst"
33
33
  requires-python = ">=3.11"
34
- version = "4.0.0.dev31"
34
+ version = "4.0.0.dev33"
35
35
 
36
36
  [project.urls]
37
37
  Download = "https://pypi.org/project/datahold/#files"
@@ -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 Any, Never, Protocol, Self, SupportsIndex, overload
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
- class SupportsKeysAndGetitem[Key, Value](Protocol):
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
- class SupportsDelitemAndSetitem[Key, Value](
109
+
110
+
111
+ class SupportsDelItemAndSetItem[Key, Value](
93
112
  Protocol,
94
113
  ):
95
114
  @setdoc.basic
96
- def __delitem__(self: Self, key: Key | str, /) -> object: ...
115
+ def __delitem__(self: Self, key: Key, /) -> object: ...
97
116
  @setdoc.basic
98
- def __setitem__(
99
- self: Self, key: Key | str, value: Value | None, /
100
- ) -> object: ...
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
- SupportsKeysAndGetitem[Key, Value | None]
169
- | SupportsKeysAndGetitem[Key | str, Value | None]
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
- SupportsDelitemAndSetitem[Key | str, Value | None],
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 | str, Value | None],
513
- abc.Reversible[Key | str],
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, /) -> FrozenDict[Key, Value]: ...
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: Dict_Init[Key_, Value_],
613
+ other: DictLike[Key_, Value_],
535
614
  /,
536
615
  ) -> DictLike[Key | Key_, Value | Value_]:
537
- other_: FrozenDict[Key, Value]
538
- try:
539
- other_ = frozendict(other) # type: ignore[arg-type]
540
- except TypeError:
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 | str]:
548
- yield from reversed(self.__frozen__())
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 | str],
555
- value: Value | None = None,
632
+ iterable: abc.Iterable[Key],
556
633
  /,
557
- ) -> Self:
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[FrozenDict[Key, Value]],
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, # type: ignore[arg-type]
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[FrozenDict[Key, Value]],
716
+ FrozenObjectSlot[frozendict[Key, Value]],
623
717
  FrozenDictLike[Key, Value],
624
718
  ):
625
719
  """Provide slotted frozen dict-like."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 4.0.0.dev31
3
+ Version: 4.0.0.dev33
4
4
  Summary: This project wraps common mutable datastructures for inheritance with modification.
5
5
  Author-email: Johannes <johannes.programming@gmail.com>
6
6
  License-Expression: MIT
@@ -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)