dtools.datastructures 0.25.1__py3-none-any.whl → 0.25.2__py3-none-any.whl

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.
@@ -13,20 +13,20 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """
16
- ### package datastructures
16
+ ### Developer Tools - data structures for algorithms **DEPRICATED**
17
17
 
18
18
  Designed to be helpful when using and implementation algorithms.
19
19
 
20
20
  #### Modules and sub-packages
21
21
 
22
- * module dtools.datastructures.nodes: nodes for graph-like data structures
23
- * package dtools.datastructures.splitends: data sharing between mutable objects
24
- * module dtools.datastructures.tuples: tuple-like data structures
25
- * module dtools.datastructures.queues: queue data structures
22
+ * module dtools.datastructures.nodes: partly incorporated into dtools.splitends
23
+ * package dtools.datastructures.splitends: now dtools.splitends
24
+ * module dtools.datastructures.tuples: now dtools.tuples
25
+ * module dtools.datastructures.queues: now dtools.queues
26
26
 
27
27
  """
28
- __version__ = "0.25.1"
29
- __author__ = "Geoffrey R. Scheller"
30
- __copyright__ = "Copyright (c) 2023-2025 Geoffrey R. Scheller"
31
- __license__ = "Apache License 2.0"
32
28
 
29
+ __version__ = '0.25.2'
30
+ __author__ = 'Geoffrey R. Scheller'
31
+ __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
32
+ __license__ = 'Apache License 2.0'
@@ -25,18 +25,20 @@ other data structures which contain these data structures.
25
25
  * class **Tree_Node:**
26
26
 
27
27
  """
28
+
28
29
  from __future__ import annotations
29
30
  from collections.abc import Callable, Iterator
30
- from typing import Callable, cast, Iterator, TypeVar
31
+ from typing import cast, TypeVar
31
32
  from dtools.fp.err_handling import MB
32
33
 
33
34
  __all__ = ['SL_Node', 'DL_Node', 'Tree_Node']
34
35
 
35
- D = TypeVar('D')
36
+ D = TypeVar('D') # Not needed for mypy, hint for pdoc.
36
37
  M = TypeVar('M')
37
38
  T = TypeVar('T')
38
39
 
39
- class SL_Node[D]():
40
+
41
+ class SL_Node[D]:
40
42
  """Data node for rearward Pointing (tip-to-root) singularly linked graphs.
41
43
 
42
44
  * for mutable and immutable linear data structures
@@ -52,6 +54,7 @@ class SL_Node[D]():
52
54
  * more than one node can point to the same node forming bush like graphs
53
55
 
54
56
  """
57
+
55
58
  __slots__ = '_data', '_prev'
56
59
 
57
60
  def __init__(self, data: D, prev: MB[SL_Node[D]]) -> None:
@@ -69,12 +72,14 @@ class SL_Node[D]():
69
72
  return self._prev != MB()
70
73
 
71
74
  def data_eq(self, other: SL_Node[D]) -> bool:
75
+ """Return true if other has same or equal data."""
72
76
  if self._data is other._data:
73
77
  return True
74
- elif self._data == other._data:
78
+
79
+ if self._data == other._data:
75
80
  return True
76
- else:
77
- return False
81
+
82
+ return False
78
83
 
79
84
  def __eq__(self, other: object) -> bool:
80
85
  if not isinstance(other, type(self)):
@@ -82,13 +87,14 @@ class SL_Node[D]():
82
87
 
83
88
  if self._prev is not other._prev:
84
89
  return False
85
- else:
86
- return self.data_eq(other)
90
+
91
+ return self.data_eq(other)
87
92
 
88
93
  def get_data(self) -> D:
94
+ """Return contained data"""
89
95
  return self._data
90
96
 
91
- def fold[T](self, f: Callable[[T, D], T], init: T|None=None) -> T:
97
+ def fold[T](self, f: Callable[[T, D], T], init: T | None = None) -> T:
92
98
  """Reduce data across linked nodes.
93
99
 
94
100
  * with a function and an optional starting value
@@ -117,7 +123,8 @@ class SL_Node[D]():
117
123
  """Push data onto the stack and return a new node containing the data."""
118
124
  return SL_Node(data, MB(self))
119
125
 
120
- class DL_Node[D]():
126
+
127
+ class DL_Node[D]:
121
128
  """Doubly Linked Node.
122
129
 
123
130
  Doubly linked nodes for graph-like data structures.
@@ -129,6 +136,7 @@ class DL_Node[D]():
129
136
  * simple recursive binary trees possible
130
137
 
131
138
  """
139
+
132
140
  __slots__ = '_left', '_data', '_right'
133
141
 
134
142
  def __init__(self, left: MB[DL_Node[D]], data: D, right: MB[DL_Node[D]]):
