datahold 3.0.0.dev2__tar.gz → 3.0.0.dev3__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 (50) hide show
  1. {datahold-3.0.0.dev2/src/datahold.egg-info → datahold-3.0.0.dev3}/PKG-INFO +1 -1
  2. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/pyproject.toml +1 -1
  3. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/tests/test_0.py +20 -18
  4. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestAbstractness.py +54 -0
  5. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestCopy.py +85 -0
  6. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestDataAttribute.py +55 -0
  7. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestFrozenMutability.py +38 -0
  8. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestInheritance.py +62 -0
  9. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestMutableBehavior.py +38 -0
  10. datahold-3.0.0.dev3/src/datahold/tests/test_datahold_TestProtocols.py +66 -0
  11. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/tests/test_generic.py +2 -0
  12. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3/src/datahold.egg-info}/PKG-INFO +1 -1
  13. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold.egg-info/SOURCES.txt +7 -1
  14. datahold-3.0.0.dev2/src/datahold/tests/test_datahold.py +0 -298
  15. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/LICENSE.txt +0 -0
  16. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/MANIFEST.in +0 -0
  17. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/README.rst +0 -0
  18. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/setup.cfg +0 -0
  19. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/__init__.py +0 -0
  20. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/_utils/__init__.py +0 -0
  21. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/_utils/wrapping.py +0 -0
  22. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseDataDict.py +0 -0
  23. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseDataList.py +0 -0
  24. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseDataObject.py +0 -0
  25. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseDataSet.py +0 -0
  26. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseHoldDict.py +0 -0
  27. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseHoldList.py +0 -0
  28. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseHoldObject.py +0 -0
  29. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/BaseHoldSet.py +0 -0
  30. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/DataDict.py +0 -0
  31. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/DataList.py +0 -0
  32. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/DataObject.py +0 -0
  33. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/DataSet.py +0 -0
  34. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenDataDict.py +0 -0
  35. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenDataList.py +0 -0
  36. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenDataObject.py +0 -0
  37. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenDataSet.py +0 -0
  38. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenHoldDict.py +0 -0
  39. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenHoldList.py +0 -0
  40. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenHoldObject.py +0 -0
  41. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/FrozenHoldSet.py +0 -0
  42. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/HoldDict.py +0 -0
  43. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/HoldList.py +0 -0
  44. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/HoldObject.py +0 -0
  45. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/HoldSet.py +0 -0
  46. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/core/__init__.py +0 -0
  47. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold/tests/__init__.py +0 -0
  48. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold.egg-info/dependency_links.txt +0 -0
  49. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold.egg-info/requires.txt +0 -0
  50. {datahold-3.0.0.dev2 → datahold-3.0.0.dev3}/src/datahold.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 3.0.0.dev2
3
+ Version: 3.0.0.dev3
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: The MIT License (MIT)
@@ -32,7 +32,7 @@ keywords = []
32
32
  name = "datahold"
33
33
  readme = "README.rst"
34
34
  requires-python = ">=3.11"
35
- version = "3.0.0.dev2"
35
+ version = "3.0.0.dev3"
36
36
 
37
37
  [project.license]
38
38
  file = "LICENSE.txt"
@@ -8,18 +8,18 @@ from datahold.core import *
8
8
  class TestData(unittest.TestCase):
9
9
  def test_constructor(self: Self) -> None:
10
10
  with self.assertRaises(Exception):
11
- DataDict()
11
+ core.DataDict.DataDict()
12
12
  with self.assertRaises(Exception):
13
- DataList()
13
+ core.DataList.DataList()
14
14
  with self.assertRaises(Exception):
15
- DataSet()
15
+ core.DataSet.DataSet()
16
16
 
17
17
 
18
18
  class TestHold(unittest.TestCase):
19
19
  def test_constructor(self: Self) -> None:
20
- HoldDict()
21
- HoldList()
22
- HoldSet()
20
+ core.HoldDict.HoldDict()
21
+ core.HoldList.HoldList()
22
+ core.HoldSet.HoldSet()
23
23
 
24
24
 
25
25
  class TestDoc(unittest.TestCase):
@@ -34,26 +34,28 @@ class TestDoc(unittest.TestCase):
34
34
  self.go(name=name)
35
35
 
36
36
  def go(self: Self, name: str) -> None:
37
- a: Any
38
- b: Any
37
+ attrname: Any
38
+ cls: Any
39
39
  doc: Any
40
40
  error: Any
41
+ member: Any
42
+ module: Any
41
43
  obj: Any
