pythonic-fp-gadgets 4.0.1__py3-none-any.whl → 4.0.3__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.
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,47 +13,34 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """
16
- **Module level function names.**
16
+ Gadgets
17
+ -------
17
18
 
18
- ========================== ================================================
19
- Function Description
20
- ========================== ================================================
21
- ``first_common_ancestor`` Find least common base class in a type hierarchy
22
- ``iterate_over_arguments`` Return an iterator over the function's arguments
23
- ========================== ================================================
19
+ .. admonition:: Collection of mostly self-contained functions and classes
20
+
21
+ - Functions and classes which could go multiple places or have
22
+ no good place to go.
23
+ - Self-contained with minimal dependencies.
24
+ - No pythonic_fp dependencies at all.
24
25
 
25
26
  """
26
27
 
27
28
  from collections.abc import Iterator
28
29
  from inspect import getmro
29
30
 
30
- __all__ = ['iterate_over_arguments', 'first_common_ancestor']
31
+ __all__ = ['first_common_ancestor', 'iterate_over_arguments']
31
32
 
32
33
  __author__ = 'Geoffrey R. Scheller'
33
- __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
34
+ __copyright__ = 'Copyright (c) 2023-2026 Geoffrey R. Scheller'
34
35
  __license__ = 'Apache License 2.0'
35
36
 
36
37
 
37
- def iterate_over_arguments[A](*args: A) -> Iterator[A]:
38
- """Function returning an iterator of its arguments.
39
-
40
- .. note::
41
-
42
- Does not create an object to iterate over.
43
-
44
- - well, not in the Python world
45
- - maybe in the C world
46
-
47
- :param args: Objects to iterate over.
48
- :returns: An iterator of the arguments.
49
-
38
+ def first_common_ancestor(cls1: type, cls2: type) -> type:
50
39
  """
51
- yield from args
52
-
40
+ .. admonition:: Least upper bound
53
41
 
54
- def first_common_ancestor(cls1: type, cls2: type) -> type:
55
- """Find the least upper bound in the inheritance graph
56
- of two classes.
42
+ Find the least upper bound in the inheritance graph
43
+ of two classes.
57
44
 
58
45
  .. warning::
59
46
 
@@ -68,8 +55,9 @@ def first_common_ancestor(cls1: type, cls2: type) -> type:
68
55
 
69
56
  :param cls1: A class in the inheritance hierarchy.
70
57
  :param cls2: A class in the inheritance hierarchy.
71
- :returns: First common ancestor based on getmro order.
72
- :raises TypeError: Raised by ``inspect.getmro``.
58
+ :returns: First common ancestor based on ``getmro`` order.
59
+ :raises TypeError: Raised when no common ancestor exists, or when
60
+ not caught when raised by ``inspect.getmro``.
73
61
 
74
62
  """
75
63
  if issubclass(cls1, cls2):
@@ -81,3 +69,20 @@ def first_common_ancestor(cls1: type, cls2: type) -> type:
81
69
  if issubclass(cls1, common_ancestor) and issubclass(cls2, common_ancestor):
82
70
  return common_ancestor
83
71
  raise TypeError("latest_common_ancestor: no common ancestor found!!!")
72
+
73
+
74
+ def iterate_over_arguments[A](*args: A) -> Iterator[A]:
75
+ """
76
+ .. admonition:: Iterate over arguments.
77
+
78
+ Function returning an iterator over its arguments.
79
+
80
+ .. note::
81
+
82
+ Does not create a Python object to iterate over.
83
+
84
+ :param args: Objects to iterate over.
85
+ :returns: An iterator of the functions arguments.
86
+
87
+ """
88
+ yield from args
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -11,6 +11,22 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ """
15
+ .. admonition:: Module box
16
+
17
+ Containers holding at most one item of a given type.
18
+
19
+ .. tip::
20
+
21
+ Objects of the ``Box`` type
22
+
23
+ - Are truthy if not empty.
24
+ - Can be combined with other iterators before being filled.
25
+ - Can be used like a promise.
26
+ - Threadsafe
27
+ - Can be used in Python match statements.
28
+
29
+ """
14
30
 