@@ -162,33 +170,33 @@ class DL_Node[D]():
162
170
  def has_right(self) -> bool:
163
171
  return self._right != MB()
164
172
 
165
- class Tree_Node[D, M]():
166
- """Binary Tree Node with metadata.
173
+
174
+ class Tree_Node[D]:
175
+ """Binary Tree Node.
167
176
 
168
177
  Nodes useful for binary trees.
169
178
 
170
179
  * this type of node always contain data, even if that data is None
171
180
  * in a Boolean context return true if not at the top of the tree
172
- * potential uses of metadata can be for re-balancing or repeat counts
173
181
  """
182
+
174
183
  __slots__ = '_data', '_left', '_right', '_up'
175
184
 
176
- def __init__(self, data: D,
177
- up: MB[Tree_Node[D,M]],
178
- left: MB[Tree_Node[D,M]],
179
- right: MB[Tree_Node[D,M]],
180
- meta: tuple[M, ...] = ()):
185
+ def __init__(
186
+ self,
187
+ data: D,
188
+ up: MB[Tree_Node[D]],
189
+ left: MB[Tree_Node[D]],
190
+ right: MB[Tree_Node[D]]
191
+ ):
181
192
  self._data = data
182
193
  self._up = up
183
194
  self._left = left
184
195
  self._right = right
185
196
 
186
197
  def __bool__(self) -> bool:
187
- if self._up == MB():
188
- return False
189
- else:
190
- return True
198
+ return bool(self)
191
199
 
192
200
  def is_top(self) -> bool:
201
+ """Return true if top node"""
193
202
  return self._up == MB()
194
-
@@ -12,7 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """### Queue based data structures
15
+ """
16
+ ### Queue based data structures
16
17
 
17
18
  * stateful queue data structures with amortized O(1) pushes and pops each end
18
19
  * obtaining length (number of elements) of a queue is an O(1) operation
@@ -39,6 +40,7 @@
39
40
  * function DQ: Constructs a DoubleQueue from a variable number of arguments
40
41
 
41
42
  """
43
+
42
44
  from __future__ import annotations
43
45
 
44
46
  from collections.abc import Callable, Iterable, Iterator, Sequence
@@ -46,14 +48,14 @@ from typing import Never, overload, TypeVar
46
48
  from dtools.circular_array.ca import ca, CA
47
49
  from dtools.fp.err_handling import MB
48
50
 
49
- __all__ = [ 'DoubleQueue', 'FIFOQueue', 'LIFOQueue', 'QueueBase',
50
- 'DQ', 'FQ', 'LQ' ]
51
+ __all__ = ['DoubleQueue', 'FIFOQueue', 'LIFOQueue', 'QueueBase', 'DQ', 'FQ', 'LQ']
51
52
 
52
- D = TypeVar('D')
53
+ D = TypeVar('D') # Not needed for mypy, hint for pdoc.
53
54
  L = TypeVar('L')
54
55
  R = TypeVar('R')
55
56
  U = TypeVar('U')
56
57
 
58
+
57
59
  class QueueBase[D](Sequence[D]):
58
60
  """Base class for circular area based queues.
59
61
 
@@ -62,7 +64,8 @@ class QueueBase[D](Sequence[D]):
62
64
  * slicing not yet implemented
63
65
 
64
66
  """
65
- __slots__ = '_ca'
67
+
68
+ __slots__ = ('_ca',)
66
69
 
67
70
  def __init__(self, *dss: Iterable[D]) -> None:
68
71
  if len(dss) < 2:
@@ -70,7 +73,7 @@ class QueueBase[D](Sequence[D]):
70
73
  else:
71
74
  msg1 = f'{type(self).__name__}: expected at most 1 '
72
75
  msg2 = f'iterable argument, got {len(dss)}.'
73
- raise TypeError(msg1+msg2)
76
+ raise TypeError(msg1 + msg2)
74
77
 
75
78
  def __bool__(self) -> bool:
76
79
  return len(self._ca) > 0
@@ -88,11 +91,12 @@ class QueueBase[D](Sequence[D]):
88
91
  @overload
89
92
  def __getitem__(self, idx: slice, /) -> Sequence[D]: ...
90
93
 
91
- def __getitem__(self, idx: int|slice, /) -> D|Sequence[D]|Never:
94
+ def __getitem__(self, idx: int | slice, /) -> D | Sequence[D] | Never:
92
95
  if isinstance(idx, slice):
93
96
  raise NotImplementedError
94
97
  return self._ca[idx]
95
98
 
99
+
96
100
  class FIFOQueue[D](QueueBase[D]):
97
101
  """FIFO Queue
98
102
 
@@ -100,6 +104,7 @@ class FIFOQueue[D](QueueBase[D]):
100
104
  * initial data pushed on in natural FIFO order
101
105
 
102
106
  """