42
- y: Any
43
- y = getattr(core, name)
44
- for a in dir(y):
45
- b = getattr(y, a)
46
- if not callable(b) and not isinstance(b, property):
44
+ module = getattr(core, name)
45
+ cls = getattr(module, name)
46
+ for attrname in dir(cls):
47
+ member = getattr(cls, attrname)
48
+ if not callable(member) and not isinstance(member, property):
47
49
  continue
48
- if getattr(b, "__isabstractmethod__", False):
50
+ if getattr(member, "__isabstractmethod__", False):
49
51
  continue
50
- if a == "__subclasshook__":
52
+ if attrname == "__subclasshook__":
51
53
  continue
52
- doc = getattr(b, "__doc__", None)
53
- error = "%r inside %r has no docstring" % (a, name)
54
+ doc = getattr(member, "__doc__", None)
55
+ error = "%r inside %r has no docstring" % (attrname, name)
54
56
  self.assertNotEqual(doc, None, error)
55
57
  try:
56
- obj = y()
58
+ obj = cls()
57
59
  except TypeError:
58
60
  return
59
61
  with self.assertRaises(AttributeError):
@@ -0,0 +1,54 @@
1
+ import unittest
2
+ from inspect import isabstract
3
+ from typing import Self
4
+
5
+ from frozendict import frozendict
6
+
7
+ from datahold.core.DataDict import DataDict
8
+ from datahold.core.DataList import DataList
9
+ from datahold.core.DataObject import DataObject
10
+ from datahold.core.DataSet import DataSet
11
+ from datahold.core.FrozenDataDict import FrozenDataDict
12
+ from datahold.core.FrozenDataList import FrozenDataList
13
+ from datahold.core.FrozenDataObject import FrozenDataObject
14
+ from datahold.core.FrozenDataSet import FrozenDataSet
15
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
16
+ from datahold.core.FrozenHoldList import FrozenHoldList
17
+ from datahold.core.FrozenHoldObject import FrozenHoldObject
18
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
19
+ from datahold.core.HoldDict import HoldDict
20
+ from datahold.core.HoldList import HoldList
21
+ from datahold.core.HoldSet import HoldSet
22
+
23
+ __all__ = ["TestAbstractness"]
24
+
25
+
26
+ class TestAbstractness(unittest.TestCase):
27
+ def test_abstract_classes(self: Self) -> None:
28
+ # data
29
+ self.assertTrue(isabstract(DataObject))
30
+ self.assertTrue(isabstract(DataDict))
31
+ self.assertTrue(isabstract(DataList))
32
+ self.assertTrue(isabstract(DataSet))
33
+
34
+ self.assertTrue(isabstract(FrozenDataObject))
35
+ self.assertTrue(isabstract(FrozenDataDict))
36
+ self.assertTrue(isabstract(FrozenDataList))
37
+ self.assertTrue(isabstract(FrozenDataSet))
38
+
39
+ # hold
40
+ self.assertFalse(isabstract(FrozenHoldObject))
41
+ # self.assertFalse(isabstract(HoldObject))
42
+
43
+ def test_concrete_classes(self: Self) -> None:
44
+ FrozenHoldDict({"a": 1})
45
+ FrozenHoldList([1, 2])
46
+ FrozenHoldSet({1, 2})
47
+
48
+ HoldDict({"a": 1})
49
+ HoldList([1, 2])
50
+ HoldSet({1, 2})
51
+
52
+
53
+ if __name__ == "__main__":
54
+ unittest.main()
@@ -0,0 +1,85 @@
1
+ import unittest
2
+ from typing import Any, Self
3
+
4
+ from frozendict import frozendict
5
+
6
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
7
+ from datahold.core.FrozenHoldList import FrozenHoldList
8
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
9
+ from datahold.core.HoldDict import HoldDict
10
+ from datahold.core.HoldList import HoldList
11
+ from datahold.core.HoldSet import HoldSet
12
+
13
+ __all__ = ["TestCopy"]
14
+
15
+
16
+ class TestCopy(unittest.TestCase):
17
+ def test_frozen_have_no_copy(self: Self) -> None:
18
+ self.assertFalse(hasattr(FrozenHoldDict({"a": 1}), "copy"))
19
+ self.assertFalse(hasattr(FrozenHoldList([1, 2]), "copy"))
20
+ self.assertFalse(hasattr(FrozenHoldSet({1, 2}), "copy"))
21
+
22
+ def test_frozen_have_no_copy_2(self: Self) -> None:
23
+ """
24
+ Frozen classes should not define their own copy method.
25
+ (If a parent class or wrapped object exposes one, we ignore that.)
26
+ """
27
+ args: Any
28
+ cls: Any
29
+ copy_obj: Any
30
+ obj: Any
31
+ for cls, args in (
32
+ (FrozenHoldDict, ({"a": 1},)),
33
+ (FrozenHoldList, ([1, 2],)),
34
+ (FrozenHoldSet, ({1, 2},)),
35
+ ):
36
+ # They must not *define* copy themselves
37
+ self.assertNotIn("copy", cls.__dict__)
38
+
39
+ # Optional: if they *do* expose copy on the instance, it should not
40
+ # create a mutable variant; you can drop this if you prefer.
41
+ obj = cls(*args)
42
+ if hasattr(obj, "copy"):
43
+ copy_obj = obj.copy()
44
+ self.assertIsInstance(copy_obj, cls)
45
+
46
+ def test_mutable_copy_returns_same_type_and_is_shallow(self: Self) -> None:
47
+ d: HoldDict
48
+ d_copy: HoldDict
49
+ d = HoldDict({"a": {"x": 1}})
50
+ d_copy = d.copy()
51
+ self.assertIsInstance(d_copy, type(d))
52
+ self.assertIsNot(d_copy, d)
53
+ self.assertEqual(dict(d_copy), dict(d))
54
+
55
+ # shallow: inner object is shared
56
+ d["a"]["x"] = 2
57
+ self.assertEqual(d_copy["a"]["x"], 2)
58
+
59
+ def test_list_copy(self: Self) -> None:
60
+ lst: HoldList
61
+ lst_copy: HoldList
62
+ lst = HoldList([[1], [2]])
63
+ lst_copy = lst.copy()
64
+ self.assertIsInstance(lst_copy, type(lst))
65
+ self.assertIsNot(lst_copy, lst)
66
+ self.assertEqual(list(lst_copy), list(lst))
67
+
68
+ lst[0].append(99)
69
+ self.assertEqual(lst_copy[0], [1, 99])
70
+
71
+ def test_set_copy(self: Self) -> None:
72
+ s: HoldSet
73
+ s_copy: HoldSet
74
+ s = HoldSet({1, 2, 3})
75
+ s_copy = s.copy()
76
+ self.assertIsInstance(s_copy, type(s))
77
+ self.assertIsNot(s_copy, s)
78
+ self.assertEqual(set(s_copy), set(s))
79
+
80
+ s.add(4)
81
+ self.assertNotIn(4, s_copy)
82
+
83
+
84
+ if __name__ == "__main__":
85
+ unittest.main()
@@ -0,0 +1,55 @@
1
+ import unittest
2
+ from typing import Any, Self
3
+
4
+ from frozendict import frozendict
5
+
6
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
7
+ from datahold.core.FrozenHoldList import FrozenHoldList
8
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
9
+ from datahold.core.HoldDict import HoldDict
10
+ from datahold.core.HoldList import HoldList
11
+ from datahold.core.HoldSet import HoldSet
12
+
13
+
14
+ class TestDataAttribute(unittest.TestCase):
15
+ def test_dict_data_is_immutable_mapping(self: Self) -> None:
16
+ f: FrozenHoldDict
17
+ m: HoldDict
18
+ obj: Any
19
+ f = FrozenHoldDict({"a": 1})
20
+ m = HoldDict({"a": 1})
21
+
22
+ for obj in (f, m):
23
+ self.assertIsInstance(obj.data, frozendict)
24
+
25
+ # try to mutate underlying data
26
+ with self.assertRaises((TypeError, AttributeError)):
27
+ obj.data["b"] = 2
28
+
29
+ def test_list_data_is_tuple(self: Self) -> None:
30
+ f: FrozenHoldList
31
+ m: HoldList
32
+ o: Any
33
+ f = FrozenHoldList([1, 2, 3])
34
+ m = HoldList([1, 2, 3])
35
+
36
+ for o in (f, m):
37
+ self.assertIsInstance(o.data, tuple)
38
+ with self.assertRaises(Exception):
39
+ o.data.append(4)
40
+
41
+ def test_set_data_is_frozenset(self: Self) -> None:
42
+ f: FrozenHoldSet
43
+ m: HoldSet
44
+ obj: Any
45
+ f = FrozenHoldSet({1, 2, 3})
46
+ m = HoldSet({1, 2, 3})
47
+
48
+ for obj in (f, m):
49
+ self.assertIsInstance(obj.data, frozenset)
50
+ with self.assertRaises(AttributeError):
51
+ obj.data.add(4)
52
+
53
+
54
+ if __name__ == "__main__":
55
+ unittest.main()
@@ -0,0 +1,38 @@
1
+ import unittest
2
+ from typing import Any, Self
3
+
4
+ from frozendict import frozendict
5
+
6
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
7
+ from datahold.core.FrozenHoldList import FrozenHoldList
8
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
9
+
10
+
11
+ class TestFrozenMutability(unittest.TestCase):
12
+ def test_frozen_dict_cannot_mutate(self: Self) -> None:
13
+ f: FrozenHoldDict
14
+ f = FrozenHoldDict({"a": 1})
15
+ with self.assertRaises((TypeError, AttributeError)):
16
+ f["b"] = 2
17
+ with self.assertRaises((TypeError, AttributeError)):
18
+ f.pop("a", None)
19
+
20
+ def test_frozen_list_cannot_mutate(self: Self) -> None:
21
+ f: FrozenHoldList
22
+ f = FrozenHoldList([1, 2, 3])
23
+ with self.assertRaises((TypeError, AttributeError)):
24
+ f.append(4)
25
+ with self.assertRaises((TypeError, AttributeError)):
26
+ f.pop()
27
+
28
+ def test_frozen_set_cannot_mutate(self: Self) -> None:
29
+ f: FrozenHoldSet
30
+ f = FrozenHoldSet({1, 2, 3})
31
+ with self.assertRaises((TypeError, AttributeError)):
32
+ f.add(4)
33
+ with self.assertRaises((TypeError, AttributeError)):
34
+ f.remove(1)
35
+
36
+
37
+ if __name__ == "__main__":
38
+ unittest.main()
@@ -0,0 +1,62 @@
1
+ import unittest
2
+ from typing import Self
3
+
4
+ from frozendict import frozendict
5
+
6
+ from datahold.core.BaseDataDict import BaseDataDict
7
+ from datahold.core.BaseDataList import BaseDataList
8
+ from datahold.core.BaseDataSet import BaseDataSet
9
+ from datahold.core.BaseHoldDict import BaseHoldDict
10
+ from datahold.core.BaseHoldList import BaseHoldList
11
+ from datahold.core.BaseHoldSet import BaseHoldSet
12
+ from datahold.core.DataDict import DataDict
13
+ from datahold.core.DataList import DataList
14
+ from datahold.core.DataObject import DataObject
15
+ from datahold.core.DataSet import DataSet
16
+ from datahold.core.FrozenDataDict import FrozenDataDict
17
+ from datahold.core.FrozenDataList import FrozenDataList
18
+ from datahold.core.FrozenDataObject import FrozenDataObject
19
+ from datahold.core.FrozenDataSet import FrozenDataSet
20
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
21
+ from datahold.core.FrozenHoldList import FrozenHoldList
22
+ from datahold.core.FrozenHoldObject import FrozenHoldObject
23
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
24
+ from datahold.core.HoldDict import HoldDict
25
+ from datahold.core.HoldList import HoldList
26
+ from datahold.core.HoldObject import HoldObject
27
+ from datahold.core.HoldSet import HoldSet
28
+
29
+
30
+ class TestInheritance(unittest.TestCase):
31
+ def test_dict_inheritance(self: Self) -> None:
32
+ # base → concrete
33
+ self.assertTrue(issubclass(DataDict, DataObject))
34
+ self.assertTrue(issubclass(FrozenDataDict, FrozenDataObject))
35
+ self.assertTrue(issubclass(HoldDict, HoldObject))
36
+ self.assertTrue(issubclass(FrozenHoldDict, FrozenHoldObject))
37
+
38
+ # non-frozen data inherit from frozen
39
+ self.assertTrue(issubclass(DataDict, BaseDataDict))
40
+ self.assertTrue(issubclass(HoldDict, BaseHoldDict))
41
+
42
+ def test_list_inheritance(self: Self) -> None:
43
+ self.assertTrue(issubclass(DataList, DataObject))
44
+ self.assertTrue(issubclass(FrozenDataList, FrozenDataObject))
45
+ self.assertTrue(issubclass(HoldList, HoldObject))
46
+ self.assertTrue(issubclass(FrozenHoldList, FrozenHoldObject))
47
+
48
+ self.assertTrue(issubclass(DataList, BaseDataList))
49
+ self.assertTrue(issubclass(HoldList, BaseHoldList))
50
+
51
+ def test_set_inheritance(self: Self) -> None:
52
+ self.assertTrue(issubclass(DataSet, DataObject))
53
+ self.assertTrue(issubclass(FrozenDataSet, FrozenDataObject))
54
+ self.assertTrue(issubclass(HoldSet, HoldObject))
55
+ self.assertTrue(issubclass(FrozenHoldSet, FrozenHoldObject))
56
+
57
+ self.assertTrue(issubclass(DataSet, BaseDataSet))
58
+ self.assertTrue(issubclass(HoldSet, BaseHoldSet))
59
+
60
+
61
+ if __name__ == "__main__":
62
+ unittest.main()
@@ -0,0 +1,38 @@
1
+ import unittest
2
+ from typing import Any, Self
3
+
4
+ from frozendict import frozendict
5
+
6
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
7
+ from datahold.core.FrozenHoldList import FrozenHoldList
8
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
9
+ from datahold.core.HoldDict import HoldDict
10
+ from datahold.core.HoldList import HoldList
11
+ from datahold.core.HoldSet import HoldSet
12
+
13
+
14
+ class TestMutableBehavior(unittest.TestCase):
15
+ def test_hold_dict_mutates_and_syncs_data(self: Self) -> None:
16
+ x: HoldDict
17
+ x = HoldDict({"a": 1})
18
+ x["b"] = 2
19
+ self.assertEqual(x["b"], 2)
20
+ self.assertEqual(x.data["b"], 2)
21
+
22
+ def test_hold_list_mutates_and_syncs_data(self: Self) -> None:
23
+ x: HoldList
24
+ x = HoldList([1, 2])
25
+ x.append(3)
26
+ self.assertEqual(list(x), [1, 2, 3])
27
+ self.assertEqual(x.data, (1, 2, 3))
28
+
29
+ def test_hold_set_mutates_and_syncs_data(self: Self) -> None:
30
+ s: HoldSet
31
+ s = HoldSet({1, 2})
32
+ s.add(3)
33
+ self.assertTrue(3 in s)
34
+ self.assertTrue(3 in s.data)
35
+
36
+
37
+ if __name__ == "__main__":
38
+ unittest.main()
@@ -0,0 +1,66 @@
1
+ import unittest
2
+ from collections.abc import (
3
+ Mapping,
4
+ MutableMapping,
5
+ MutableSequence,
6
+ MutableSet,
7
+ Sequence,
8
+ )
9
+ from collections.abc import Set as AbstractSet
10
+ from typing import Self
11
+
12
+ from frozendict import frozendict
13
+
14
+ from datahold.core.FrozenHoldDict import FrozenHoldDict
15
+ from datahold.core.FrozenHoldList import FrozenHoldList
16
+ from datahold.core.FrozenHoldSet import FrozenHoldSet
17
+ from datahold.core.HoldDict import HoldDict
18
+ from datahold.core.HoldList import HoldList
19
+ from datahold.core.HoldSet import HoldSet
20
+
21
+ __all__ = ["TestProtocols"]
22
+
23
+
24
+ class TestProtocols(unittest.TestCase):
25
+ def test_mapping_protocols_x(self: Self) -> None:
26
+ x: FrozenHoldDict
27
+ x = FrozenHoldDict({"a": 1})
28
+
29
+ self.assertIsInstance(x, Mapping)
30
+ self.assertNotIsInstance(x, MutableMapping)
31
+
32
+ def test_mapping_protocols_y(self: Self) -> None:
33
+ y: HoldDict
34
+ y = HoldDict({"a": 1})
35
+
36
+ self.assertIsInstance(y, Mapping)
37
+ self.assertIsInstance(y, MutableMapping)
38
+
39
+ def test_sequence_protocols_x(self: Self) -> None:
40
+ f: FrozenHoldList
41
+ f = FrozenHoldList([1, 2, 3])
42
+
43
+ self.assertIsInstance(f, Sequence)
44
+ self.assertNotIsInstance(f, MutableSequence)
45
+
46
+ def test_sequence_protocols_y(self: Self) -> None:
47
+ m: HoldList
48
+ m = HoldList([1, 2, 3])
49
+ self.assertIsInstance(m, Sequence)
50
+ self.assertIsInstance(m, MutableSequence)
51
+
52
+ def test_set_protocols(self: Self) -> None:
53
+ f: FrozenHoldSet
54
+ m: HoldSet
55
+ f = FrozenHoldSet({1, 2, 3})
56
+ m = HoldSet({1, 2, 3})
57
+
58
+ self.assertIsInstance(f, AbstractSet)
59
+ self.assertNotIsInstance(f, MutableSet)
60
+
61
+ self.assertIsInstance(m, AbstractSet)
62
+ self.assertIsInstance(m, MutableSet)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ unittest.main()
@@ -4,6 +4,8 @@ from typing import *
4
4
 