15
31
  __all__ = ['Box']
16
32
 
@@ -22,19 +38,10 @@ _sentinel: Final[_Sentinel] = object()
22
38
 
23
39
 
24
40
  class Box[T]:
25
- """Container holding at most one item of a given type.
26
-
27
- .. note::
28
-
29
- - ``Box(item: T)``: contains at one item of type ``T``
30
- - ``Box[T]()``: creates empty container
31
-
32
- Where type ``T`` is some definite type, which
33
- could be ``None`` or even ``Never``.
34
-
35
- .. tip ::
41
+ """
42
+ .. admonition:: Box
36
43
 
37
- ``Box`` objects can be used in Python match statements.
44
+ Container holding at most one item of a given type.
38
45
 
39
46
  """
40
47
  __slots__ = ('_item',)
@@ -47,7 +54,8 @@ class Box[T]:
47
54
 
48
55
  def __init__(self, item: T | _Sentinel = _sentinel) -> None:
49
56
  """
50
- :param item: An "optional" initial contained ``item`` for the ``Box``.
57
+ :param item: An optional initial ``item`` for the ``Box``.
58
+
51
59
  """
52
60
  self._item = item
53
61
 
@@ -67,6 +75,17 @@ class Box[T]:
67
75
  return 1 if self else 0
68
76
 
69
77
  def __eq__(self, other: object) -> bool:
78
+ """
79
+ .. admonition:: Equality comparison
80
+
81
+ Efficiently compare ``Box`` to another object.
82
+
83
+ :param other: The object to be compared with,
84
+ :returns: ``True`` if ``other`` is of type Box and contains
85
+ an object which compares as equal to the object
86
+ contained in the ``Box``, otherwise ``False``.
87
+
88
+ """
70
89
  if not isinstance(other, type(self)):
71
90
  return False
72
91
 
@@ -82,11 +101,18 @@ class Box[T]:
82
101
  def get(self, alt: T) -> T: ...
83
102
 
84
103
  def get(self, alt: T | _Sentinel = _sentinel) -> T:
85
- """Return the contained item if it exists, otherwise an alternate item.
104
+ """
105
+ .. admonition:: Get
86
106
 
87
- :param alt: an "optional" item of type ``T`` to return if ``Box`` is empty
88
- :returns: contents of ``Box``, or an alternate item if given and ``Box`` empty
89
- :raises ValueError: when an ``alt`` item is not provided but needed
107
+ Return the boxed item, if it exists, otherwise
108
+ an alternate item, if given.
109
+
110
+ :param alt: An optional item of type ``T`` to return
111
+ if the ``Box`` is empty.
112
+ :returns: Contents of ``Box`` or an alternate item, if given,
113
+ when the ``Box`` is empty.
114
+ :raises ValueError: When the ``alt`` item is not provided
115
+ but needed.
90
116
 
91
117
  """
92
118
  if self._item is not _sentinel:
@@ -97,7 +123,10 @@ class Box[T]:
97
123
  return cast(T, alt)
98
124
 
99
125
  def pop(self) -> T:
100
- """Pop the contained item if ``Box`` is not empty.
126
+ """
127
+ .. admonition:: Pop
128
+
129
+ Pop item from ``Box`` if not empty.
101
130
 
102
131
  :returns: The item contained in the ``Box``.
103
132
  :raises ValueError: If Box is empty.
@@ -111,7 +140,10 @@ class Box[T]:
111
140
  return popped
112
141
 
113
142
  def push(self, item: T) -> None:
114
- """Push an item into an empty ``Box``.
143
+ """
144
+ .. admonition:: Push
145
+
146
+ Push an item into ``Box`` if empty.
115
147
 
116
148
  :param item: Item to push into the empty ``Box``.
117
149
  :raises ValueError: If ``Box`` is not empty.
@@ -125,15 +157,24 @@ class Box[T]:
125
157
  return None
126
158
 
127
159
  def put(self, item: T) -> None:
