datahold 4.0.0.dev10__tar.gz → 4.0.0.dev21__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 (37) hide show
  1. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/PKG-INFO +1 -1
  2. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/pyproject.toml +1 -1
  3. datahold-4.0.0.dev21/src/datahold/__init__.py +649 -0
  4. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold.egg-info/PKG-INFO +1 -1
  5. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold.egg-info/SOURCES.txt +1 -0
  6. datahold-4.0.0.dev21/tests/test_prefix.py +41 -0
  7. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/testdata.toml +83 -15
  8. datahold-4.0.0.dev10/src/datahold/__init__.py +0 -258
  9. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/LICENSE.txt +0 -0
  10. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/MANIFEST.in +0 -0
  11. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/README.rst +0 -0
  12. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v1.1.rst +0 -0
  13. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v1.2.rst +0 -0
  14. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v2.0.rst +0 -0
  15. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v2.1.rst +0 -0
  16. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v2.2.rst +0 -0
  17. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v2.3.rst +0 -0
  18. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v3.0.rst +0 -0
  19. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/docs/v4.0.rst +0 -0
  20. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/run_tests.py +0 -0
  21. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/setup.cfg +0 -0
  22. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold/py.typed +0 -0
  23. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold.egg-info/dependency_links.txt +0 -0
  24. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold.egg-info/requires.txt +0 -0
  25. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/src/datahold.egg-info/top_level.txt +0 -0
  26. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_FrozenListSlot.py +0 -0
  27. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_MutableListHold.py +0 -0
  28. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_abstractmethods.py +0 -0
  29. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_all.py +0 -0
  30. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_attributes.py +0 -0
  31. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_docs.py +0 -0
  32. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_generic.py +0 -0
  33. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_internal_comparison.py +0 -0
  34. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_issubclass.py +0 -0
  35. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_nested.py +0 -0
  36. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_sorted.py +0 -0
  37. {datahold-4.0.0.dev10 → datahold-4.0.0.dev21}/tests/test_variance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 4.0.0.dev10