107
+
103
108
  __slots__ = ()
104
109
 
105
110
  def __iter__(self) -> Iterator[D]:
@@ -112,7 +117,7 @@ class FIFOQueue[D](QueueBase[D]):
112
117
  return 'FQ(' + ', '.join(map(repr, self._ca)) + ')'
113
118
 
114
119
  def __str__(self) -> str:
115
- return "<< " + " < ".join(map(str, self)) + " <<"
120
+ return '<< ' + ' < '.join(map(str, self)) + ' <<'
116
121
 
117
122
  def copy(self) -> FIFOQueue[D]:
118
123
  """Return a shallow copy of the `FIFOQueue`."""
@@ -164,7 +169,7 @@ class FIFOQueue[D](QueueBase[D]):
164
169
  else:
165
170
  return MB()
166
171
 
167
- def fold[L](self, f: Callable[[L, D], L], initial: L|None=None, /) -> MB[L]:
172
+ def fold[L](self, f: Callable[[L, D], L], initial: L | None = None, /) -> MB[L]:
168
173
  """Fold `FIFOQueue` in natural order.
169
174
 
170
175
  Reduce with `f` using an optional initial value.
@@ -191,6 +196,7 @@ class FIFOQueue[D](QueueBase[D]):
191
196
  """
192
197
  return FIFOQueue(map(f, self._ca))
193
198
 
199
+
194
200
  class LIFOQueue[D](QueueBase[D]):
195
201
  """LIFO Queue.
196
202
 
@@ -198,6 +204,7 @@ class LIFOQueue[D](QueueBase[D]):
198
204
  * initial data pushed on in natural LIFO order
199
205
 
200
206
  """
207
+
201
208
  __slots__ = ()
202
209
 
203
210
  def __iter__(self) -> Iterator[D]:
@@ -206,11 +213,10 @@ class LIFOQueue[D](QueueBase[D]):
206
213
  def __repr__(self) -> str:
207
214
  if len(self) == 0:
208
215
  return 'LQ()'
209
- else:
210
- return 'LQ(' + ', '.join(map(repr, self._ca)) + ')'
216
+ return 'LQ(' + ', '.join(map(repr, self._ca)) + ')'
211
217
 
212
218
  def __str__(self) -> str:
213
- return "|| " + " > ".join(map(str, self)) + " ><"
219
+ return '|| ' + ' > '.join(map(str, self)) + ' ><'
214
220
 
215
221
  def copy(self) -> LIFOQueue[D]:
216
222
  """Return a shallow copy of the `LIFOQueue`."""
@@ -233,8 +239,7 @@ class LIFOQueue[D](QueueBase[D]):
233
239
  """
234
240
  if self._ca:
235
241
  return MB(self._ca.popR())
236
- else:
237
- return MB()
242
+ return MB()
238
243
 
239
244
  def peak(self) -> MB[D]:
240
245
  """Peak next data out of `LIFOQueue`.
@@ -246,10 +251,9 @@ class LIFOQueue[D](QueueBase[D]):
246
251
  """
247
252
  if self._ca:
248
253
  return MB(self._ca[-1])
249
- else:
250
- return MB()
254
+ return MB()
251
255
 
252
- def fold[R](self, f: Callable[[D, R], R], initial: R|None=None, /) -> MB[R]:
256
+ def fold[R](self, f: Callable[[D, R], R], initial: R | None = None, /) -> MB[R]:
253
257
  """Fold `LIFOQueue` in natural order.
254
258
 
255
259
  Reduce with `f` using an optional initial value.
@@ -276,6 +280,7 @@ class LIFOQueue[D](QueueBase[D]):
276
280
  """
277
281
  return LIFOQueue(reversed(CA(*map(f, reversed(self._ca)))))
278
282
 
283
+
279
284
  class DoubleQueue[D](QueueBase[D]):
280
285
  """Double Ended Queue
281
286
 
@@ -283,6 +288,7 @@ class DoubleQueue[D](QueueBase[D]):
283
288
  * order of initial data retained
284
289
 
285
290
  """
291
+
286
292
  __slots__ = ()
287
293
 
288
294
  def __iter__(self) -> Iterator[D]:
@@ -294,11 +300,10 @@ class DoubleQueue[D](QueueBase[D]):
294
300
  def __repr__(self) -> str:
295
301
  if len(self) == 0:
296
302
  return 'DQ()'
297
- else:
298
- return 'DQ(' + ', '.join(map(repr, self._ca)) + ')'
303
+ return 'DQ(' + ', '.join(map(repr, self._ca)) + ')'
299
304
 
300
305
  def __str__(self) -> str:
301
- return ">< " + " | ".join(map(str, self)) + " ><"
306
+ return '>< ' + ' | '.join(map(str, self)) + ' ><'
302
307
 
303
308
  def copy(self) -> DoubleQueue[D]:
304
309
  """Return a shallow copy of the `DoubleQueue`."""
@@ -341,8 +346,7 @@ class DoubleQueue[D](QueueBase[D]):
341
346
  """
