pythonic-fp.iterables 5.0.0__tar.gz → 5.1.1__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.
@@ -1,6 +1,7 @@
1
1
  # Minimal version - only add to when necessary
2
2
  **/__pycache__/
3
3
  dist/
4
+ **/.dmypy.json
4
5
  **/.mypy_cache/
5
6
  **/.pytest_cache/
6
7
  **/.ruff_cache
@@ -17,6 +17,18 @@ See `Semantic Versioning 2.0.0 <https://semver.org>`_.
17
17
  Releases and Important Milestones
18
18
  ---------------------------------
19
19
 
20
+ 5.1.0 - 2025-08-02
21
+ ~~~~~~~~~~~~~~~~~~
22
+
23
+ - changed singletons -> sentinels
24
+ - Removed "from __future__ import annotations"
25
+ - Added .pyi files
26
+
27
+ 5.0.0 - 2025-08-02
28
+ ~~~~~~~~~~~~~~~~~~
29
+
30
+ General consistency tweaks and fixes across all pythonic-fp projects.
31
+
20
32
  4.0.0 - 2025-07-16
21
33
  ~~~~~~~~~~~~~~~~~~
22
34
 
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonic-fp-iterables
3
- Version: 5.0.0
4
- Summary: Library of functions for iterating iterables.
3
+ Version: 5.1.1
4
+ Summary: Library of functions for iterating iterables
5
5
  Keywords: iterables,iterators
6
6
  Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
7
- Requires-Python: >=3.12
7
+ Requires-Python: >=3.13
8
8
  Description-Content-Type: text/x-rst
9
9
  Classifier: Development Status :: 5 - Production/Stable
10
10
  Classifier: Framework :: Pytest
@@ -14,9 +14,9 @@ Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Typing :: Typed
16
16
  License-File: LICENSE
17
- Requires-Dist: pythonic-fp-fptools>=5.0.0
18
- Requires-Dist: pythonic-fp>=1.1.0
19
- Requires-Dist: pythonic-fp-singletons>=1.0.0
17
+ Requires-Dist: pythonic-fp-fptools>=5.1.1
18
+ Requires-Dist: pythonic-fp-gadgets>=3.0.1
19
+ Requires-Dist: pythonic-fp-sentinels>=2.1.0
20
20
  Requires-Dist: pytest>=8.4.1 ; extra == "test"
21
21
  Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-iterables/blob/main/CHANGELOG.rst
22
22
  Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/iterables/development/build/html/releases.html
@@ -1,12 +1,8 @@
1
- [build-system]
2
- requires = ["flit_core>=3.12,<4"]
3
- build-backend = "flit_core.buildapi"
4
-
5
1
  [project]
6
2
  name = "pythonic-fp-iterables"
7
- version = "5.0.0"
3
+ version = "5.1.1"
8
4
  readme = "README.rst"
9
- requires-python = ">=3.12"
5
+ requires-python = ">=3.13"
10
6
  license = { file = "LICENSE" }
11
7
  authors = [{ name = "Geoffrey R. Scheller", email = "geoffrey@scheller.com" }]
12
8
  keywords = ["iterables", "iterators"]
@@ -20,30 +16,36 @@ classifiers = [
20
16
  "Typing :: Typed",
21
17
  ]
22
18
  dependencies = [
23
- "pythonic-fp-fptools>=5.0.0",
24
- "pythonic-fp>=1.1.0",
25
- "pythonic-fp-singletons>=1.0.0",
19
+ "pythonic-fp-fptools>=5.1.1",
20
+ "pythonic-fp-gadgets>=3.0.1",
21
+ "pythonic-fp-sentinels>=2.1.0",
26
22
  ]
27
23
  dynamic = ["description"]
28
24
 
29
- [project.optional-dependencies]
30
- test = [
31
- "pytest>=8.4.1",
32
- ]
33
-
34
25
  [project.urls]
35
26
  Changelog = "https://github.com/grscheller/pythonic-fp-iterables/blob/main/CHANGELOG.rst"
36
27
  Documentation = "https://grscheller.github.io/pythonic-fp/iterables/development/build/html/releases.html"
37
28
  Homepage = "https://github.com/grscheller/pythonic-fp/blob/main/README.md"