5
5
  import datahold
6
6
 
7
+ __all__ = ["TestDataholdGenerics"]
8
+
7
9
 
8
10
  class TestDataholdGenerics(unittest.TestCase):
9
11
  def _assert_is_generic(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 3.0.0.dev2
3
+ Version: 3.0.0.dev3
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: The MIT License (MIT)
@@ -38,5 +38,11 @@ src/datahold/core/HoldSet.py
38
38
  src/datahold/core/__init__.py
39
39
  src/datahold/tests/__init__.py
40
40
  src/datahold/tests/test_0.py
41
- src/datahold/tests/test_datahold.py
41
+ src/datahold/tests/test_datahold_TestAbstractness.py
42
+ src/datahold/tests/test_datahold_TestCopy.py
43
+ src/datahold/tests/test_datahold_TestDataAttribute.py
44
+ src/datahold/tests/test_datahold_TestFrozenMutability.py
45
+ src/datahold/tests/test_datahold_TestInheritance.py
46
+ src/datahold/tests/test_datahold_TestMutableBehavior.py
47
+ src/datahold/tests/test_datahold_TestProtocols.py
42
48
  src/datahold/tests/test_generic.py
@@ -1,298 +0,0 @@
1
- import unittest
2
- from collections.abc import (
3
- Mapping,
4
- MutableMapping,
5
- MutableSequence,
6
- MutableSet,
7
- Sequence,
8
- )
9
- from collections.abc import Set as AbstractSet
10
- from inspect import isabstract
11
- from typing import Any, Self
12
-
13
- from frozendict import frozendict
14
-
15
- from datahold.core.BaseDataDict import BaseDataDict
16
- from datahold.core.BaseDataList import BaseDataList
17
- from datahold.core.BaseDataObject import BaseDataObject
18
- from datahold.core.BaseDataSet import BaseDataSet
19
- from datahold.core.BaseHoldDict import BaseHoldDict
20
- from datahold.core.BaseHoldList import BaseHoldList
21
- from datahold.core.BaseHoldObject import BaseHoldObject
22
- from datahold.core.BaseHoldSet import BaseHoldSet
23
- from datahold.core.DataDict import DataDict
24
- from datahold.core.DataList import DataList
25
- from datahold.core.DataObject import DataObject
26
- from datahold.core.DataSet import DataSet
27
- from datahold.core.FrozenDataDict import FrozenDataDict
28
- from datahold.core.FrozenDataList import FrozenDataList
29
- from datahold.core.FrozenDataObject import FrozenDataObject
30
- from datahold.core.FrozenDataSet import FrozenDataSet
31
- from datahold.core.FrozenHoldDict import FrozenHoldDict
32
- from datahold.core.FrozenHoldList import FrozenHoldList
33
- from datahold.core.FrozenHoldObject import FrozenHoldObject
34
- from datahold.core.FrozenHoldSet import FrozenHoldSet
35
- from datahold.core.HoldDict import HoldDict
36
- from datahold.core.HoldList import HoldList
37
- from datahold.core.HoldObject import HoldObject
38
- from datahold.core.HoldSet import HoldSet
39
-
40
-
41
- class TestAbstractness(unittest.TestCase):
42
- def test_abstract_classes(self: Self) -> None:
43
- # data
44
- self.assertTrue(isabstract(DataObject))
45
- self.assertTrue(isabstract(DataDict))
46
- self.assertTrue(isabstract(DataList))
47
- self.assertTrue(isabstract(DataSet))
48
-
49
- self.assertTrue(isabstract(FrozenDataObject))
50
- self.assertTrue(isabstract(FrozenDataDict))
51
- self.assertTrue(isabstract(FrozenDataList))
52
- self.assertTrue(isabstract(FrozenDataSet))
53
-
54
- # hold
55
- self.assertFalse(isabstract(FrozenHoldObject))
56
- # self.assertFalse(isabstract(HoldObject))
57
-
58
- def test_concrete_classes(self: Self) -> None:
59
- FrozenHoldDict({"a": 1})
60
- FrozenHoldList([1, 2])
61
- FrozenHoldSet({1, 2})
62
-
63
- HoldDict({"a": 1})
64
- HoldList([1, 2])
65
- HoldSet({1, 2})
66
-
67
-
68
- class TestInheritance(unittest.TestCase):
69
- def test_dict_inheritance(self: Self) -> None:
70
- # base → concrete
71
- self.assertTrue(issubclass(DataDict, DataObject))
72
- self.assertTrue(issubclass(FrozenDataDict, FrozenDataObject))
73
- self.assertTrue(issubclass(HoldDict, HoldObject))
74
- self.assertTrue(issubclass(FrozenHoldDict, FrozenHoldObject))
75
-
76
- # non-frozen data inherit from frozen
77
- self.assertTrue(issubclass(DataDict, BaseDataDict))
78
- self.assertTrue(issubclass(HoldDict, BaseHoldDict))
79
-
80
- def test_list_inheritance(self: Self) -> None:
81
- self.assertTrue(issubclass(DataList, DataObject))
82
- self.assertTrue(issubclass(FrozenDataList, FrozenDataObject))
83
- self.assertTrue(issubclass(HoldList, HoldObject))
84
- self.assertTrue(issubclass(FrozenHoldList, FrozenHoldObject))
85
-
86
- self.assertTrue(issubclass(DataList, BaseDataList))
87
- self.assertTrue(issubclass(HoldList, BaseHoldList))
88
-
89
- def test_set_inheritance(self: Self) -> None:
90
- self.assertTrue(issubclass(DataSet, DataObject))
91
- self.assertTrue(issubclass(FrozenDataSet, FrozenDataObject))
92
- self.assertTrue(issubclass(HoldSet, HoldObject))
93
- self.assertTrue(issubclass(FrozenHoldSet, FrozenHoldObject))
94
-
95
- self.assertTrue(issubclass(DataSet, BaseDataSet))
96
- self.assertTrue(issubclass(HoldSet, BaseHoldSet))
97
-
98
-
99
- class TestProtocols(unittest.TestCase):
100
- def test_mapping_protocols_x(self: Self) -> None:
101
- x: FrozenHoldDict
102
- x = FrozenHoldDict({"a": 1})
103
-
104
- self.assertIsInstance(x, Mapping)
105
- self.assertNotIsInstance(x, MutableMapping)
106
-
107
- def test_mapping_protocols_y(self: Self) -> None:
108
- y: HoldDict
109
- y = HoldDict({"a": 1})
110
-
111
- self.assertIsInstance(y, Mapping)
112
- self.assertIsInstance(y, MutableMapping)
113
-
114
- def test_sequence_protocols_x(self: Self) -> None:
115
- f: FrozenHoldList
116
- f = FrozenHoldList([1, 2, 3])
117
-
118
- self.assertIsInstance(f, Sequence)
119
- self.assertNotIsInstance(f, MutableSequence)
120
-
121
- def test_sequence_protocols_y(self: Self) -> None:
122
- m: HoldList
123
- m = HoldList([1, 2, 3])
124
- self.assertIsInstance(m, Sequence)
125
- self.assertIsInstance(m, MutableSequence)
126
-
127
- def test_set_protocols(self: Self) -> None:
128
- f: FrozenHoldSet
129
- m: HoldSet
130
- f = FrozenHoldSet({1, 2, 3})
131
- m = HoldSet({1, 2, 3})
132
-
133
- self.assertIsInstance(f, AbstractSet)
134
- self.assertNotIsInstance(f, MutableSet)
135
-
136
- self.assertIsInstance(m, AbstractSet)
137
- self.assertIsInstance(m, MutableSet)
138
-
139
-
140
- class TestDataAttribute(unittest.TestCase):
141
- def test_dict_data_is_immutable_mapping(self: Self) -> None:
142
- f: FrozenHoldDict
143
- m: HoldDict
144
- obj: Any
145
- f = FrozenHoldDict({"a": 1})
146
- m = HoldDict({"a": 1})
147
-
148
- for obj in (f, m):
149
- self.assertIsInstance(obj.data, frozendict)
150
-
151
- # try to mutate underlying data
152
- with self.assertRaises((TypeError, AttributeError)):
153
- obj.data["b"] = 2
154
-
155
- def test_list_data_is_tuple(self: Self) -> None:
156
- f: FrozenHoldList
157
- m: HoldList
158
- o: Any
159
- f = FrozenHoldList([1, 2, 3])
160
- m = HoldList([1, 2, 3])
161
-
162
- for o in (f, m):
163
- self.assertIsInstance(o.data, tuple)
164
- with self.assertRaises(Exception):
165
- o.data.append(4)
166
-
167
- def test_set_data_is_frozenset(self: Self) -> None:
168
- f: FrozenHoldSet
169
- m: HoldSet
170
- obj: Any
171
- f = FrozenHoldSet({1, 2, 3})
172
- m = HoldSet({1, 2, 3})
173
-
174
- for obj in (f, m):
175
- self.assertIsInstance(obj.data, frozenset)
176
- with self.assertRaises(AttributeError):
177
- obj.data.add(4)
178
-
179
-
180
- class TestFrozenMutability(unittest.TestCase):
181
- def test_frozen_dict_cannot_mutate(self: Self) -> None:
182
- f: FrozenHoldDict
183
- f = FrozenHoldDict({"a": 1})
184
- with self.assertRaises((TypeError, AttributeError)):
185
- f["b"] = 2
186
- with self.assertRaises((TypeError, AttributeError)):
187
- f.pop("a", None)
188
-
189
- def test_frozen_list_cannot_mutate(self: Self) -> None:
190
- f: FrozenHoldList
191
- f = FrozenHoldList([1, 2, 3])
192
- with self.assertRaises((TypeError, AttributeError)):
193
- f.append(4)
194
- with self.assertRaises((TypeError, AttributeError)):
195
- f.pop()
196
-
197
- def test_frozen_set_cannot_mutate(self: Self) -> None:
198
- f: FrozenHoldSet
199
- f = FrozenHoldSet({1, 2, 3})
200
- with self.assertRaises((TypeError, AttributeError)):
201
- f.add(4)
202
- with self.assertRaises((TypeError, AttributeError)):
203
- f.remove(1)
204
-
205
-
206
- class TestMutableBehavior(unittest.TestCase):
207
- def test_hold_dict_mutates_and_syncs_data(self: Self) -> None:
208
- x: HoldDict
209
- x = HoldDict({"a": 1})
210
- x["b"] = 2
211
- self.assertEqual(x["b"], 2)
212
- self.assertEqual(x.data["b"], 2)
213
-
214
- def test_hold_list_mutates_and_syncs_data(self: Self) -> None:
215
- x: HoldList
216
- x = HoldList([1, 2])
217
- x.append(3)
218
- self.assertEqual(list(x), [1, 2, 3])
219
- self.assertEqual(x.data, (1, 2, 3))
220
-
221
- def test_hold_set_mutates_and_syncs_data(self: Self) -> None:
222
- s: HoldSet
223
- s = HoldSet({1, 2})
224
- s.add(3)
225
- self.assertTrue(3 in s)
226
- self.assertTrue(3 in s.data)
227
-
228
-
229
- class TestCopy(unittest.TestCase):
230
- def test_frozen_have_no_copy(self: Self) -> None:
231
- self.assertFalse(hasattr(FrozenHoldDict({"a": 1}), "copy"))
232
- self.assertFalse(hasattr(FrozenHoldList([1, 2]), "copy"))
233
- self.assertFalse(hasattr(FrozenHoldSet({1, 2}), "copy"))
234
-
235
- def test_frozen_have_no_copy_2(self: Self) -> None:
236
- """
237
- Frozen classes should not define their own copy method.
238
- (If a parent class or wrapped object exposes one, we ignore that.)
239
- """
240
- cls: Any
241
- args: Any
242
- obj: Any
243
- copy_obj: Any
244
- for cls, args in (
245
- (FrozenHoldDict, ({"a": 1},)),
246
- (FrozenHoldList, ([1, 2],)),
247
- (FrozenHoldSet, ({1, 2},)),
248
- ):
249
- # They must not *define* copy themselves
250
- self.assertNotIn("copy", cls.__dict__)
251
-
252
- # Optional: if they *do* expose copy on the instance, it should not
253
- # create a mutable variant; you can drop this if you prefer.
254
- obj = cls(*args)
255
- if hasattr(obj, "copy"):
256
- copy_obj = obj.copy()
257
- self.assertIsInstance(copy_obj, cls)
258
-
259
- def test_mutable_copy_returns_same_type_and_is_shallow(self: Self) -> None:
260
- d: HoldDict
261
- d_copy: HoldDict
262
- d = HoldDict({"a": {"x": 1}})
263
- d_copy = d.copy()
264
- self.assertIsInstance(d_copy, type(d))
265
- self.assertIsNot(d_copy, d)
266
- self.assertEqual(dict(d_copy), dict(d))
267
-
268
- # shallow: inner object is shared
269
- d["a"]["x"] = 2
270
- self.assertEqual(d_copy["a"]["x"], 2)
271
-
272
- def test_list_copy(self: Self) -> None:
273
- lst: HoldList
274
- lst_copy: HoldList
275
- lst = HoldList([[1], [2]])
276
- lst_copy = lst.copy()
277
- self.assertIsInstance(lst_copy, type(lst))
278
- self.assertIsNot(lst_copy, lst)
279
- self.assertEqual(list(lst_copy), list(lst))
280
-
281
- lst[0].append(99)
282
- self.assertEqual(lst_copy[0], [1, 99])
283
-
284
- def test_set_copy(self: Self) -> None:
285
- s: HoldSet
286
- s_copy: HoldSet
287
- s = HoldSet({1, 2, 3})
288
- s_copy = s.copy()
289
- self.assertIsInstance(s_copy, type(s))
290
- self.assertIsNot(s_copy, s)
291
- self.assertEqual(set(s_copy), set(s))
292
-
293
- s.add(4)
294
- self.assertNotIn(4, s_copy)
295
-
296
-
297
- if __name__ == "__main__":
298
- unittest.main()
File without changes
File without changes
File without changes
File without changes