342
347
  if self._ca:
343
348
  return MB(self._ca.popR())
344
- else:
345
- return MB()
349
+ return MB()
346
350
 
347
351
  def peakL(self) -> MB[D]:
348
352
  """Peak left side of `DoubleQueue`.
@@ -354,8 +358,7 @@ class DoubleQueue[D](QueueBase[D]):
354
358
  """
355
359
  if self._ca:
356
360
  return MB(self._ca[0])
357
- else:
358
- return MB()
361
+ return MB()
359
362
 
360
363
  def peakR(self) -> MB[D]:
361
364
  """Peak right side of `DoubleQueue`.
@@ -367,10 +370,9 @@ class DoubleQueue[D](QueueBase[D]):
367
370
  """
368
371
  if self._ca:
369
372
  return MB(self._ca[-1])
370
- else:
371
- return MB()
373
+ return MB()
372
374
 
373
- def foldL[L](self, f: Callable[[L, D], L], initial: L|None=None, /) -> MB[L]:
375
+ def foldL[L](self, f: Callable[[L, D], L], initial: L | None = None, /) -> MB[L]:
374
376
  """Fold `DoubleQueue` left to right.
375
377
 
376
378
  Reduce left with `f` using an optional initial value.
@@ -385,7 +387,7 @@ class DoubleQueue[D](QueueBase[D]):
385
387
  return MB()
386
388
  return MB(self._ca.foldL(f, initial=initial))
387
389
 
388
- def foldR[R](self, f: Callable[[D, R], R], initial: R|None=None, /) -> MB[R]:
390
+ def foldR[R](self, f: Callable[[D, R], R], initial: R | None = None, /) -> MB[R]:
389
391
  """Fold `DoubleQueue` right to left.
390
392
 
391
393
  Reduce right with `f` using an optional initial value.
@@ -411,15 +413,17 @@ class DoubleQueue[D](QueueBase[D]):
411
413
  """
412
414
  return DoubleQueue(map(f, self._ca))
413
415
 
416
+
414
417
  def FQ[D](*ds: D) -> FIFOQueue[D]:
415
418
  """Return a FIFOQueue where data is pushed on in natural FIFO order."""
416
419
  return FIFOQueue(ds)
417
420
 
421
+
418
422
  def LQ[D](*ds: D) -> LIFOQueue[D]:
419
423
  """Return a LIFOQueue where data is pushed on in natural LIFO order."""
420
424
  return LIFOQueue(ds)
421
425
 
426
+
422
427
  def DQ[D](*ds: D) -> DoubleQueue[D]:
423
428
  """Return a DoubleQueue whose data is pushed on from the right."""
424
429
  return DoubleQueue(ds)
425
-
@@ -22,7 +22,7 @@ Singularly linked datastructures that can safely share data between themselves.
22
22
  * module **dtools.datastructures.splitends.se: Basic SplitEnd data structure
23
23
 
24
24
  """
25
- __author__ = "Geoffrey R. Scheller"
26
- __copyright__ = "Copyright (c) 2024-2025 Geoffrey R. Scheller"
27
- __license__ = "Apache License 2.0"
28
25
 
26
+ __author__ = 'Geoffrey R. Scheller'
27
+ __copyright__ = 'Copyright (c) 2024-2025 Geoffrey R. Scheller'
28
+ __license__ = 'Apache License 2.0'
@@ -12,7 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """### SplitEnd stack related data structures
15
+ """
16
+ ### SplitEnd stack related data structures
16
17
 
17
18
  With use I am finding this data structure needs some sort of supporting
18
19
  infrastructure. Hence I split the original splitend module out to be its own
@@ -24,19 +25,21 @@ subpackage.
24
25
  * function SE: create SplitEnd from a variable number of arguments
25
26
 
26
27
  """
28
+
27
29
  from __future__ import annotations
28
30
 
29
31
  from collections.abc import Callable, Iterable, Iterator
30
- from typing import cast, Never, TypeVar
31
- from ..nodes import SL_Node
32
+ from typing import Never, TypeVar
32
33
  from dtools.fp.err_handling import MB
34
+ from ..nodes import SL_Node
33
35
 
34
- __all__ = [ 'SplitEnd', 'SE' ]
36
+ __all__ = ['SplitEnd', 'SE']
35
37
 
36
38
  D = TypeVar('D')
37
39
  T = TypeVar('T')
38
40
 
39
- class SplitEnd[D]():
41
+
42
+ class SplitEnd[D]:
40
43
  """Class SplitEnd