38
29
  Source = "https://github.com/grscheller/pythonic-fp-iterables"
39
30
 
31
+ [project.optional-dependencies]
32
+ test = [
33
+ "pytest>=8.4.1",
34
+ ]
35
+
36
+ [build-system]
37
+ requires = ["flit_core>=3.12,<4"]
38
+ build-backend = "flit_core.buildapi"
39
+
40
40
  [tool.flit.module]
41
41
  name = "pythonic_fp.iterables"
42
42
 
43
43
  [tool.mypy]
44
- enable_incomplete_feature = ["NewGenericSyntax"]
44
+ enable_incomplete_feature = "NewGenericSyntax"
45
+ explicit_package_bases = true
45
46
  implicit_reexport = false
46
47
  local_partial_types = true
48
+ namespace_packages = true
47
49
  warn_redundant_casts = true
48
50
  warn_return_any = true
49
51
  warn_unused_configs = true
@@ -51,21 +53,25 @@ warn_unused_configs = true
51
53
  [tool.pylsp-mypy]
52
54
  enabled = true
53
55
  live-mode = true
56
+ dmypy = false
54
57
  strict = true
55
58
  report_progress = true
56
59
 
57
60
  [tool.pytest.ini_options]
61
+ addopts = "-ra"
58
62
  consider_namespace_packages = true
59
63
  testpaths = ["tests/"]
60
- addopts = "-ra"
61
64
 
62
65
  [tool.ruff]
63
66
  target-version = "py313"
64
- ignore = ["E741"]
65
67
 
66
68
  [tool.ruff.lint.flake8-quotes]
67
69
  docstring-quotes = "double"
68
70
 
71
+ [tool.ruff.lint.per-file-ignores]
72
+ "tests/*" = ["C901"]
73
+ "**/*.py" = ["E741"]
74
+
69
75
  [tool.ruff.format]
70
76
  quote-style = "single"
71
77
  docstring-code-line-length = 72
@@ -12,7 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """Library of functions for iterating iterables.
15
+ """
16
+ Library of functions for iterating iterables
17
+ ============================================
16
18
 
17
19
  +-----------+-------------------------------------------+
18
20
  | Module | Description |
@@ -24,7 +26,8 @@
24
26
  | folding | Reducing and accumulating iterables |
25
27
  +-----------+-------------------------------------------+
26
28
 
27
- Assumptions:
29
+ Assumptions
30
+ -----------
28
31
 
29
32
  - iterables are not necessarily iterators
30
33
  - at all times iterator protocol is assumed to be followed
@@ -12,13 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """Module pythonic_fp.iterables.drop_take"""
16
-
17
- from __future__ import annotations
18
-
19
- __author__ = 'Geoffrey R. Scheller'
20
- __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
21
- __license__ = 'Apache License 2.0'
15
+ """
16
+ Module pythonic_fp.iterables.drop_take
17
+ """
22
18
 
23
19
  from collections.abc import Callable, Iterable, Iterator
24
20
  from pythonic_fp.gadgets.box import Box
@@ -42,7 +38,7 @@ def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
42
38
 
43
39
  :param iterable: iterable whose values are to be dropped
44
40
  :param n: number of values to be dropped
45
- :return: an iterator of the remaining values
41
+ :returns: an iterator of the remaining values
46
42
 
47
43
  """
48
44
  iterator = iter(iterable)
@@ -54,10 +50,7 @@ def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]:
54
50
  return iterator
55
51
 
56
52
 
57
- def drop_while[D](
58
- iterable: Iterable[D],
59
- pred: Callable[[D], bool]
60
- ) -> Iterator[D]:
53
+ def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
61
54
  """Drop initial values from iterable while predicate is true.
62
55
 
63
56
  :param iterable: iterable whose values are to be dropped
@@ -94,10 +87,7 @@ def take[D](iterable: Iterable[D], n: int) -> Iterator[D]:
94
87
  break
95
88
 
96
89
 