128
- """Put an item in the Box. Discard any previous contents."""
160
+ """
161
+ .. admonition:: Put
162
+
163
+ Put an item in the Box. Discard any previous contents.
164
+
165
+ """
129
166
  self._item = item
130
167
 
131
168
  def exchange(self, new_item: T) -> T:
132
- """Exchange an item with what is in the Box.
169
+ """
170
+ .. admonition:: Exchange
171
+
172
+ Exchange an item with what is in the Box.
133
173
 
134
174
  :param ``new_item``: New item to exchange for current item.
135
175
  :returns: Original contents of the ``Box``.
136
176
  :raises ValueError: If Box is empty.
177
+
137
178
  """
138
179
  if self._item is _sentinel:
139
180
  msg = 'Box: Trying to exchange items from an empty Box'
@@ -143,11 +184,14 @@ class Box[T]:
143
184
  return popped
144
185
 
145
186
  def map[U](self, f: Callable[[T], U]) -> 'Box[U]':
146
- """Map function ``f`` over contents. We need to return a new
147
- instance since the type of Box can change.
187
+ """
188
+ .. admonition:: Map
189
+
190
+ Map function ``f`` over contents. We need to return a new
191
+ instance since the type of Box can change.
148
192
 
149
- :param f: mapping function
150
- :returns: a new instance
193
+ :param f: Mapping function.
194
+ :returns: New instance.
151
195
 
152
196
  """
153
197
  if self._item is _sentinel:
@@ -155,10 +199,13 @@ class Box[T]:
155
199
  return Box(f(cast(T, self._item)))
156
200
 
157
201
  def bind[U](self, f: Callable[[T], 'Box[U]']) -> 'Box[U]':
158
- """Flatmap ``Box`` with function ``f``.
202
+ """
203
+ .. admonition:: Bind
204
+
205
+ Flatmap ``Box`` with function ``f``.
159
206
 
160
- :param f: binding function
161
- :returns: a new instance
207
+ :param f: Binding function.
208
+ :returns: New instance.
162
209
 
163
210
  """
164
211
  if self._item is _sentinel:
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  __author__ = 'Geoffrey R. Scheller'
16
- __copyright__ = 'Copyright (c) 2023-2025 Geoffrey R. Scheller'
16
+ __copyright__ = 'Copyright (c) 2023-2026 Geoffrey R. Scheller'
17
17
  __license__ = 'Apache License 2.0'
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,24 +13,27 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """
16
- **Sentinel values labeled by different (hashable) flavors.**
16
+ .. admonition:: When different flavors of the truth are needed.
17
17
 
18
- .. note::
18
+ Sentinel values labeled by different (hashable) flavors.
19
+ Threadsafe.
20
+
21
+ .. tip::
19
22
 
20
23
  Can be compared using ``==`` and ``!=``. A flavored sentinel
21
24
  value always equals itself and never equals anything else,
22
25
  especially other flavored sentinel values.
23
26
 
27
+ .. tip::
28
+
24
29
  Useful for union types where ``Sentinel[H]`` is one of the
25
30
  types making up the union.
26
31
 
32
+ .. tip::
33
+
27
34
  To ensure that reference equality is used, put the known
28
35
  sentinel value first in the comparison.
29
36
 
30
- .. note::
31
-
32
- Threadsafe.
33
-
34
37
  """
35
38
 
36
39
  import threading
@@ -58,6 +61,7 @@ class Sentinel[H: Hashable]:
58
61
  :param flavor: Some Hashable value of generic type ``H``.
59
62
  :returns: The ``Sentinel`` singleton instance with flavor ``flavor``.
60
63
  :rtype: ``Sentinel[H]`` where ``H`` is a subtype of Hashable.
64
+
61
65
  """
62
66
  if not hasattr(self, '_flavor'):
63
67
  self._flavor = flavor
@@ -67,6 +71,12 @@ class Sentinel[H: Hashable]:
67
71
 
68
72
  def flavor(self) -> H:
69
73
  """
70
- :returns: The sentinel's flavor. A ``Hashable`` value of type ``H``.
74
+ .. admonition:: Get flavor
75
+
76
+ Get the sentinel's flavor, a hashable
77
+ value of type ``H``.
78
+
79
+ :returns: The sentinel's flavor.
80
+
71
81
  """
72
82
  return self._flavor
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,9 +13,10 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """
16
- **Singleton class representing an actually, not potentially, missing value.**
16
+ .. admonition:: Missing value.
17
17
 
18
- .. note:
18
+ Singleton class representing an actually,
19
+ not potentially, missing value.
19
20
 
20
21
  ``NoValue()`` is a singleton object representing a missing value.
21
22
 
@@ -52,7 +53,7 @@
52
53
 
53
54
  Similarly for not equals.
54
55
 
55
- .. table:: ``x != y``
56
+ .. table:: ``x != y``:wq
56
57
 
57
58
  +-----------+-----------+--------+--------+
58
59
  | x∖y | NoValue() | 42 | 57 |
@@ -101,6 +102,7 @@ class NoValue():
101
102
  def __new__(cls) -> 'NoValue':
102
103
  """
103
104
  :returns: The ``NoValue`` singleton instance.
105
+
104
106
  """
105
107
  if cls._instance is None:
106
108
  with cls._lock:
@@ -113,12 +115,14 @@ class NoValue():
113
115
 
114
116
  def __eq__(self, other: object) -> bool:
115
117
  """
116
- :returns: False
118
+ :returns: ``False``
119
+
117
120
  """
118
121
  return False
119
122
 
120
123
  def __ne__(self, other: object) -> bool:
121
124
  """
122
- :returns: False
125
+ :returns: ``False``
126
+
123
127
  """
124
128
  return False
@@ -1,4 +1,4 @@
1
- # Copyright 2023-2025 Geoffrey R. Scheller
1
+ # Copyright 2023-2026 Geoffrey R. Scheller
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -11,6 +11,15 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+ """
15
+ .. admonition:: Module wrap
16
+
17
+ Wrap objects in ways to make them "immutable."
18
+
19
+ - Class ``Wrap``: wrap an object
20
+ - Class ``HWrap``: wrap a hashable object
21
+
22
+ """
14
23
 
15
24
  __all__ = ['Wrap', 'HWrap']
16
25
 
@@ -18,23 +27,38 @@ from collections.abc import Callable, Iterator, Hashable
18
27
 
19
28
 
20
29
  class Wrap[T]():
21
- """Immutablely wrap exactly one value of a given type.
22
-
23
- .. tip::
30
+ """
31
+ .. admonition:: Wrap object
24
32
 
25
- ``Wrap`` objects can be used in Python match statements.
33
+ Immutablely wrap exactly one value of a given type.
26
34
 
27
35
  """
28
36
  __slots__ = ('_item',)
29
37
  __match_args__ = ('_item',)
30
38
 
31
39
  def __init__(self, item: T) -> None:
40
+ """
41
+ :param item: Item to be wrapped.
42
+
43
+ """
32
44
  self._item = item
33
45
 
34
46
  def __bool__(self) -> bool:
47
+ """
48
+ .. admonition:: Bool
49
+
50
+ Truthiness same as wrapped object.
51
+
52
+ """
35
53
  return bool(self._item)
36
54
 
37
55
  def __iter__(self) -> Iterator[T]:
56
+ """
57
+ .. admonition:: Iter
58
+
59
+ Iterable, iterates wrapped item.
60
+
61
+ """
38
62
  if self:
39
63
  yield self._item
40
64
 
@@ -42,6 +66,17 @@ class Wrap[T]():
42
66
  return 'Wrap(' + repr(self._item) + ')'
43
67
 
44
68
  def __eq__(self, other: object) -> bool:
69
+ """
70
+ .. admonition:: Equality comparison
71
+
72
+ Efficiently compare ``Wrap`` to another object.
73
+
74
+ :param other: The object to be compared with,
75
+ :returns: ``True`` if ``other`` is of type Wrap and wraps
76
+ an object which compares as equal to the wrapped
77
+ object, otherwise ``False``.
78
+
79
+ """
45
80
  if not isinstance(other, type(self)):