41
44
 
42
45
  LIFO stacks which can safely share immutable data between themselves.
@@ -51,10 +54,11 @@ class SplitEnd[D]():
51
54
  * in boolean context, return true if split end is not empty
52
55
 
53
56
  """
57
+
54
58
  __slots__ = '_count', '_tip'
55
59
 
56
60
  def __init__(self, *dss: Iterable[D]) -> None:
57
- if length:=len(dss) < 2:
61
+ if length := len(dss) < 2:
58
62
  self._tip: MB[SL_Node[D]] = MB()
59
63
  self._count: int = 0
60
64
  if length == 1:
@@ -62,7 +66,7 @@ class SplitEnd[D]():
62
66
  else:
63
67
  msg1 = 'SplitEnd: expected at most 1 '
64
68
  msg2 = f'iterable argument, got {length}.'
65
- raise TypeError(msg1+msg2)
69
+ raise TypeError(msg1 + msg2)
66
70
 
67
71
  def __iter__(self) -> Iterator[D]:
68
72
  if self._tip == MB():
@@ -84,7 +88,7 @@ class SplitEnd[D]():
84
88
  return 'SE(' + ', '.join(map(repr, reversed(self))) + ')'
85
89
 
86
90
  def __str__(self) -> str:
87
- return ('>< ' + ' -> '.join(map(str, self)) + ' ||')
91
+ return '>< ' + ' -> '.join(map(str, self)) + ' ||'
88
92
 
89
93
  def __eq__(self, other: object, /) -> bool:
90
94
  if not isinstance(other, type(self)):
@@ -112,15 +116,15 @@ class SplitEnd[D]():
112
116
  """Push data onto the top of the SplitEnd."""
113
117
  for d in ds:
114
118
  node = SL_Node(d, self._tip)
115
- self._tip, self._count = MB(node), self._count+1
119
+ self._tip, self._count = MB(node), self._count + 1
116
120
 
117
121
  def push(self, *ds: D) -> None:
118
122
  """Push data onto the top of the SplitEnd."""
119
123
  for d in ds:
120
124
  node = SL_Node(d, self._tip)
121
- self._tip, self._count = MB(node), self._count+1
125
+ self._tip, self._count = MB(node), self._count + 1
122
126
 
123
- def pop(self, default: D|None = None, /) -> D|Never:
127
+ def pop(self, default: D | None = None, /) -> D | Never:
124
128
  """Pop data off of the top of the SplitEnd.
125
129
 
126
130
  * raises ValueError if
@@ -131,13 +135,12 @@ class SplitEnd[D]():
131
135
  if self._count == 0:
132
136
  if default is None:
133
137
  raise ValueError('SE: Popping from an empty SplitEnd')
134
- else:
135
- return default
138
+ return default
136
139
 
137
- data, self._tip, self._count = self._tip.get().pop2() + (self._count-1,)
140
+ data, self._tip, self._count = self._tip.get().pop2() + (self._count - 1,)
138
141
  return data
139
142
 
140
- def peak(self, default: D|None = None, /) -> D:
143
+ def peak(self, default: D | None = None, /) -> D:
141
144
  """Return the data at the top of the SplitEnd.
142
145
 
143
146
  * does not consume the data
@@ -147,8 +150,7 @@ class SplitEnd[D]():
147
150
  if self._count == 0:
148
151
  if default is None:
149
152
  raise ValueError('SE: Popping from an empty SplitEnd')
150
- else:
151
- return default
153
+ return default
152
154
 
153
155
  return self._tip.get().get_data()
154
156
 
@@ -163,7 +165,7 @@ class SplitEnd[D]():
163
165
  se._tip, se._count = self._tip, self._count
164
166
  return se
165
167
 
166
- def fold[T](self, f:Callable[[T, D], T], init: T|None = None, /) -> T|Never:
168
+ def fold[T](self, f: Callable[[T, D], T], init: T | None = None, /) -> T | Never:
167
169
  """Reduce with a function.
168
170
 
169
171
  * folds in natural LIFO Order