97
- def take_while[D](
98
- iterable: Iterable[D],
99
- pred: Callable[[D], bool]
100
- ) -> Iterator[D]:
90
+ def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]:
101
91
  """Yield values from iterable while predicate is true.
102
92
 
103
93
  .. warning::
@@ -120,10 +110,7 @@ def take_while[D](
120
110
  break
121
111
 
122
112
 
123
- def take_split[D](
124
- iterable: Iterable[D],
125
- n: int
126
- ) -> tuple[Iterator[D], Iterator[D]]:
113
+ def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[D]]:
127
114
  """Same as take except also return iterator of remaining values.
128
115
 
129
116
  .. Warning::
@@ -157,6 +144,7 @@ def take_while_split[D](
157
144
  :return: tuple containing an iterator of values taken and an iterator of remaining values
158
145
 
159
146
  """
147
+
160
148
  def _take_while(
161
149
  iterator: Iterator[D], pred: Callable[[D], bool], val: Box[D]
162
150
  ) -> Iterator[D]:
@@ -0,0 +1,33 @@
1
+ # Copyright 2023-2025 Geoffrey R. Scheller
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Callable, Iterable, Iterator
16
+
17
+ __all__ = [
18
+ 'drop',
19
+ 'drop_while',
20
+ 'take',
21
+ 'take_while',
22
+ 'take_split',
23
+ 'take_while_split',
24
+ ]
25
+
26
+ def drop[D](iterable: Iterable[D], n: int) -> Iterator[D]: ...
27
+ def drop_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]: ...
28
+ def take[D](iterable: Iterable[D], n: int) -> Iterator[D]: ...
29
+ def take_while[D](iterable: Iterable[D], pred: Callable[[D], bool]) -> Iterator[D]: ...
30
+ def take_split[D](iterable: Iterable[D], n: int) -> tuple[Iterator[D], Iterator[D]]: ...
31
+ def take_while_split[D](
32
+ iterable: Iterable[D], pred: Callable[[D], bool]
33
+ ) -> tuple[Iterator[D], Iterator[D]]: ...
@@ -14,17 +14,11 @@
14
14
 
15
15
  """Module pythonic_fp.iterables.folding"""
16
16
 
17
- from __future__ import annotations
18
-
19
- __author__ = 'Geoffrey R. Scheller'
20
- __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
21
- __license__ = 'Apache License 2.0'
22
-
23
17
  from collections.abc import Callable, Iterable, Iterator
24
18
  from typing import cast, Never
25
19
  from pythonic_fp.fptools.function import negate, swap
26
20
  from pythonic_fp.fptools.maybe import MayBe
27
- from pythonic_fp.singletons.novalue import NoValue
21
+ from pythonic_fp.sentinels.novalue import NoValue
28
22
  from .drop_take import drop_while, take_while_split
29
23
 
30
24
  __all__ = [
@@ -36,11 +30,10 @@ __all__ = [
36
30
  'sc_reduce_right',
37
31
  ]
38
32
 
33
+
39
34
  def accumulate[D, L](
40
- iterable: Iterable[D],
41
- f: Callable[[L, D], L],
42
- initial: L | NoValue = NoValue()
43
- ) -> Iterator[L]:
35
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
36
+ ) -> Iterator[L]:
44
37
  """Returns an iterator of partial fold values.
45
38
 
46
39
  A pure Python version of standard library's ``itertools.accumulate``
@@ -78,10 +71,7 @@ def accumulate[D, L](
78
71
  yield acc
79
72
 
80
73
 
81
- def reduce_left[D](
82
- iterable: Iterable[D],
83
- f: Callable[[D, D], D]
84
- ) -> D | Never:
74
+ def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never:
85
75
  """Fold an iterable left with a function.
86
76
 
87
77
  .. Warning::
@@ -113,10 +103,8 @@ def reduce_left[D](
113
103
 
114
104
 
115
105
  def fold_left[D, L](
116
- iterable: Iterable[D],
117
- f: Callable[[L, D], L],
118
- initial: L
119
- ) -> L | Never:
106
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L
107
+ ) -> L | Never:
120
108
  """Fold an iterable left with a function and initial value.
121
109
 
122
110
  - not restricted to ``__add__`` for the folding function
@@ -144,10 +132,8 @@ def fold_left[D, L](
144
132
 
145
133
 
146
134
  def maybe_fold_left[D, L](
147
- iterable: Iterable[D],
148
- f: Callable[[L, D], L],
149
- initial: L | NoValue = NoValue()
150
- ) -> MayBe[L] | Never:
135
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
136
+ ) -> MayBe[L] | Never:
151
137
  """Folds an iterable left with an "optional" initial value..
152
138
 
153
139
  - when an initial value is not given then ``L = D``
@@ -188,13 +174,13 @@ def maybe_fold_left[D, L](
188
174
 
189
175
 
190
176
  def sc_reduce_left[D](
191
- iterable: Iterable[D],
192
- f: Callable[[D, D], D],
193
- start: Callable[[D], bool] = (lambda d: True),
194
- stop: Callable[[D], bool] = (lambda d: False),
195
- include_start: bool = True,
196
- include_stop: bool = True,
197
- ) -> tuple[MayBe[D], Iterator[D]]:
177
+ iterable: Iterable[D],
178
+ f: Callable[[D, D], D],
179
+ start: Callable[[D], bool] = (lambda d: True),
180
+ stop: Callable[[D], bool] = (lambda d: False),
181
+ include_start: bool = True,
182
+ include_stop: bool = True,
183
+ ) -> tuple[MayBe[D], Iterator[D]]:
198
184
  """Short circuit version of a left reduce.
199
185
 
200
186
  Useful for infinite iterables.
@@ -240,13 +226,13 @@ def sc_reduce_left[D](
240
226
 
241
227
 
242
228
  def sc_reduce_right[D](
243
- iterable: Iterable[D],
244
- f: Callable[[D, D], D],
245
- start: Callable[[D], bool] = (lambda d: False),
246
- stop: Callable[[D], bool] = (lambda d: False),
247
- include_start: bool = True,
248
- include_stop: bool = True,
249
- ) -> tuple[MayBe[D], Iterator[D]]:
229
+ iterable: Iterable[D],
230
+ f: Callable[[D, D], D],
231
+ start: Callable[[D], bool] = (lambda d: False),
232
+ stop: Callable[[D], bool] = (lambda d: False),
233
+ include_start: bool = True,
234
+ include_stop: bool = True,
235
+ ) -> tuple[MayBe[D], Iterator[D]]:
250
236
  """Short circuit version of a right reduce.
251
237
 
252
238
  Useful for infinite and non-reversible iterables.
@@ -0,0 +1,56 @@
1
+ # Copyright 2023-2025 Geoffrey R. Scheller
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Callable, Iterable, Iterator
16
+ from typing import cast, Never
17
+ from pythonic_fp.fptools.function import negate, swap
18
+ from pythonic_fp.fptools.maybe import MayBe
19
+ from pythonic_fp.sentinels.novalue import NoValue
20
+ from .drop_take import drop_while, take_while_split
21
+
22
+ __all__ = [
23
+ 'accumulate',
24
+ 'reduce_left',
25
+ 'fold_left',
26
+ 'maybe_fold_left',
27
+ 'sc_reduce_left',
28
+ 'sc_reduce_right',
29
+ ]
30
+
31
+ def accumulate[D, L](
32
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
33
+ ) -> Iterator[L]: ...
34
+ def reduce_left[D](iterable: Iterable[D], f: Callable[[D, D], D]) -> D | Never: ...
35
+ def fold_left[D, L](
36
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L
37
+ ) -> L | Never: ...
38
+ def maybe_fold_left[D, L](
39
+ iterable: Iterable[D], f: Callable[[L, D], L], initial: L | NoValue = NoValue()
40
+ ) -> MayBe[L] | Never: ...
41
+ def sc_reduce_left[D](
42
+ iterable: Iterable[D],
43
+ f: Callable[[D, D], D],
44
+ start: Callable[[D], bool] = (lambda d: True),
45
+ stop: Callable[[D], bool] = (lambda d: False),
46
+ include_start: bool = True,
47
+ include_stop: bool = True,
48
+ ) -> tuple[MayBe[D], Iterator[D]]: ...
49
+ def sc_reduce_right[D](
50
+ iterable: Iterable[D],
51
+ f: Callable[[D, D], D],
52
+ start: Callable[[D], bool] = (lambda d: False),
53
+ stop: Callable[[D], bool] = (lambda d: False),
54
+ include_start: bool = True,
55
+ include_stop: bool = True,
56
+ ) -> tuple[MayBe[D], Iterator[D]]: ...
@@ -14,8 +14,6 @@
14
14
 
15
15
  """Module pythonic_fp.iterables.merging"""
16
16
 
17
- from __future__ import annotations
18
-
19
17
  from collections.abc import Iterable, Iterator
20
18
  from enum import auto, Enum
21
19
 
@@ -27,6 +25,7 @@ __all__ = [
27
25
  'blend',
28
26
  ]
29
27
 
28
+
30
29
  class MergeEnum(Enum):
31
30
  """Iterable Blending Enums.
32
31
 
@@ -35,6 +34,7 @@ class MergeEnum(Enum):
35
34
  - **MergeEnum.Exhaust:** Merge until all are exhausted
36
35
 
37
36
  """
37
+
38
38
  Concat = auto()
39
39
  Merge = auto()
40
40
  Exhaust = auto()
@@ -46,7 +46,7 @@ def concat[D](*iterables: Iterable[D]) -> Iterator[D]:
46
46
  .. warning::
47
47
  An infinite iterable will prevent subsequent iterables from
48
48
  yielding any values.
49
-
49
+
50
50
  .. note::
51
51
 
52
52
  Performant to the standard library's ``itertools.chain``.
@@ -64,10 +64,7 @@ def concat[D](*iterables: Iterable[D]) -> Iterator[D]:
64
64
  break
65
65
 
66
66
 
67
- def merge[D](
68
- *iterables: Iterable[D],
69
- yield_partials: bool = False
70
- ) -> Iterator[D]:
67
+ def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]:
71
68
  """Merge together ``iterables`` until one is exhausted.
72
69
 
73
70
  .. note::
@@ -124,10 +121,11 @@ def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]:
124
121
  yield from values
125
122
 
126
123
 
127
- def blend[D](*iterables: Iterable[D],
128
- merge_enum: MergeEnum = MergeEnum.Concat,
129
- yield_partials: bool = False
130
- ) -> Iterator[D]:
124
+ def blend[D](
125
+ *iterables: Iterable[D],
126
+ merge_enum: MergeEnum = MergeEnum.Concat,
127
+ yield_partials: bool = False,
128
+ ) -> Iterator[D]:
131
129
  """Base merge behavior on name only parameters.
132
130
 
133
131
  :param iterables: iterables to blend together
@@ -141,7 +139,7 @@ def blend[D](*iterables: Iterable[D],
141
139
  case MergeEnum.Concat:
142
140
  return concat(*iterables)
143
141
  case MergeEnum.Merge:
144
- return merge(*iterables, yield_partials = yield_partials)
142
+ return merge(*iterables, yield_partials=yield_partials)
145
143
  case MergeEnum.Exhaust:
146
144
  return exhaust(*iterables)
147
145
 
@@ -0,0 +1,38 @@
1
+ # Copyright 2023-2025 Geoffrey R. Scheller
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Iterable, Iterator
16
+ from enum import auto, Enum
17
+
18
+ __all__ = [
19
+ 'MergeEnum',
20
+ 'concat',
21
+ 'merge',
22
+ 'exhaust',
23
+ 'blend',
24
+ ]
25
+
26
+ class MergeEnum(Enum):
27
+ Concat = auto()
28
+ Merge = auto()
29
+ Exhaust = auto()
30
+
31
+ def concat[D](*iterables: Iterable[D]) -> Iterator[D]: ...
32
+ def merge[D](*iterables: Iterable[D], yield_partials: bool = False) -> Iterator[D]: ...
33
+ def exhaust[D](*iterables: Iterable[D]) -> Iterator[D]: ...
34
+ def blend[D](
35
+ *iterables: Iterable[D],
36
+ merge_enum: MergeEnum = MergeEnum.Concat,
37
+ yield_partials: bool = False,
38
+ ) -> Iterator[D]: ...
@@ -143,7 +143,7 @@ class Test_fp_sc_reduce_left:
143
143
  else:
144
144
  assert False
145
145
 
146
- def test_start_stop(self) -> None:
146
+ def test_start_stop(self) -> None: # noqa: C901
147
147
  data = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
148
148
 
149
149
  ge2 = partial(swap(ge_n), 2)