3
+ Version: 4.0.0.dev21
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
@@ -30,7 +30,7 @@ license-files = [
30
30
  name = "datahold"
31
31
  readme = "README.rst"
32
32
  requires-python = ">=3.11"
33
- version = "4.0.0.dev10"
33
+ version = "4.0.0.dev21"
34
34
 
35
35
  [project.urls]
36
36
  Download = "https://pypi.org/project/datahold/#files"
@@ -0,0 +1,649 @@
1
+ """Provide provides base classes for customized collections."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __all__: list[str] = [
6
+ "Collection",
7
+ "FrozenListLike",
8
+ "FrozenListSlot",
9
+ "FrozenSetLike",
10
+ "FrozenSetSlot",
11
+ "ListLike",
12
+ "ListSlot",
13
+ "MutableListLike",
14
+ "MutableListSlot",
15
+ "MutableSequence",
16
+ "MutableSet",
17
+ "MutableSetLike",
18
+ "MutableSetSlot",
19
+ "Sequence",
20
+ "Set",
21
+ "SetLike",
22
+ "SetSlot",
23
+ ]
24
+
25
+ from abc import abstractmethod
26
+ from collections import abc
27
+ from contextlib import contextmanager
28
+ from types import NotImplementedType, TracebackType
29
+ from typing import (
30
+ Any,
31
+ Never,
32
+ Optional,
33
+ Protocol,
34
+ Self,
35
+ SupportsIndex,
36
+ overload,
37
+ )
38
+
39
+ import setdoc
40
+
41
+ ### UTILS ###
42
+
43
+
44
+ class ContextManager[Enter](Protocol):
45
+ """Provide context manager protocol."""
46
+
47
+ @setdoc.basic
48
+ def __enter__(self: Self, /) -> Enter: ...
49
+
50
+ @setdoc.basic
51
+ def __exit__(
52
+ self: Self,
53
+ exc_type: type[BaseException] | None,
54
+ exc_value: BaseException | None,
55
+ traceback: TracebackType | None,
56
+ /,
57
+ ) -> object: ...
58
+
59
+
60
+ type Slice[Index] = slice[Optional[Index], Optional[Index], Optional[Index]]
61
+
62
+
63
+ ### COLLECTION ###
64
+
65
+
66
+ class Collection[Item](
67
+ abc.Sized,
68
+ abc.Iterable[Item],
69
+ abc.Container[object],
70
+ ):
71
+ """Provide abc for custom collections."""
72
+
73
+ @setdoc.basic
74
+ class __Frozen__[FrozenItem](
75
+ abc.Sized,
76
+ abc.Iterable[FrozenItem],
77
+ Protocol,
78
+ ):
79
+ @setdoc.basic
80
+ def __contains__(self: Self, other: Never, /) -> bool: ...
81
+
82
+ @setdoc.basic
83
+ def __contains__(self: Self, other: object, /) -> bool:
84
+ try:
85
+ return other in self.__frozen__() # type: ignore[operator]
86
+ except TypeError:
87
+ return other in (x for x in self) # type: ignore[operator]
88
+
89
+ @abstractmethod
90
+ @setdoc.basic
91
+ def __frozen__(self: Self, /) -> __Frozen__[Item]: ...
92
+
93
+ @setdoc.basic
94
+ def __iter__(self: Self) -> abc.Iterator[Item]:
95
+ return iter(self.__frozen__())
96
+
97
+ @setdoc.basic
98
+ def __len__(self: Self, /) -> int:
99
+ return len(self.__frozen__())
100
+
101
+
102
+ ### SET ###
103
+
104
+
105
+ class Set[Item: abc.Hashable](Collection[Item], abc.Set[Item]):
106
+ """Provide abc for custom set."""
107
+
108
+ __slots__ = ()
109
+
110
+
111
+ class MutableSet[Item: abc.Hashable](Set[Item], abc.MutableSet[Item]):
112
+ """Provide abc for custom mutable set."""
113
+
114
+ __slots__ = ()
115
+
116
+ @setdoc.basic
117
+ class __Mutable__[MutableItem: abc.Hashable](Protocol):
118
+ @setdoc.basic
119
+ def add(self: Self, item: MutableItem, /) -> object: ...
120
+ @setdoc.basic
121
+ def discard(self: Self, item: abc.Hashable, /) -> object: ...
122
+ @abstractmethod
123
+ @setdoc.basic
124
+ def __mutate__(self: Self) -> ContextManager[__Mutable__[Item]]: ...
125
+ @setdoc.basic
126
+ def add(self: Self, item: Item, /) -> None:
127
+ with self.__mutate__() as mutable:
128
+ mutable.add(item)
129
+
130
+ @setdoc.basic
131
+ def discard(self: Self, item: abc.Hashable, /) -> None:
132
+ with self.__mutate__() as mutable:
133
+ mutable.discard(item)
134
+
135
+
136
+ ### SET-LIKE ###
137
+
138
+
139
+ class SetLike[Item: abc.Hashable](Set[Item]):
140
+ """Provide abc for custom set-like."""
141
+
142
+ __slots__ = ()
143
+ type __Frozen__[FrozenItem] = frozenset[FrozenItem]
144
+ type Init[FrozenItem] = abc.Iterable[FrozenItem]
145
+
146
+ @abstractmethod
147
+ @setdoc.basic
148
+ def __frozen__(self: Self, /) -> __Frozen__[Item]: ...
149
+ @abstractmethod
150
+ @setdoc.basic
151
+ def __init__(self: Self, data: Init[Item] = (), /) -> None: ...
152
+ @setdoc.basic
153
+ def difference(self: Self, /, *others: abc.Iterable[abc.Hashable]) -> Self:
154
+ return type(self)(self.__frozen__().difference(*others))
155
+
156
+ @setdoc.basic
157
+ def intersection(
158
+ self: Self, /, *others: abc.Iterable[abc.Hashable]
159
+ ) -> Self:
160
+ return type(self)(self.__frozen__().intersection(*others))
161
+
162
+ @setdoc.basic
163
+ def issubset(self: Self, other: abc.Iterable[abc.Hashable], /) -> Self:
164
+ return type(self)(self.__frozen__().issubset(other)) # type: ignore
165
+
166
+ @setdoc.basic
167
+ def issuperset(self: Self, other: abc.Iterable[abc.Hashable], /) -> Self:
168
+ return type(self)(self.__frozen__().issuperset(other)) # type: ignore
169
+
170
+ @setdoc.basic
171
+ def symmetric_difference(self: Self, other: abc.Iterable[Item], /) -> Self:
172
+ return type(self)(self.__frozen__().symmetric_difference(other))
173
+
174
+ @setdoc.basic
175
+ def union(self: Self, /, *others: abc.Iterable[Item]) -> Self:
176
+ return type(self)(self.__frozen__().union(others)) # type: ignore
177
+
178
+
179
+ class FrozenSetLike[Item: abc.Hashable](SetLike[Item], abc.Hashable):
180
+ """Provide abc for custom frozen set-like."""
181
+
182
+ __slots__ = ()
183
+
184
+ @setdoc.basic
185
+ def __hash__(self: Self) -> int:
186
+ return hash(self.__frozen__())
187
+
188
+
189
+ class MutableSetLike[Item: abc.Hashable](SetLike[Item], MutableSet[Item]):
190
+ """Provide abc for custom mutable set-like."""
191
+
192
+ __slots__ = ()
193
+
194
+ type __Mutable__[MutableItem] = set[MutableItem]
195
+
196
+ @setdoc.basic
197
+ def __frozen__(self: Self, /) -> MutableSetLike.__Frozen__[Item]:
198
+ with self.__mutate__() as mutable:
199
+ return frozenset(mutable)
200
+
201
+ @abstractmethod
202
+ @setdoc.basic
203
+ def __init__(self: Self, data: MutableSetLike.Init[Item] = (), /) -> None:
204
+ with self.__mutate__() as mutable:
205
+ mutable.update(data)
206
+
207
+ @abstractmethod
208
+ @setdoc.basic
209
+ def __mutate__(self: Self) -> ContextManager[__Mutable__[Item]]: ...
210
+ @setdoc.basic
211
+ def difference_update(
212
+ self: Self, /, *others: abc.Iterable[abc.Hashable]
213
+ ) -> None:
214
+ with self.__mutate__() as mutable:
215
+ mutable.difference_update(*others)
216
+
217
+ @setdoc.basic
218
+ def intersection_update(
219
+ self: Self, /, *others: abc.Iterable[abc.Hashable]
220
+ ) -> None:
221
+ with self.__mutate__() as mutable:
222
+ mutable.intersection_update(*others)
223
+
224
+ @setdoc.basic
225
+ def symmetric_difference_update(
226
+ self: Self, other: abc.Iterable[Item], /
227
+ ) -> None:
228
+ with self.__mutate__() as mutable:
229
+ mutable.symmetric_difference_update(other)
230
+
231
+ @setdoc.basic
232
+ def update(self: Self, /, *others: abc.Iterable[Item]) -> None:
233
+ with self.__mutate__() as mutable:
234
+ mutable.update(*others)
235
+
236
+
237
+ ### SET-SLOT ###
238
+
239
+
240
+ class SetSlot[Item: abc.Hashable](SetLike[Item]):
241
+ """Provide slotted set-like."""
242
+
243
+ __slots__ = ("_slot",)
244
+
245
+ _slot: SetSlot.__Frozen__[Item]
246
+
247
+ @setdoc.basic
248
+ def __frozen__(self: Self) -> SetSlot.__Frozen__[Item]:
249
+ return self._slot
250
+
251
+
252
+ class FrozenSetSlot[Item](SetSlot[Item], FrozenSetLike[Item]):
253
+ """Provide slotted frozen set-like."""
254
+
255
+ __slots__ = ()
256
+
257
+ @setdoc.basic
258
+ def __init__(self: Self, data: FrozenSetSlot.Init[Item] = (), /) -> None:
259
+ self._slot = frozenset(data)
260
+
261
+
262
+ class MutableSetSlot[Item](SetSlot[Item], MutableSetLike[Item]):
263
+ """Provide slotted mutable set-like."""
264
+
265
+ __slots__ = ()
266
+
267
+ @contextmanager
268
+ @setdoc.basic
269
+ def __mutate__(self: Self, /) -> abc.Generator[set[Item], None, None]:
270
+ slot = set(getattr(self, "_slot", ()))
271
+ yield slot
272
+ self._slot = frozenset(slot)
273
+
274
+
275
+ ### SEQUENCE ###
276
+
277
+
278
+ class Sequence[Item](Collection[Item], abc.Sequence[Item]):
279
+ """Provide a base class for customized sequence."""
280
+
281
+ __slots__ = ()
282
+
283
+ @setdoc.basic
284
+ class __Frozen__[FrozenItem](
285
+ Collection.__Frozen__[FrozenItem],
286
+ Protocol,
287
+ ):
288
+ @overload
289
+ @setdoc.basic
290
+ def __getitem__(self: Self, key: int, /) -> FrozenItem: ...
291
+ @overload
292
+ @setdoc.basic
293
+ def __getitem__(
294
+ self: Self, key: Slice[int], /
295
+ ) -> abc.Sequence[FrozenItem]: ...
296
+ @setdoc.basic
297
+ def __getitem__(
298
+ self: Self,
299
+ key: int | Slice[int],
300
+ /,
301
+ ) -> FrozenItem | abc.Sequence[FrozenItem]: ...
302
+
303
+ @abstractmethod
304
+ @setdoc.basic
305
+ def __frozen__(self: Self, /) -> __Frozen__[Item]: ...
306
+
307
+ @overload
308
+ @setdoc.basic
309
+ def __getitem__(self: Self, key: int, /) -> Item: ...
310
+ @overload
311
+ @setdoc.basic
312
+ def __getitem__(self: Self, key: Slice[int], /) -> abc.Sequence[Item]: ...
313
+ @setdoc.basic
314
+ def __getitem__(
315
+ self: Self, key: int | Slice[int], /
316
+ ) -> Item | abc.Sequence[Item]:
317
+ return self.__frozen__()[key]
318
+
319
+
320
+ class MutableSequence[Item](Sequence[Item], abc.MutableSequence[Item]):
321
+ """Provide a base class for customized mutable list-likes."""
322
+
323
+ __slots__ = ()
324
+
325
+ @setdoc.basic
326
+ class __Mutable__[MutableItem](Protocol):
327
+
328
+ @overload
329
+ @setdoc.basic
330
+ def __delitem__(self: Self, key: SupportsIndex, /) -> None: ...
331
+ @overload
332
+ @setdoc.basic
333
+ def __delitem__(self: Self, key: Slice[SupportsIndex], /) -> None: ...
334
+ @setdoc.basic
335
+ def __delitem__(
336
+ self: Self, key: SupportsIndex | Slice[SupportsIndex], /
337
+ ) -> None: ...
338
+
339
+ @overload
340
+ @setdoc.basic
341
+ def __getitem__(self: Self, key: int, /) -> MutableItem: ...
342
+ @overload
343
+ @setdoc.basic
344
+ def __getitem__(
345
+ self: Self, key: Slice[int], /
346
+ ) -> abc.MutableSequence[MutableItem]: ...
347
+ @setdoc.basic
348
+ def __getitem__(
349
+ self: Self,
350
+ key: int | Slice[int],
351
+ /,
352
+ ) -> MutableItem | abc.MutableSequence[MutableItem]: ...
353
+
354
+ @overload
355
+ @setdoc.basic
356
+ def __setitem__(
357
+ self: Self, key: int, value: MutableItem, /
358
+ ) -> None: ...
359
+ @overload
360
+ @setdoc.basic
361
+ def __setitem__(
362
+ self: Self, key: Slice[int], value: abc.Iterable[MutableItem], /
363
+ ) -> None: ...
364
+ @setdoc.basic
365
+ def __setitem__(
366
+ self: Self,
367
+ key: int | Slice[int],
368
+ value: MutableItem | abc.Iterable[MutableItem],
369
+ /,
370
+ ) -> None: ...
371
+
372
+ @setdoc.basic
373
+ def insert(self: Self, index: int, item: MutableItem, /) -> None: ...
374
+
375
+ @overload
376
+ @setdoc.basic
377
+ def __delitem__(self: Self, key: int, /) -> None: ...
378
+ @overload
379
+ @setdoc.basic
380
+ def __delitem__(self: Self, key: Slice[int], /) -> None: ...
381
+ @setdoc.basic
382
+ def __delitem__(self: Self, key: int | Slice[int], /) -> None:
383
+ with self.__mutate__() as mutable:
384
+ del mutable[key]
385
+
386
+ @overload
387
+ @setdoc.basic
388
+ def __getitem__(self: Self, key: int, /) -> Item: ...
389
+ @overload
390
+ @setdoc.basic
391
+ def __getitem__(
392
+ self: Self, key: Slice[int], /
393
+ ) -> abc.MutableSequence[Item]: ...
394
+ @setdoc.basic
395
+ def __getitem__(
396
+ self: Self, key: int | Slice[int], /
397
+ ) -> Item | abc.MutableSequence[Item]:
398
+ with self.__mutate__() as mutable:
399
+ return mutable[key]
400
+
401
+ @abstractmethod
402
+ @setdoc.basic
403
+ def __mutate__(self: Self, /) -> ContextManager[__Mutable__[Item]]: ...
404
+
405
+ @overload
406
+ @setdoc.basic
407
+ def __setitem__(self: Self, key: int, value: Item, /) -> None: ...
408
+ @overload
409
+ @setdoc.basic
410
+ def __setitem__(
411
+ self: Self, key: Slice[int], value: abc.Iterable[Item], /
412
+ ) -> None: ...
413
+ @setdoc.basic
414
+ def __setitem__(
415
+ self: Self,
416
+ key: int | Slice[int],
417
+ value: Item | abc.Iterable[Item],
418
+ /,
419
+ ) -> None:
420
+ with self.__mutate__() as mutable:
421
+ mutable[key] = value # type: ignore
422
+
423
+ @setdoc.basic
424
+ def insert(self: Self, index: int, item: Item, /) -> None:
425
+ with self.__mutate__() as mutable:
426
+ mutable.insert(index, item)
427
+
428
+
429
+ ### LIST-LIKE ###
430
+ class ListLike[Item](Sequence[Item]):
431
+ """Provide a base class for customized list-likes."""
432
+
433
+ __slots__ = ()
434
+
435
+ type __Frozen__[FrozenItem] = tuple[FrozenItem, ...]
436
+ # Frozen has to be tuple to allow covariance
437
+
438
+ type Init[InitItem] = abc.Iterable[InitItem]
439
+
440
+ @setdoc.basic
441
+ def __add__[Item_](
442
+ self: Self, other: ListLike[Item_], /
443
+ ) -> ListLike[Item | Item_]:
444
+ if isinstance(other, ListLike):
445
+ return type(self)(self.__frozen__() + other.__frozen__()) # type: ignore[operator]
446
+ else:
447
+ raise TypeError
448
+
449
+ @setdoc.basic
450
+ def __eq__(self: Self, other: object, /) -> NotImplementedType | bool:
451
+ if isinstance(other, ListLike):
452
+ return self.__frozen__() == other.__frozen__()
453
+ else:
454
+ return NotImplemented
455
+
456
+ @abstractmethod
457
+ @setdoc.basic
458
+ def __frozen__(self: Self, /) -> __Frozen__[Item]: ...
459
+
460
+ @setdoc.basic
461
+ def __ge__(self: Self, other: ListLike[Any], /) -> bool:
462
+ if isinstance(other, ListLike):
463
+ return self.__frozen__() >= other.__frozen__()
464
+ else:
465
+ return NotImplemented
466
+
467
+ @overload
468
+ @setdoc.basic
469
+ def __getitem__(self: Self, key: SupportsIndex, /) -> Item: ...
470
+
471
+ @overload
472
+ @setdoc.basic
473
+ def __getitem__(self: Self, key: Slice[SupportsIndex], /) -> Self: ...
474
+
475
+ @setdoc.basic
476
+ def __getitem__(
477
+ self: Self,
478
+ key: SupportsIndex | Slice[SupportsIndex],
479
+ /,
480
+ ) -> Item | Self:
481
+ if isinstance(key, SupportsIndex):
482
+ return self.__frozen__()[key]
483
+ else:
484
+ return type(self)(self.__frozen__()[key])
485
+
486
+ @setdoc.basic
487
+ def __gt__(self: Self, other: ListLike[Any], /) -> bool:
488
+ if isinstance(other, ListLike):
489
+ return self.__frozen__() > other.__frozen__()
490
+ else:
491
+ return NotImplemented
492
+
493
+ @abstractmethod
494
+ @setdoc.basic
495
+ def __init__(self: Self, data: Init[Item] = (), /) -> None: ...
496
+
497
+ @setdoc.basic
498
+ def __le__(self: Self, other: ListLike[Any], /) -> bool:
499
+ if isinstance(other, ListLike):
500
+ return self.__frozen__() <= other.__frozen__()
501
+ else:
502
+ return NotImplemented
503
+
504
+ @setdoc.basic
505
+ def __lt__(self: Self, other: ListLike[Any], /) -> bool:
506
+ if isinstance(other, ListLike):
507
+ return self.__frozen__() < other.__frozen__()
508
+ else:
509
+ return NotImplemented
510
+
511
+ @setdoc.basic
512
+ def __mul__(self: Self, other: SupportsIndex, /) -> Self:
513
+ if isinstance(other, SupportsIndex):
514
+ return type(self)(self.__frozen__() * other)
515
+ else:
516
+ raise TypeError
517
+
518
+ __rmul__ = __mul__
519
+
520
+ @setdoc.basic
521
+ def __repr__(self: Self, /) -> str:
522
+ return f"{type(self).__name__}({list(self)!r})"
523
+
524
+
525
+ class FrozenListLike[Item](ListLike[Item], abc.Hashable):
526
+ """Provide a base class for customized frozen list-likes."""
527
+
528
+ __slots__ = ()
529
+
530
+ @setdoc.basic
531
+ def __hash__(self: Self) -> int:
532
+ return hash(self.__frozen__())
533
+
534
+
535
+ class MutableListLike[Item](ListLike[Item], MutableSequence[Item]):
536
+ """Provide a base class for customized mutable list-likes."""
537
+
538
+ __slots__ = ()
539
+
540
+ type __Mutable__[MutableItem] = list[MutableItem]
541
+
542
+ @overload
543
+ @setdoc.basic
544
+ def __delitem__(self: Self, key: SupportsIndex, /) -> None: ...
545
+ @overload
546
+ @setdoc.basic
547
+ def __delitem__(self: Self, key: Slice[SupportsIndex], /) -> None: ...
548
+ @setdoc.basic
549
+ def __delitem__(
550
+ self: Self, key: SupportsIndex | Slice[SupportsIndex], /
551
+ ) -> None:
552
+ with self.__mutate__() as mutable:
553
+ del mutable[key]
554
+
555
+ @setdoc.basic
556
+ def __frozen__(self: Self) -> MutableListLike.__Frozen__[Item]:
557
+ with self.__mutate__() as mutable:
558
+ return tuple(mutable)
559
+
560
+ @setdoc.basic
561
+ def __imul__(self: Self, other: SupportsIndex, /) -> Self:
562
+ with self.__mutate__() as mutable:
563
+ mutable *= other
564
+ return self
565
+
566
+ @setdoc.basic
567
+ def __init__(self: Self, data: abc.Iterable[Item] = (), /) -> None:
568
+ with self.__mutate__() as mutable:
569
+ mutable.extend(data)
570
+
571
+ @abstractmethod
572
+ @setdoc.basic
573
+ def __mutate__(self: Self, /) -> ContextManager[__Mutable__[Item]]: ...
574
+
575
+ @overload
576
+ @setdoc.basic
577
+ def __setitem__(
578
+ self: Self, key: SupportsIndex, value: Item, /
579
+ ) -> None: ...
580
+ @overload
581
+ @setdoc.basic
582
+ def __setitem__(
583
+ self: Self, key: Slice[SupportsIndex], value: abc.Iterable[Item], /
584
+ ) -> None: ...
585
+ @setdoc.basic
586
+ def __setitem__(
587
+ self: Self,
588
+ key: SupportsIndex | Slice[SupportsIndex],
589
+ value: Item | abc.Iterable[Item],
590
+ /,
591
+ ) -> None:
592
+ with self.__mutate__() as mutable:
593
+ mutable[key] = value # type: ignore
594
+
595
+ @setdoc.basic
596
+ def copy(self: Self) -> Self:
597
+ return type(self)(self)
598
+
599
+ @setdoc.basic
600
+ def insert(self: Self, index: SupportsIndex, item: Item, /) -> None:
601
+ with self.__mutate__() as mutable:
602
+ mutable.insert(index, item)
603
+
604
+ @setdoc.basic
605
+ def sort(self: Self, /, *, key: Any = None, reverse: bool = False) -> None:
606
+ # list.sort reveals Overload(
607
+ # def [_T, SupportsRichComparisonT <: _typeshed.SupportsDunderLT[Any] | _typeshed.SupportsDunderGT[Any]] (self: list[SupportsRichComparisonT], *, key: None =, reverse: bool =),
608
+ # def [_T] (self: list[_T], *, key: def (_T) -> _typeshed.SupportsDunderLT[Any] | _typeshed.SupportsDunderGT[Any], reverse: bool =),
609
+ # )
610
+ with self.__mutate__() as mutable:
611
+ mutable.sort(key=key, reverse=reverse)
612
+
613
+
614
+ ### LIST-SLOT ###
615
+
616
+
617
+ class ListSlot[Item](ListLike[Item]):
618
+ """Provide slotted list-like class."""
619
+
620
+ __slots__ = ("_slot",)
621
+
622
+ _slot: ListSlot.__Frozen__[Item]
623
+
624
+ @setdoc.basic
625
+ def __frozen__(self: Self) -> ListSlot.__Frozen__[Item]:
626
+ return self._slot
627
+
628
+
629
+ class FrozenListSlot[Item](ListSlot[Item], FrozenListLike[Item]):
630
+ """Provide a base class for customized frozen data-holds."""
631
+
632
+ __slots__ = ()
633
+
634
+ @setdoc.basic
635
+ def __init__(self: Self, data: abc.Iterable[Item] = (), /) -> None:
636
+ self._slot = tuple(data)
637
+
638
+
639
+ class MutableListSlot[Item](ListSlot[Item], MutableListLike[Item]):
640
+ """Provide slotted mutable list-like class."""
641
+
642
+ __slots__ = ()
643
+
644
+ @contextmanager
645
+ @setdoc.basic
646
+ def __mutate__(self: Self, /) -> abc.Generator[list[Item], None, None]:
647
+ slot = list(getattr(self, "_slot", ()))
648
+ yield slot
649
+ self._slot = tuple(slot)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datahold
3
- Version: 4.0.0.dev10
3
+ Version: 4.0.0.dev21
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
@@ -29,6 +29,7 @@ tests/test_generic.py
29
29
  tests/test_internal_comparison.py
30
30
  tests/test_issubclass.py
31
31
  tests/test_nested.py
32
+ tests/test_prefix.py
32
33
  tests/test_sorted.py
33
34
  tests/test_variance.py
34
35
  tests/testdata.toml
@@ -0,0 +1,41 @@
1
+ from __future__ import annotations
2
+
3
+ __all__: list[str] = ["TestPrefix"]
4
+
5
+ import unittest
6
+ from collections import abc
7
+ from typing import Self
8
+
9
+ from Lazy import Lazy
10
+
11
+ import datahold
12
+
13
+
14
+ class TestPrefix(unittest.TestCase):
15
+ def _test_prefix(self: Self, name: str, /) -> None:
16
+ datatype = getattr(datahold, name)
17
+ self.assertEqual(datatype.__name__, name)
18
+ self.assertTrue(hasattr(datatype, "__Frozen__"))
19
+ self.assertTrue(hasattr(datatype, "__frozen__"))
20
+ if name.startswith("Frozen"):
21
+ self.assertIsNot(datatype.__hash__, object.__hash__)
22
+ self.assertTrue(issubclass(datatype, abc.Hashable))
23
+ self.assertFalse(hasattr(datatype, "__Mutable__"))
24
+ self.assertFalse(hasattr(datatype, "__mutate__"))
25
+ return
26
+ self.assertIn(datatype.__hash__, [None, object.__hash__])
27
+ if name.startswith("Mutable"):
28
+ self.assertTrue(hasattr(datatype, "__Mutable__"))
29
+ self.assertTrue(hasattr(datatype, "__mutate__"))
30
+ return
31
+ self.assertFalse(hasattr(datatype, "__Mutable__"))
32
+ self.assertFalse(hasattr(datatype, "__mutate__"))
33
+
34
+ def test_prefix(self: Self, /) -> None:
35
+ for name in Lazy.lazy.datatypes.keys():
36
+ with self.subTest(datatype=name):
37
+ self._test_prefix(name)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ unittest.main(verbosity=2)
@@ -1,3 +1,5 @@
1
+ [datatypes.Collection]
2
+
1
3
  [datatypes.FrozenListLike]
2
4
  abstractmethods = [
3
5
  "__frozen__",
@@ -16,9 +18,9 @@ __init__ = "datahold.ListLike"
16
18
  "collections.abc.Sequence" = true
17
19
 
18
20
  [datatypes.FrozenListLike.nested]
19
- Frozen = "builtins.tuple"
20
21
  Init = "collections.abc.Iterable"
21
- Mutable = ""
22
+ __Frozen__ = "builtins.tuple"
23
+ __Mutable__ = ""
22
24
 
23
25
  [datatypes.FrozenListLike.varia]
24
26
  generic = 1
@@ -131,13 +133,25 @@ args = [
131
133
  ]
132
134
 
133
135
  [datatypes.FrozenListSlot.nested]
134
- Frozen = "builtins.tuple"
135
136
  Init = "collections.abc.Iterable"
136
- Mutable = ""
137
+ __Frozen__ = "builtins.tuple"
138
+ __Mutable__ = ""
137
139
 
138
140
  [datatypes.FrozenListSlot.varia]
139
141
  generic = 1
140
142
 
143
+ [datatypes.FrozenSetLike.issubclass]
144
+ "collections.abc.Hashable" = true
145
+ "collections.abc.Set" = true
146
+ "datahold.Collection" = true
147
+ "datahold.SetLike" = true
148
+
149
+ [datatypes.FrozenSetSlot.issubclass]
150
+ "collections.abc.Collection" = true
151
+ "collections.abc.MutableSet" = false
152
+ "collections.abc.Set" = true
153
+ "datahold.Collection" = true
154
+
141
155
  [datatypes.ListLike]
142
156
  abstractmethods = [
143
157
  "__frozen__",
@@ -147,7 +161,7 @@ abstractmethods = [
147
161
  [datatypes.ListLike.attributes]
148
162
  __frozen__ = "datahold.ListLike"
149
163
  __init__ = "datahold.ListLike"
150
- __mutable__ = ""
164
+ __mutate__ = ""
151
165
  __reversed__ = "collections.abc.Sequence"
152
166
  count = "collections.abc.Sequence"
153
167
  index = "collections.abc.Sequence"
@@ -157,11 +171,12 @@ index = "collections.abc.Sequence"
157
171
  "collections.abc.MutableSequence" = false
158
172
  "collections.abc.Sequence" = true
159
173
  "datahold.ListLike" = true
174
+ "datahold.MutableSequence" = false
160
175
 
161
176
  [datatypes.ListLike.nested]
162
- Frozen = "builtins.tuple"
163
177
  Init = "collections.abc.Iterable"
164
- Mutable = ""
178
+ __Frozen__ = "builtins.tuple"
179
+ __Mutable__ = ""
165
180
 
166
181
  [datatypes.ListLike.varia]
167
182
  generic = 1
@@ -172,26 +187,25 @@ abstractmethods = [
172
187
  ]
173
188
 
174
189
  [datatypes.ListSlot.nested]
175
- Frozen = "builtins.tuple"
176
190
  Init = "collections.abc.Iterable"
177
- Mutable = ""
191
+ __Frozen__ = "builtins.tuple"
192
+ __Mutable__ = ""
178
193
 
179
194
  [datatypes.ListSlot.varia]
180
195
  generic = 1
181
196
 
182
197
  [datatypes.MutableListLike]
183
198
  abstractmethods = [
184
- "__frozen__",
185
- "__mutable__",
199
+ "__mutate__",
186
200
  ]
187
201
 
188
202
  [datatypes.MutableListLike.attributes]
189
203
  __add__ = "datahold.MutableListLike"
190
- __frozen__ = "datahold.ListLike"
204
+ __frozen__ = "datahold.MutableListLike"
191
205
  __iadd__ = "collections.abc.MutableSequence"
192
206
  __imul__ = "datahold.MutableListLike"
193
207
  __init__ = "datahold.MutableListLike"
194
- __mutable__ = "datahold.MutableListLike"
208
+ __mutate__ = "datahold.MutableListLike"
195
209
  __reversed__ = "collections.abc.Sequence"
196
210
  append = "collections.abc.MutableSequence"
197
211
  clear = "collections.abc.MutableSequence"
@@ -199,6 +213,7 @@ count = "collections.abc.Sequence"
199
213
  extend = "collections.abc.MutableSequence"
200
214
  foo = ""
201
215
  index = "collections.abc.Sequence"
216
+ insert = "datahold.MutableListLike"
202
217
  pop = "collections.abc.MutableSequence"
203
218
  remove = "collections.abc.MutableSequence"
204
219
  reverse = "collections.abc.MutableSequence"
@@ -208,10 +223,11 @@ reverse = "collections.abc.MutableSequence"
208
223
  "collections.abc.Hashable" = false
209
224
  "collections.abc.MutableMapping" = false
210
225
  "collections.abc.MutableSequence" = true
226
+ "datahold.MutableSequence" = true
211
227
 
212
228
  [datatypes.MutableListLike.nested]
213
- Frozen = "builtins.tuple"
214
229
  Init = "collections.abc.Iterable"
230
+ __Frozen__ = "builtins.tuple"
215
231
  __hash__ = ""
216
232
 
217
233
  [datatypes.MutableListLike.varia]
@@ -227,11 +243,63 @@ abstractmethods = []
227
243
  "datahold.MutableListSlot" = true
228
244
 
229
245
  [datatypes.MutableListSlot.nested]
230
- Frozen = "builtins.tuple"
231
246
  Init = "collections.abc.Iterable"
247
+ __Frozen__ = "builtins.tuple"
232
248
  __hash__ = ""
233
249
 
234
250
  [datatypes.MutableListSlot.varia]
235
251
  generic = 1
236
252
 
253
+ [datatypes.MutableSequence.attributes]
254
+ __Frozen__ = "datahold.Sequence"
255
+ __Mutable__ = "datahold.MutableSequence"
256
+ __delitem__ = "datahold.MutableSequence"
257
+ __frozen__ = "datahold.Sequence"
258
+ __getitem__ = "datahold.MutableSequence"
259
+ __mutate__ = "datahold.MutableSequence"
260
+ __setitem__ = "datahold.MutableSequence"
261
+ insert = "datahold.MutableSequence"
262
+ sort = ""
263
+
264
+ [datatypes.MutableSet.issubclass]
265
+ "collections.abc.MutableSet" = true
266
+ "collections.abc.Set" = true
267
+ "datahold.Collection" = true
268
+
269
+ [datatypes.MutableSetLike.issubclass]
270
+ "collections.abc.Hashable" = false
271
+ "collections.abc.MutableSet" = true
272
+ "collections.abc.Set" = true
273
+ "datahold.Collection" = true
274
+ "datahold.MutableSet" = true
275
+ "datahold.SetLike" = true
276
+
277
+ [datatypes.MutableSetSlot.issubclass]
278
+ "collections.abc.MutableSet" = true
279
+ "collections.abc.Set" = true
280
+ "datahold.Collection" = true
281
+ "datahold.MutableSet" = true
282
+ "datahold.MutableSetLike" = true
283
+ "datahold.SetSlot" = true
284
+
285
+ [datatypes.Sequence]
286
+ abstractmethods = [
287
+ "__frozen__",
288
+ ]
289
+
290
+ [datatypes.Set.issubclass]
291
+ "collections.abc.Set" = true
292
+ "datahold.Collection" = true
293
+
294
+ [datatypes.SetLike.issubclass]
295
+ "collections.abc.Set" = true
296
+ "datahold.Collection" = true
297
+ "datahold.Set" = true
298
+ "datahold.SetLike" = true
299
+
300
+ [datatypes.SetSlot.issubclass]
301
+ "collections.abc.Set" = true
302
+ "datahold.Collection" = true
303
+ "datahold.SetLike" = true
304
+
237
305
  [non_datatypes]
@@ -1,258 +0,0 @@
1
- """Provide provides base classes for customized collections."""
2
-
3
- from __future__ import annotations
4
-
5
- __all__: list[str] = [
6
- "FrozenListLike",
7
- "FrozenListSlot",
8
- "ListLike",
9
- "ListSlot",
10
- "MutableListLike",
11
- "MutableListSlot",
12
- ]
13
-
14
- from abc import abstractmethod
15
- from collections import abc
16
- from contextlib import contextmanager
17
- from types import NotImplementedType, TracebackType
18
- from typing import Any, Optional, Protocol, Self, SupportsIndex, overload
19
-
20
- import setdoc
21
-
22
- ### UTILS ###
23
-
24
- type Slice[Index] = slice[Optional[Index], Optional[Index], Optional[Index]]
25
-
26
-
27
- ### LIST-LIKE ###
28
- class ListLike[Item](abc.Sequence[Item]):
29
- """Provide a base class for customized list-likes."""
30
-
31
- __slots__ = ()
32
-
33
- type Frozen[FrozenItem] = tuple[FrozenItem, ...]
34
- # Frozen has to be tuple to allow covariance
35
-
36
- type Init[InitItem] = abc.Iterable[InitItem]
37
-
38
- @setdoc.basic
39
- def __add__[Item_](
40
- self: Self, other: ListLike[Item_], /
41
- ) -> ListLike[Item | Item_]:
42
- if isinstance(other, ListLike):
43
- return type(self)(self.__frozen__() + other.__frozen__()) # type: ignore[operator]
44
- else:
45
- raise TypeError
46
-
47
- @setdoc.basic
48
- def __contains__(self: Self, other: object, /) -> bool:
49
- return other in self.__frozen__()
50
-
51
- @setdoc.basic
52
- def __eq__(self: Self, other: object, /) -> NotImplementedType | bool:
53
- if isinstance(other, ListLike):
54
- return self.__frozen__() == other.__frozen__()
55
- else:
56
- return NotImplemented
57
-
58
- @abstractmethod
59
- @setdoc.basic
60
- def __frozen__(self: Self, /) -> Frozen[Item]: ...
61
-
62
- @setdoc.basic
63
- def __ge__(self: Self, other: ListLike[Any], /) -> bool:
64
- if isinstance(other, ListLike):
65
- return self.__frozen__() >= other.__frozen__()
66
- else:
67
- return NotImplemented
68
-
69
- @overload
70
- @setdoc.basic
71
- def __getitem__(self: Self, key: SupportsIndex, /) -> Item: ...
72
-
73
- @overload
74
- @setdoc.basic
75
- def __getitem__(self: Self, key: Slice[SupportsIndex], /) -> Self: ...
76
-
77
- @setdoc.basic
78
- def __getitem__(
79
- self: Self,
80
- key: SupportsIndex | Slice[SupportsIndex],
81
- /,
82
- ) -> Item | Self:
83
- if isinstance(key, SupportsIndex):
84
- return self.__frozen__()[key]
85
- else:
86
- return type(self)(self.__frozen__()[key])
87
-
88
- @setdoc.basic
89
- def __gt__(self: Self, other: ListLike[Any], /) -> bool:
90
- if isinstance(other, ListLike):
91
- return self.__frozen__() > other.__frozen__()
92
- else:
93
- return NotImplemented
94
-
95
- @abstractmethod
96
- @setdoc.basic
97
- def __init__(self: Self, data: Init[Item] = (), /) -> None: ...
98
-
99
- @setdoc.basic
100
- def __le__(self: Self, other: ListLike[Any], /) -> bool:
101
- if isinstance(other, ListLike):
102
- return self.__frozen__() <= other.__frozen__()
103
- else:
104
- return NotImplemented
105
-
106
- @setdoc.basic
107
- def __len__(self: Self, /) -> int:
108
- return len(self.__frozen__())
109
-
110
- @setdoc.basic
111
- def __lt__(self: Self, other: ListLike[Any], /) -> bool:
112
- if isinstance(other, ListLike):
113
- return self.__frozen__() < other.__frozen__()
114
- else:
115
- return NotImplemented
116
-
117
- @setdoc.basic
118
- def __mul__(self: Self, other: SupportsIndex, /) -> Self:
119
- if isinstance(other, SupportsIndex):
120
- return type(self)(self.__frozen__() * other)
121
- else:
122
- raise TypeError
123
-
124
- __rmul__ = __mul__
125
-
126
- @setdoc.basic
127
- def __repr__(self: Self, /) -> str:
128
- return f"{type(self).__name__}({list(self)!r})"
129
-
130
-
131
- class ListSlot[Item](ListLike[Item]):
132
- """Provide slotted list-like class."""
133
-
134
- __slots__ = ("_slot",)
135
-
136
- _slot: ListSlot.Frozen[Item]
137
-
138
- @setdoc.basic
139
- def __frozen__(self: Self) -> ListSlot.Frozen[Item]:
140
- return self._slot
141
-
142
-
143
- class FrozenListLike[Item](ListLike[Item], abc.Hashable):
144
- """Provide a base class for customized frozen list-likes."""
145
-
146
- __slots__ = ()
147
-
148
- @setdoc.basic
149
- def __hash__(self: Self) -> int:
150
- return hash(self.__frozen__())
151
-
152
-
153
- class FrozenListSlot[Item](ListSlot[Item], FrozenListLike[Item]):
154
- """Provide a base class for customized frozen data-holds."""
155
-
156
- __slots__ = ()
157
-
158
- @setdoc.basic
159
- def __init__(self: Self, data: abc.Iterable[Item] = (), /) -> None:
160
- self._slot = tuple(data)
161
-
162
-
163
- class MutableListLike[Item](ListLike[Item], abc.MutableSequence[Item]):
164
- """Provide a base class for customized mutable list-likes."""
165
-
166
- __slots__ = ()
167
-
168
- @setdoc.basic
169
- class Mutable[MutableItem](Protocol):
170
- @setdoc.basic
171
- def __enter__(self: Self, /) -> list[MutableItem]: ...
172
- @setdoc.basic
173
- def __exit__(
174
- self,
175
- exc_type: type[BaseException] | None,
176
- exc_value: BaseException | None,
177
- traceback: TracebackType | None,
178
- /,
179
- ) -> object: ...
180
-
181
- @overload
182
- @setdoc.basic
183
- def __delitem__(self: Self, key: SupportsIndex, /) -> None: ...
184
- @overload
185
- @setdoc.basic
186
- def __delitem__(self: Self, key: Slice[SupportsIndex], /) -> None: ...
187
- @setdoc.basic
188
- def __delitem__(
189
- self: Self, key: SupportsIndex | Slice[SupportsIndex], /
190
- ) -> None:
191
- with self.__mutable__() as mutable:
192
- del mutable[key]
193
-
194
- @setdoc.basic
195
- def __imul__(self: Self, other: SupportsIndex, /) -> Self:
196
- with self.__mutable__() as mutable:
197
- mutable *= other
198
- return self
199
-
200
- @setdoc.basic
201
- def __init__(self: Self, data: abc.Iterable[Item] = (), /) -> None:
202
- with self.__mutable__() as mutable:
203
- mutable.extend(data)
204
-
205
- @abstractmethod
206
- @setdoc.basic
207
- def __mutable__(self: Self, /) -> Mutable[Item]: ...
208
-
209
- @overload
210
- @setdoc.basic
211
- def __setitem__(
212
- self: Self, key: SupportsIndex, value: Item, /
213
- ) -> None: ...
214
- @overload
215
- @setdoc.basic
216
- def __setitem__(
217
- self: Self, key: Slice[SupportsIndex], value: abc.Iterable[Item], /
218
- ) -> None: ...
219
- @setdoc.basic
220
- def __setitem__(
221
- self: Self,
222
- key: SupportsIndex | Slice[SupportsIndex],
223
- value: Item | abc.Iterable[Item],
224
- /,
225
- ) -> None:
226
- with self.__mutable__() as mutable:
227
- mutable[key] = value # type: ignore
228
-
229
- @setdoc.basic
230
- def copy(self: Self) -> Self:
231
- return type(self)(self.__frozen__())
232
-
233
- @setdoc.basic
234
- def insert(self: Self, index: SupportsIndex, item: Item, /) -> None:
235
- with self.__mutable__() as mutable:
236
- mutable.insert(index, item)
237
-
238
- @setdoc.basic
239
- def sort(self: Self, /, *, key: Any = None, reverse: bool = False) -> None:
240
- # list.sort reveals Overload(
241
- # def [_T, SupportsRichComparisonT <: _typeshed.SupportsDunderLT[Any] | _typeshed.SupportsDunderGT[Any]] (self: list[SupportsRichComparisonT], *, key: None =, reverse: bool =),
242
- # def [_T] (self: list[_T], *, key: def (_T) -> _typeshed.SupportsDunderLT[Any] | _typeshed.SupportsDunderGT[Any], reverse: bool =),
243
- # )
244
- with self.__mutable__() as mutable:
245
- mutable.sort(key=key, reverse=reverse)
246
-
247
-
248
- class MutableListSlot[Item](ListSlot[Item], MutableListLike[Item]):
249
- """Provide slotted mutable list-like class."""
250
-
251
- __slots__ = ()
252
-
253
- @contextmanager
254
- @setdoc.basic
255
- def __mutable__(self: Self, /) -> abc.Generator[list[Item], None, None]:
256
- slot = list(getattr(self, "_slot", ()))
257
- yield slot
258
- self._slot = tuple(slot)
File without changes