@@ -171,12 +173,13 @@ class SplitEnd[D]():
171
173
  """
172
174
  if self._tip != MB():
173
175
  return self._tip.get().fold(f, init)
174
- elif init is not None:
176
+
177
+ if init is not None:
175
178
  return init
176
- else:
177
- msg = 'SE: Folding empty SplitEnd but no initial value supplied'
178
- raise ValueError(msg)
179
+
180
+ msg = 'SE: Folding empty SplitEnd but no initial value supplied'
181
+ raise ValueError(msg)
182
+
179
183
 
180
184
  def SE[D](*ds: D) -> SplitEnd[D]:
181
185
  return SplitEnd(ds)
182
-
@@ -12,19 +12,20 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """### Tuple based data structures
15
+ """
16
+ ### Tuple based data structures
16
17
 
17
18
  Only example here is the ftuple, basically an FP interface wrapping a tuple.
18
- Originally it inherited from tuple, but I found containing the tuple in a
19
+ Originally it inherited from tuple, but I found containing the tuple in a
19
20
  "has-a" relationship makes for a faster implementation. Buried in the git
20
21
  history is another example called a "process array" (parray) which I might
21
22
  return to someday. The idea of the parray is a fixed length sequence with
22
- sentinel values.
23
+ sentinel values.
23
24
 
24
25
  #### FTuple and FT factory function.
25
26
 
26
27
  * class FTuple: Wrapped tuple with a Functional Programming API
27
- * function FE:
28
+ * function FE:
28
29
 
29
30
  """
30
31
 
@@ -36,12 +37,13 @@ from dtools.fp.iterables import FM, accumulate, concat, exhaust, merge
36
37
 
37
38
  __all__ = ['FTuple', 'FT']
38
39
 
39
- D = TypeVar('D')
40
+ D = TypeVar('D') # Not needed for mypy, hint for pdoc.
40
41
  E = TypeVar('E')
41
42
  L = TypeVar('L')
42
- R = TypeVar('L')
43
+ R = TypeVar('R')
43
44
  U = TypeVar('U')
44
45
 
46
+
45
47
  class FTuple[D](Sequence[D]):
46
48
  """
47
49
  #### Functional Tuple
@@ -53,7 +55,8 @@ class FTuple[D](Sequence[D]):
53
55
  * both left and right int multiplication supported
54
56
 
55
57
  """
56
- __slots__ = '_ds'
58
+
59
+ __slots__ = ('_ds',)
57
60
 
58
61
  def __init__(self, *dss: Iterable[D]) -> None:
59
62
  if len(dss) < 2:
@@ -69,7 +72,7 @@ class FTuple[D](Sequence[D]):
69
72
  return reversed(self._ds)
70
73
 
71
74
  def __bool__(self) -> bool:
72
- return bool(len(self._ds))
75
+ return bool(self._ds)
73
76
 
74
77
  def __len__(self) -> int:
75
78
  return len(self._ds)
@@ -78,7 +81,7 @@ class FTuple[D](Sequence[D]):
78
81
  return 'FT(' + ', '.join(map(repr, self)) + ')'
79
82
 
80
83
  def __str__(self) -> str:
81
- return "((" + ", ".join(map(repr, self)) + "))"
84
+ return '((' + ', '.join(map(repr, self)) + '))'
82
85
 
83
86
  def __eq__(self, other: object, /) -> bool:
84
87
  if self is other:
@@ -92,16 +95,18 @@ class FTuple[D](Sequence[D]):
92
95
  @overload
93
96
  def __getitem__(self, idx: slice, /) -> FTuple[D]: ...
94
97
 
95
- def __getitem__(self, idx: slice|int, /) -> FTuple[D]|D:
98
+ def __getitem__(self, idx: slice | int, /) -> FTuple[D] | D:
96
99
  if isinstance(idx, slice):
97
100
  return FTuple(self._ds[idx])
98
- else:
99
- return self._ds[idx]
100
-
101
- def foldL[L](self,
102
- f: Callable[[L, D], L], /,
103
- start: L|None=None,
104
- default: L|None=None) -> L|None:
101
+ return self._ds[idx]
102
+
103
+ def foldL[L](
104
+ self,
105
+ f: Callable[[L, D], L],
106
+ /,
107
+ start: L | None = None,
108
+ default: L | None = None,
109
+ ) -> L | None:
105
110
  """
106
111
  **Fold Left**
107
112
 
@@ -124,10 +129,13 @@ class FTuple[D](Sequence[D]):
124
129
  acc = f(acc, v)
125
130
  return acc
126
131
 
127
- def foldR[R](self,
128
- f: Callable[[D, R], R], /,
129
- start: R|None=None,
130
- default: R|None=None) -> R|None:
132
+ def foldR[R](
133
+ self,
134
+ f: Callable[[D, R], R],
135
+ /,
136
+ start: R | None = None,
137
+ default: R | None = None,
138
+ ) -> R | None:
131
139
  """
132
140
  **Fold Right**
133
141
 
@@ -159,7 +167,7 @@ class FTuple[D](Sequence[D]):
159
167
  """
160
168
  return FTuple(self)
161
169
 
162
- def __add__[E](self, other: FTuple[E], /) -> FTuple[D|E]:
170
+ def __add__[E](self, other: FTuple[E], /) -> FTuple[D | E]:
163
171
  return FTuple(concat(self, other))
164
172
 
165
173
  def __mul__(self, num: int, /) -> FTuple[D]:
@@ -168,7 +176,9 @@ class FTuple[D](Sequence[D]):
168
176
  def __rmul__(self, num: int, /) -> FTuple[D]:
169
177
  return FTuple(self._ds.__mul__(num if num > 0 else 0))
170
178
 
171
- def accummulate[L](self, f: Callable[[L, D], L], s: L|None=None, /) -> FTuple[L]:
179
+ def accummulate[L](
180
+ self, f: Callable[[L, D], L], s: L | None = None, /
181
+ ) -> FTuple[L]:
172
182
  """