46
81
  return False
47
82
 
@@ -50,30 +85,45 @@ class Wrap[T]():
50
85
  return self._item == other._item
51
86
 
52
87
  def map[U](self, f: Callable[[T], U]) -> 'Wrap[U]':
53
- """Map function ``f`` over contents.
88
+ """
89
+ .. admonition:: Map
90
+
91
+ Map function ``f`` over contents.
92
+
93
+ Map function ``f`` over contents.
54
94
 
55
95
  :param f: Mapping function.
56
- :returns: A new instance.
96
+ :returns: New instance.
57
97
 
58
98
  """
59
99
  return Wrap(f(self._item))
60
100
 
61
101
  def bind[U](self, f: Callable[[T], 'Wrap[U]']) -> 'Wrap[U]':
62
- """Flatmap the ``Wrap`` with function ``f``.
102
+ """
103
+ .. admonition:: Bind
104
+
105
+ Flatmap wrapped object with function ``f``.
63
106
 
64
107
  :param f: Binding function.
65
- :returns: A new instance.
108
+ :returns: New instance.
66
109
 
67
110
  """
68
111
  return f(self._item)
69
112
 
70
113
 
71
114
  class HWrap[T: Hashable](Hashable):
72
- """Immutablely wrap exactly one hashable value of a given type.
115
+ """
116
+ .. admonition:: Wrap hashable object
117
+
118
+ Immutablely wrap exactly one value of a given hashable type.
119
+
120
+ .. tip::
121
+
122
+ ``HWrap`` objects can be used in Python match statements.
73
123
 
74
124
  .. tip::
75
125
 
76
- ``Wrap`` objects can be used in Python match statements.
126
+ ``HWrap`` objects are hashable.
77
127
 
78
128
  """
79
129
  __slots__ = ('_item', '_hash')
@@ -86,9 +136,21 @@ class HWrap[T: Hashable](Hashable):
86
136
  return self._hash
87
137
 
88
138
  def __bool__(self) -> bool:
139
+ """
140
+ .. admonition:: Bool
141
+
142
+ Truthiness same as wrapped object.
143
+
144
+ """
89
145
  return bool(self._item)
90
146
 
91
147
  def __iter__(self) -> Iterator[T]:
148
+ """
149
+ .. admonition:: Iter
150
+
151
+ Iterable, iterates wrapped item.
152
+
153
+ """
92
154
  if self:
93
155
  yield self._item
94
156
 
@@ -96,6 +158,17 @@ class HWrap[T: Hashable](Hashable):
96
158
  return 'Wrap(' + repr(self._item) + ')'
97
159
 
98
160
  def __eq__(self, other: object) -> bool:
161
+ """
162
+ .. admonition:: Equality comparison
163
+
164
+ Efficiently compare to another object.
165
+
166
+ :param other: Object to be compared
167
+ :returns: ``True`` if ``other`` is of type HWrap and wraps
168
+ an object which compares as equal to the wrapped
169
+ object, otherwise ``False``.
170
+
171
+ """
99
172
  if not isinstance(other, type(self)):
100
173
  return False
101
174
 
@@ -106,19 +179,26 @@ class HWrap[T: Hashable](Hashable):
106
179
  return self._item == other._item
107
180
 
108
181
  def map[U](self, f: Callable[[T], U]) -> 'HWrap[U]':
109
- """Map function ``f`` over contents.
182
+ """
183
+ .. admonition:: Map
184
+
185
+ Map function ``f`` over wrapped the wrapped object
186
+ returning a new ``HWrap`` instance.
110
187
 
111
188
  :param f: Mapping function.
112
- :returns: A new instance.
189
+ :returns: New instance.
113
190
 
114
191
  """
115
192
  return HWrap(f(self._item))
116
193
 
117
194
  def bind[U](self, f: Callable[[T], 'HWrap[U]']) -> 'HWrap[U]':
118
- """Flatmap the ``Wrap`` with function ``f``.
195
+ """
196
+ .. admonition:: Bind
197
+
198
+ Flatmap ``Box`` with function ``f``.
119
199
 