173
183
  **Accumulate partial folds**
174
184
 
@@ -178,13 +188,14 @@ class FTuple[D](Sequence[D]):
178
188
  """
179
189
  if s is None:
180
190
  return FTuple(accumulate(self, f))
181
- else:
182
- return FTuple(accumulate(self, f, s))
191
+ return FTuple(accumulate(self, f, s))
183
192
 
184
193
  def map[U](self, f: Callable[[D], U], /) -> FTuple[U]:
185
194
  return FTuple(map(f, self))
186
195
 
187
- def bind[U](self, f: Callable[[D], FTuple[U]], type: FM=FM.CONCAT, /) -> FTuple[U]:
196
+ def bind[U](
197
+ self, f: Callable[[D], FTuple[U]], type: FM = FM.CONCAT, /
198
+ ) -> FTuple[U]:
188
199
  """
189
200
  Bind function `f` to the `FTuple`.
190
201
 
@@ -195,15 +206,15 @@ class FTuple[D](Sequence[D]):
195
206
  """
196
207
  match type:
197
208
  case FM.CONCAT:
198
- return FTuple(concat(*map(lambda x: iter(x), map(f, self))))
209
+ return FTuple(concat(*map(f, self)))
199
210
  case FM.MERGE:
200
- return FTuple(merge(*map(lambda x: iter(x), map(f, self))))
211
+ return FTuple(merge(*map(f, self)))
201
212
  case FM.EXHAUST:
202
- return FTuple(exhaust(*map(lambda x: iter(x), map(f, self))))
213
+ return FTuple(exhaust(*map(f, self)))
203
214
  case '*':
204
215
  raise ValueError('Unknown FM type')
205
216
 
217
+
206
218
  def FT[D](*ds: D) -> FTuple[D]:
207
219
  """Return an FTuple whose values are the function arguments."""
208
220
  return FTuple(ds)
209
-
@@ -1,18 +1,19 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: dtools.datastructures
3
- Version: 0.25.1
4
- Summary: ### package datastructures
3
+ Version: 0.25.2
4
+ Summary: ### Developer Tools - data structures for algorithms **DEPRICATED**
5
5
  Keywords: datastructures,data structures,fifo,lifo,stack,queue,SplitEnd
6
6
  Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
7
7
  Requires-Python: >=3.12
8
8
  Description-Content-Type: text/markdown
9
- Classifier: Development Status :: 4 - Beta
9
+ Classifier: Development Status :: 7 - Inactive
10
10
  Classifier: Framework :: Pytest
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Typing :: Typed
16
+ License-File: LICENSE
16
17
  Requires-Dist: dtools.circular-array >= 3.9.0, < 3.10
17
18
  Requires-Dist: dtools.fp >= 1.4.0, < 1.5
18
19
  Requires-Dist: pytest >=8.3.2 ; extra == "test"
@@ -21,21 +22,27 @@ Project-URL: Documentation, https://grscheller.github.io/dtools-docs/datastructu
21
22
  Project-URL: Source, https://github.com/grscheller/dtools-datastructures
22
23
  Provides-Extra: test
23
24
 
24
- # Developer Tools - Datastructures Useful for Algorithms
25
+ # Developer Tools - data structures useful for algorithms
26
+
27
+ **DEPRECATED** This project was broken up into separate projects.
28
+
29
+ * package dtools.datastructures.splitends `->` dtools.splitends
30
+ * module dtools.datastructures.tuples `->` dtools.tuples
31
+ * module dtools.datastructures.queues `->` dtools.queues
25
32
 
26
33
  Python package of data structures which support the use and
27
34
  implementation of algorithms.
28
35
 
29
- * **Repositories**
30
- * [dtools.datastructures][1] project on *PyPI*
31
- * [Source code][2] on *GitHub*
32
- * **Detailed documentation**
33
- * [Detailed API documentation][3] on *GH-Pages*
36
+ - **Repositories**
37
+ - [dtools.datastructures][1] project on *PyPI*
38
+ - [Source code][2] on *GitHub*
39
+ - **Detailed documentation**
40
+ - [Detailed API documentation][3] on *GH-Pages*
34
41
 
35
42
  This project is part of the
36
43
  [Developer Tools for Python][4] **dtools.** namespace project.
37
44
 
38
- ### Overview
45
+ ## Overview
39
46
 
40
47
  Data structures allowing developers to focus on the algorithms they are
41
48
  using instead of all the "bit fiddling" required to implement behaviors,
@@ -47,23 +54,22 @@ introducing inordinate complexity. Some of these data structures allow
47
54
  data to be safely shared between multiple data structure instances by
48
55
  making shared data immutable and inaccessible to client code.
49
56
 
50
- * functional & imperative programming styles supported
51
- * functional programming encouraged
52
- * project endeavors to remain Pythonic
53
- * methods which mutate objects don't return anything
54
- * like Python lists
55
- * in caparisons identity is considered before equality
56
- * like Python builtins
57
+ - functional & imperative programming styles supported
58
+ - functional programming encouraged
59
+ - project endeavors to remain Pythonic
60
+ - methods which mutate objects don't return anything
61
+ - like Python lists
62
+ - in caparisons identity is considered before equality
63
+ - like Python builtins
57
64
 
58
65
  Sometimes the real power of a data structure comes not from what it
59
66
  empowers you to do, but from what it prevents you from doing to
60
67
  yourself.
61
68
 
62
- ---
69
+ ______________________________________________________________________
63
70
 
64
71
  [1]: https://pypi.org/project/dtools.datastructures/
65
72
  [2]: https://github.com/grscheller/dtools-datastructures/
66
73
  [3]: https://grscheller.github.io/dtools-docs/datastructures/
67
74
  [4]: https://github.com/grscheller/dtools-docs
68
75
 
69
-
@@ -0,0 +1,12 @@
1
+ dtools/datastructures/__init__.py,sha256=edwJO3bIyCDcMy7ljHgr87gDlJCO8FvnrM0Ca3wH1iA,1181
2
+ dtools/datastructures/nodes.py,sha256=diz30k76co1DX30jGlQKiR6PdbaUEUgp-Qsgsv0467c,5666
3
+ dtools/datastructures/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ dtools/datastructures/queues.py,sha256=DJLvhmW_CKvZu3ghiCm2ud74lUEQsoHcnwFCEJBSk2I,12111
5
+ dtools/datastructures/tuples.py,sha256=TjGyA2roVZSBozRx9MxQRJ5aYaiLTckYwsesKoVcJ0k,6677
6
+ dtools/datastructures/splitends/__init__.py,sha256=EvDVQRe7P7utFSTyLcglYxkXLpDP9ccjQzWxz-mcWZ4,946
7
+ dtools/datastructures/splitends/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ dtools/datastructures/splitends/se.py,sha256=XNVfoOfZh3KAQDTg4ZbinPLUyGokFywrfKLEVcmZF4k,5591
9
+ dtools_datastructures-0.25.2.dist-info/licenses/LICENSE,sha256=csqbZRvA3Nyuav1aszWvswE8CZtaKr-hMjjjcKqms7w,10774
10
+ dtools_datastructures-0.25.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
11
+ dtools_datastructures-0.25.2.dist-info/METADATA,sha256=1UgIeHlr9DYBjLkfK2b1XAhKEJw4PQXZm4V2WP5w6T0,3143
12
+ dtools_datastructures-0.25.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.10.1
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,12 +0,0 @@
1
- dtools/datastructures/__init__.py,sha256=ST-ArKsBdvwM8l48BLTBGr-cljt6ulNw9N4QIRCC2Ck,1164
2
- dtools/datastructures/nodes.py,sha256=kbk1rcHhicQZssDguRxybakUi450qrfrHBSrf6blM78,5757
3
- dtools/datastructures/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- dtools/datastructures/queues.py,sha256=BkvGl1Opooozz46mgPNPMgXnI57yXcABAP9lwXKk8_M,12173
5
- dtools/datastructures/tuples.py,sha256=uc1kU87rf6L9sOaBVRMKP8ZT1roACIm2pJUBaF_M5-k,6678
6
- dtools/datastructures/splitends/__init__.py,sha256=y9zPBG_ZM_l0uDWZr4Xown72VnR3dvqlhrvTybLP09c,946
7
- dtools/datastructures/splitends/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- dtools/datastructures/splitends/se.py,sha256=M0lsaLVmb_zbt8CvXXGd090FUKzuxPgWtRfLvXtls_A,5644
9
- dtools_datastructures-0.25.1.dist-info/LICENSE,sha256=csqbZRvA3Nyuav1aszWvswE8CZtaKr-hMjjjcKqms7w,10774
10
- dtools_datastructures-0.25.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
11
- dtools_datastructures-0.25.1.dist-info/METADATA,sha256=pG5tlUXUTkoolVEUtSzSgH_PcZvpgU_eYwmPfcoohGg,2764
12
- dtools_datastructures-0.25.1.dist-info/RECORD,,