120
200
  :param f: Binding function.
121
- :returns: A new instance.
201
+ :returns: New instance.
122
202
 
123
203
  """
124
204
  return f(self._item)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonic-fp-gadgets
3
- Version: 4.0.1
4
- Summary: **Module level function names.**
3
+ Version: 4.0.3
4
+ Summary: Gadgets
5
5
  Keywords: gadgets
6
6
  Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
7
7
  Requires-Python: >=3.13
@@ -11,14 +11,14 @@ 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
- Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
15
  Classifier: Typing :: Typed
16
16
  License-File: LICENSE
17
17
  Requires-Dist: pytest>=8.4.1 ; extra == "test"
18
- Requires-Dist: pythonic-fp-circulararray>=6.0.0 ; extra == "test"
18
+ Requires-Dist: pythonic-fp-circulararray>=6.0.4 ; extra == "test"
19
19
  Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-gadgets/blob/main/CHANGELOG.rst
20
- Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/gadgets/development/build/html/
21
- Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/homepage/build/html/
20
+ Project-URL: Documentation, https://grscheller.github.io/pythonic-fp-gadgets/
21
+ Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/homepage/html/
22
22
  Project-URL: Source, https://github.com/grscheller/pythonic-fp-gadgets
23
23
  Provides-Extra: test
24
24
 
@@ -27,7 +27,7 @@ Pythonic FP - Gadgets
27
27
 
28
28
  PyPI project
29
29
  `pythonic-fp-gadgets
30
- <https://pypi.org/project/pythonic-fp>`_.
30
+ <https://pypi.org/project/pythonic-fp-gadgets>`_.
31
31
 
32
32
  Library of simple, but useful, classes and functions with no dependencies
33
33
  outside the Python Standard Library.
@@ -35,12 +35,14 @@ outside the Python Standard Library.
35
35
  - Gadgets
36
36
 
37
37
  - single item box
38
+ - wrapped (hashable) references
38
39
  - function returning iterator of its arguments
39
- - find the latest common ancestor of two classes
40
+ - function to find the latest common ancestor of two classes
41
+ - sentinel values
40
42
 
41
43
  Part of the
42
44
  `pythonic-fp
43
- <https://grscheller.github.io/pythonic-fp>`_
45
+ <https://grscheller.github.io/pythonic-fp/homepage/html/>`_
44
46
  PyPI projects.
45
47
 
46
48
  Documentation
@@ -48,11 +50,11 @@ Documentation
48
50
 
49
51
  Documentation for this project is hosted on
50
52
  `GitHub Pages
51
- <https://grscheller.github.io/pythonic-fp/gadgets>`_.
53
+ <https://grscheller.github.io/pythonic-fp-gadgets>`_.
52
54
 
53
55
  Copyright and License
54
56
  ---------------------
55
57
 
56
- Copyright (c) 2025 Geoffrey R. Scheller. Licensed under the Apache
58
+ Copyright (c) 2025-2026 Geoffrey R. Scheller. Licensed under the Apache
57
59
  License, Version 2.0. See the LICENSE file for details.
58
60
 
@@ -0,0 +1,17 @@
1
+ pythonic_fp/gadgets/__init__.py,sha256=29fNYn8LLhCUfvZ_vcofSoGhs9_Hw95cPF3sd0G1z9M,2739
2
+ pythonic_fp/gadgets/__init__.pyi,sha256=cAf10WX2ZHMs-Tf93mImmDdZw7lNEmwjorkiVF04s_E,224
3
+ pythonic_fp/gadgets/box.py,sha256=2PL0wkimRwgsL15aTkB2QTo4B40IY6G0lCo0Esa0CTU,5860
4
+ pythonic_fp/gadgets/box.pyi,sha256=UkJBY8Xiv4oe70Q3bhJL1jGHwYmFWwkTIdxvf2zR3v4,837
5
+ pythonic_fp/gadgets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ pythonic_fp/gadgets/wrap.py,sha256=EVhp115DcokaBa-0xN3CN3Qlr4vkHvEZQIPuMYYxHas,4950
7
+ pythonic_fp/gadgets/wrap.pyi,sha256=TRbBph_517VNCKchwU-pdtPCn73c09gq8EchDFM7Uyo,868
8
+ pythonic_fp/gadgets/sentinels/__init__.py,sha256=WsGXds578j1y7FsLEGer59P1c8EItUBTp60cuA0T56E,724
9
+ pythonic_fp/gadgets/sentinels/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ pythonic_fp/gadgets/sentinels/flavored.py,sha256=W33020r3U8jxIDdJDaa-xE7o4cI1NY0bLZi8puIUBqA,2353
11
+ pythonic_fp/gadgets/sentinels/flavored.pyi,sha256=K3YSyXLyylPII2ahRP0olhzLJruOeR73TFJDC6rCUwk,212
12
+ pythonic_fp/gadgets/sentinels/novalue.py,sha256=9wya9NBDQzfr2rxwrCd7uh74Trm4iVsK53UAUZo5Iyk,3613
13
+ pythonic_fp/gadgets/sentinels/novalue.pyi,sha256=zhZdePpWoQ3ZXOq7xQWGR0A4W_XzasdBQKcoywXZEZI,173
14
+ pythonic_fp_gadgets-4.0.3.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
15
+ pythonic_fp_gadgets-4.0.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
16
+ pythonic_fp_gadgets-4.0.3.dist-info/METADATA,sha256=z6LP-dUh7AgGHq-TTbn3qS0QyIDc-5GNohGM23QXMzU,1868
17
+ pythonic_fp_gadgets-4.0.3.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- pythonic_fp/gadgets/__init__.py,sha256=PXZJRwsDkGrI2_B3nbwU4n3tzeSGONquV-_inWroxsg,2811
2
- pythonic_fp/gadgets/__init__.pyi,sha256=cAf10WX2ZHMs-Tf93mImmDdZw7lNEmwjorkiVF04s_E,224
3
- pythonic_fp/gadgets/box.py,sha256=aSR9V_PuAhjqQ8Vs7fj80zgirb8BWzkUFr1pWvSbBDc,4994
4
- pythonic_fp/gadgets/box.pyi,sha256=UkJBY8Xiv4oe70Q3bhJL1jGHwYmFWwkTIdxvf2zR3v4,837
5
- pythonic_fp/gadgets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- pythonic_fp/gadgets/wrap.py,sha256=5FonuzJ6E3SeUoneUoUsjM6x9COZUnyzWQHPKN45cRo,3259
7
- pythonic_fp/gadgets/wrap.pyi,sha256=TRbBph_517VNCKchwU-pdtPCn73c09gq8EchDFM7Uyo,868
8
- pythonic_fp/gadgets/sentinels/__init__.py,sha256=81T-HGQ9BgXj57PO_pduo8MpSQpRgZwT8LIXwODhHkI,724
9
- pythonic_fp/gadgets/sentinels/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- pythonic_fp/gadgets/sentinels/flavored.py,sha256=RMqDRmN_ImbRlf_Yaqj7jwnOc6YBeEdAfi8xGCyw1xs,2195
11
- pythonic_fp/gadgets/sentinels/flavored.pyi,sha256=K3YSyXLyylPII2ahRP0olhzLJruOeR73TFJDC6rCUwk,212
12
- pythonic_fp/gadgets/sentinels/novalue.py,sha256=RA5foyWFgSHCpaJPJ0N0Td7cldLEbwX_bzkTgs_ZW-o,3573
13
- pythonic_fp/gadgets/sentinels/novalue.pyi,sha256=zhZdePpWoQ3ZXOq7xQWGR0A4W_XzasdBQKcoywXZEZI,173
14
- pythonic_fp_gadgets-4.0.1.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
15
- pythonic_fp_gadgets-4.0.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
16
- pythonic_fp_gadgets-4.0.1.dist-info/METADATA,sha256=lpGqtuqWWxiuh__avGe4ZUyXnRTf532iLL0UFLeaLPM,1828
17
- pythonic_fp_gadgets-4.0.1.dist-info/RECORD,,