pythonic-fp-gadgets 4.0.3__py3-none-any.whl → 4.1.0__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.
- pythonic_fp/gadgets/__init__.py +19 -18
- pythonic_fp/gadgets/__init__.pyi +2 -2
- pythonic_fp/gadgets/box.py +90 -45
- pythonic_fp/gadgets/sentinels/__init__.py +14 -3
- pythonic_fp/gadgets/sentinels/flavored.py +49 -32
- pythonic_fp/gadgets/sentinels/novalue.py +119 -60
- pythonic_fp/gadgets/sentinels/novalue.pyi +2 -0
- pythonic_fp/gadgets/wrap.py +124 -58
- {pythonic_fp_gadgets-4.0.3.dist-info → pythonic_fp_gadgets-4.1.0.dist-info}/METADATA +7 -7
- pythonic_fp_gadgets-4.1.0.dist-info/RECORD +17 -0
- pythonic_fp_gadgets-4.0.3.dist-info/RECORD +0 -17
- {pythonic_fp_gadgets-4.0.3.dist-info → pythonic_fp_gadgets-4.1.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_gadgets-4.0.3.dist-info → pythonic_fp_gadgets-4.1.0.dist-info}/licenses/LICENSE +0 -0
pythonic_fp/gadgets/__init__.py
CHANGED
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
16
|
Gadgets
|
|
17
|
-
|
|
17
|
+
=======
|
|
18
18
|
|
|
19
19
|
.. admonition:: Collection of mostly self-contained functions and classes
|
|
20
20
|
|
|
21
21
|
- Functions and classes which could go multiple places or have
|
|
22
22
|
no good place to go.
|
|
23
23
|
- Self-contained with minimal dependencies.
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
- No pythonic_fp dependencies at all.
|
|
25
26
|
|
|
26
27
|
"""
|
|
27
28
|
|
|
@@ -42,22 +43,22 @@ def first_common_ancestor(cls1: type, cls2: type) -> type:
|
|
|
42
43
|
Find the least upper bound in the inheritance graph
|
|
43
44
|
of two classes.
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
:param cls1: A class in the inheritance hierarchy.
|
|
47
|
+
:param cls2: A class in the inheritance hierarchy.
|
|
48
|
+
:returns: First common ancestor based on ``getmro`` order.
|
|
49
|
+
:raises TypeError: Raised when no common ancestor exists, or when
|
|
50
|
+
not caught when raised by ``inspect.getmro``.
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
seen are
|
|
52
|
+
.. warning::
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
This function can fail with a TypeError. Some error messages
|
|
55
|
+
seen are
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
- multiple bases have instance lay-out conflict
|
|
58
|
+
- type 'bool' is not an acceptable base type
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
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``.
|
|
60
|
+
This happens frequently when the function is given
|
|
61
|
+
Python builtin types or in multiple inheritance situations.
|
|
61
62
|
|
|
62
63
|
"""
|
|
63
64
|
if issubclass(cls1, cls2):
|
|
@@ -77,12 +78,12 @@ def iterate_over_arguments[A](*args: A) -> Iterator[A]:
|
|
|
77
78
|
|
|
78
79
|
Function returning an iterator over its arguments.
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
:param args: Objects to iterate over.
|
|
82
|
+
:returns: An iterator of the function's arguments.
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
.. note::
|
|
83
85
|
|
|
84
|
-
|
|
85
|
-
:returns: An iterator of the functions arguments.
|
|
86
|
+
Does not create a Python object to iterate over.
|
|
86
87
|
|
|
87
88
|
"""
|
|
88
89
|
yield from args
|
pythonic_fp/gadgets/__init__.pyi
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from collections.abc import Iterator
|
|
2
2
|
|
|
3
|
-
__all__ = ['
|
|
3
|
+
__all__ = ['first_common_ancestor', 'iterate_over_arguments']
|
|
4
4
|
|
|
5
|
-
def iterate_over_arguments[A](*args: A) -> Iterator[A]: ...
|
|
6
5
|
def first_common_ancestor(cls1: type, cls2: type) -> type: ...
|
|
6
|
+
def iterate_over_arguments[A](*args: A) -> Iterator[A]: ...
|
pythonic_fp/gadgets/box.py
CHANGED
|
@@ -11,28 +11,12 @@
|
|
|
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
|
-
"""
|
|
30
|
-
|
|
31
|
-
__all__ = ['Box']
|
|
32
14
|
|
|
33
15
|
from collections.abc import Callable, Iterator
|
|
34
16
|
from typing import cast, Final, overload
|
|
35
17
|
|
|
18
|
+
__all__ = ['Box']
|
|
19
|
+
|
|
36
20
|
type _Sentinel = object
|
|
37
21
|
_sentinel: Final[_Sentinel] = object()
|
|
38
22
|
|
|
@@ -43,6 +27,16 @@ class Box[T]:
|
|
|
43
27
|
|
|
44
28
|
Container holding at most one item of a given type.
|
|
45
29
|
|
|
30
|
+
.. tip::
|
|
31
|
+
|
|
32
|
+
Objects of the ``Box`` type
|
|
33
|
+
|
|
34
|
+
- Are truthy if not empty.
|
|
35
|
+
- Can be combined with other iterators before being filled.
|
|
36
|
+
- Can be used like a promise.
|
|
37
|
+
- Can be used in Python match statements.
|
|
38
|
+
- Threadsafe
|
|
39
|
+
|
|
46
40
|
"""
|
|
47
41
|
__slots__ = ('_item',)
|
|
48
42
|
__match_args__ = ('_item',)
|
|
@@ -54,24 +48,44 @@ class Box[T]:
|
|
|
54
48
|
|
|
55
49
|
def __init__(self, item: T | _Sentinel = _sentinel) -> None:
|
|
56
50
|
"""
|
|
57
|
-
|
|
51
|
+
.. admonition:: Initializer
|
|
52
|
+
|
|
53
|
+
Initialize ``Box`` with 0 or 1 items.
|
|
54
|
+
|
|
55
|
+
:param item: An optional initial item for the ``Box``.
|
|
58
56
|
|
|
59
57
|
"""
|
|
60
58
|
self._item = item
|
|
61
59
|
|
|
62
60
|
def __bool__(self) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
.. admonition:: Bool
|
|
63
|
+
|
|
64
|
+
Truthy if not empty.
|
|
65
|
+
|
|
66
|
+
"""
|
|
63
67
|
return self._item is not _sentinel
|
|
64
68
|
|
|
65
69
|
def __iter__(self) -> Iterator[T]:
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
"""
|
|
71
|
+
.. admonition:: iter
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
:yields: Boxed item.
|
|
74
|
+
|
|
75
|
+
"""
|
|
70
76
|
if self:
|
|
71
|
-
|
|
72
|
-
return 'Box()'
|
|
77
|
+
yield cast(T, self._item)
|
|
73
78
|
|
|
74
79
|
def __len__(self) -> int:
|
|
80
|
+
"""
|
|
81
|
+
.. admonition:: Length
|
|
82
|
+
|
|
83
|
+
- 1 if ``Box`` contains an item
|
|
84
|
+
- 0 if ``Box`` is empty
|
|
85
|
+
|
|
86
|
+
:returns: The number of items currently in the ``Box``.
|
|
87
|
+
|
|
88
|
+
"""
|
|
75
89
|
return 1 if self else 0
|
|
76
90
|
|
|
77
91
|
def __eq__(self, other: object) -> bool:
|
|
@@ -80,10 +94,10 @@ class Box[T]:
|
|
|
80
94
|
|
|
81
95
|
Efficiently compare ``Box`` to another object.
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
:param other: The object to be compared.
|
|
98
|
+
:returns: ``True`` if ``other`` is another ``Box`` containing
|
|
99
|
+
an object which compares as equal to the item
|
|
100
|
+
contained in the ``Box``, otherwise ``False``.
|
|
87
101
|
|
|
88
102
|
"""
|
|
89
103
|
if not isinstance(other, type(self)):
|
|
@@ -95,6 +109,37 @@ class Box[T]:
|
|
|
95
109
|
return True
|
|
96
110
|
return False
|
|
97
111
|
|
|
112
|
+
def __repr__(self) -> str:
|
|
113
|
+
"""
|
|
114
|
+
.. admonition:: repr string
|
|
115
|
+
|
|
116
|
+
Construct string 'Box()' if empty, otherwise 'Box(item_repr)'
|
|
117
|
+
where ``item_repr = repr(item)`` for the currently contained
|
|
118
|
+
item.
|
|
119
|
+
|
|
120
|
+
:returns: A string to reproduce the current state of the ``Box``.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
if self:
|
|
124
|
+
return 'Box(' + repr(self._item) + ')'
|
|
125
|
+
return 'Box()'
|
|
126
|
+
|
|
127
|
+
def __str__(self) -> str:
|
|
128
|
+
"""
|
|
129
|
+
.. admonition:: user string
|
|
130
|
+
|
|
131
|
+
Construct string 'Box()' if empty, otherwise 'Box(item_str)'
|
|
132
|
+
where ``item_str = str(item)`` for the currently contained
|
|
133
|
+
item.
|
|
134
|
+
|
|
135
|
+
:returns: A user meaningful string to represent the current
|
|
136
|
+
state of the ``Box``.
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
if self:
|
|
140
|
+
return 'Box(' + str(self._item) + ')'
|
|
141
|
+
return 'Box()'
|
|
142
|
+
|
|
98
143
|
@overload
|
|
99
144
|
def get(self) -> T: ...
|
|
100
145
|
@overload
|
|
@@ -107,12 +152,12 @@ class Box[T]:
|
|
|
107
152
|
Return the boxed item, if it exists, otherwise
|
|
108
153
|
an alternate item, if given.
|
|
109
154
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
155
|
+
:param alt: An optional item of type ``T`` to return
|
|
156
|
+
if the ``Box`` is empty.
|
|
157
|
+
:returns: Contents of ``Box`` or an alternate item, if given,
|
|
158
|
+
when the ``Box`` is empty.
|
|
159
|
+
:raises ValueError: When the ``alt`` item is not provided
|
|
160
|
+
but needed.
|
|
116
161
|
|
|
117
162
|
"""
|
|
118
163
|
if self._item is not _sentinel:
|
|
@@ -128,8 +173,8 @@ class Box[T]:
|
|
|
128
173
|
|
|
129
174
|
Pop item from ``Box`` if not empty.
|
|
130
175
|
|
|
131
|
-
|
|
132
|
-
|
|
176
|
+
:returns: The item contained in the ``Box``.
|
|
177
|
+
:raises ValueError: If Box is empty.
|
|
133
178
|
|
|
134
179
|
"""
|
|
135
180
|
if self._item is _sentinel:
|
|
@@ -145,8 +190,8 @@ class Box[T]:
|
|
|
145
190
|
|
|
146
191
|
Push an item into ``Box`` if empty.
|
|
147
192
|
|
|
148
|
-
|
|
149
|
-
|
|
193
|
+
:param item: Item to push into the empty ``Box``.
|
|
194
|
+
:raises ValueError: If ``Box`` is not empty.
|
|
150
195
|
|
|
151
196
|
"""
|
|
152
197
|
if self._item is _sentinel:
|
|
@@ -171,9 +216,9 @@ class Box[T]:
|
|
|
171
216
|
|
|
172
217
|
Exchange an item with what is in the Box.
|
|
173
218
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
219
|
+
:param ``new_item``: New item to exchange for current item.
|
|
220
|
+
:returns: Original contents of the ``Box``.
|
|
221
|
+
:raises ValueError: If Box is empty.
|
|
177
222
|
|
|
178
223
|
"""
|
|
179
224
|
if self._item is _sentinel:
|
|
@@ -190,8 +235,8 @@ class Box[T]:
|
|
|
190
235
|
Map function ``f`` over contents. We need to return a new
|
|
191
236
|
instance since the type of Box can change.
|
|
192
237
|
|
|
193
|
-
|
|
194
|
-
|
|
238
|
+
:param f: Mapping function.
|
|
239
|
+
:returns: New instance.
|
|
195
240
|
|
|
196
241
|
"""
|
|
197
242
|
if self._item is _sentinel:
|
|
@@ -204,8 +249,8 @@ class Box[T]:
|
|
|
204
249
|
|
|
205
250
|
Flatmap ``Box`` with function ``f``.
|
|
206
251
|
|
|
207
|
-
|
|
208
|
-
|
|
252
|
+
:param f: Binding function.
|
|
253
|
+
:returns: New instance.
|
|
209
254
|
|
|
210
255
|
"""
|
|
211
256
|
if self._item is _sentinel:
|
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
"""
|
|
16
|
+
sentinels
|
|
17
|
+
---------
|
|
18
|
+
|
|
19
|
+
.. admonition:: Sentinel values
|
|
20
|
+
|
|
21
|
+
- Singletons
|
|
22
|
+
- Threadsafe
|
|
23
|
+
- Useful for both
|
|
24
|
+
|
|
25
|
+
- referenced objects
|
|
26
|
+
- hidden implementation details
|
|
27
|
+
|
|
28
|
+
"""
|
|
@@ -12,30 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
"""
|
|
16
|
-
.. admonition:: When different flavors of the truth are needed.
|
|
17
|
-
|
|
18
|
-
Sentinel values labeled by different (hashable) flavors.
|
|
19
|
-
Threadsafe.
|
|
20
|
-
|
|
21
|
-
.. tip::
|
|
22
|
-
|
|
23
|
-
Can be compared using ``==`` and ``!=``. A flavored sentinel
|
|
24
|
-
value always equals itself and never equals anything else,
|
|
25
|
-
especially other flavored sentinel values.
|
|
26
|
-
|
|
27
|
-
.. tip::
|
|
28
|
-
|
|
29
|
-
Useful for union types where ``Sentinel[H]`` is one of the
|
|
30
|
-
types making up the union.
|
|
31
|
-
|
|
32
|
-
.. tip::
|
|
33
|
-
|
|
34
|
-
To ensure that reference equality is used, put the known
|
|
35
|
-
sentinel value first in the comparison.
|
|
36
|
-
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
15
|
import threading
|
|
40
16
|
from typing import ClassVar, final, Hashable
|
|
41
17
|
|
|
@@ -44,12 +20,34 @@ __all__ = ['Sentinel']
|
|
|
44
20
|
|
|
45
21
|
@final
|
|
46
22
|
class Sentinel[H: Hashable]:
|
|
23
|
+
"""
|
|
24
|
+
.. admonition:: Sentinel
|
|
25
|
+
|
|
26
|
+
Sentinel values labeled by different (hashable) flavors.
|
|
27
|
+
|
|
28
|
+
.. note::
|
|
29
|
+
|
|
30
|
+
- Useful for union types.
|
|
31
|
+
- A flavored ``Sentinel`` value always equals itself
|
|
32
|
+
and never equals anything else, especially other
|
|
33
|
+
flavored sentinel values.
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
|
|
47
37
|
__slots__ = ('_flavor',)
|
|
48
38
|
|
|
49
39
|
_flavors: 'dict[H, Sentinel[H]]' = {}
|
|
50
40
|
_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
51
41
|
|
|
52
42
|
def __new__(cls, flavor: H) -> 'Sentinel[H]':
|
|
43
|
+
"""
|
|
44
|
+
.. admonition:: new
|
|
45
|
+
|
|
46
|
+
:param flavor: Hashable value determining which
|
|
47
|
+
flavored ``Sentinel`` to return.
|
|
48
|
+
:returns: The ``Sentinel(flavor)`` singleton instance.
|
|
49
|
+
|
|
50
|
+
"""
|
|
53
51
|
if flavor not in cls._flavors:
|
|
54
52
|
with cls._lock:
|
|
55
53
|
if flavor not in cls._flavors:
|
|
@@ -58,25 +56,44 @@ class Sentinel[H: Hashable]:
|
|
|
58
56
|
|
|
59
57
|
def __init__(self, flavor: H) -> None:
|
|
60
58
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
.. admonition:: init
|
|
60
|
+
|
|
61
|
+
:param flavor: Hashable value to initially cache the flavor
|
|
62
|
+
:type flavor: ``H: Hashable``
|
|
64
63
|
|
|
65
64
|
"""
|
|
66
65
|
if not hasattr(self, '_flavor'):
|
|
67
66
|
self._flavor = flavor
|
|
68
67
|
|
|
69
68
|
def __repr__(self) -> str:
|
|
69
|
+
"""
|
|
70
|
+
.. admonition:: repr string
|
|
71
|
+
|
|
72
|
+
Construct string 'Sentinel(flavor)' where the flavor
|
|
73
|
+
is displayed with ``repr()``.
|
|
74
|
+
|
|
75
|
+
:returns: A string to reproduce the flavored sentinel.
|
|
76
|
+
|
|
77
|
+
"""
|
|
70
78
|
return "Sentinel('" + repr(self._flavor) + "')"
|
|
71
79
|
|
|
72
|
-
def
|
|
80
|
+
def __str__(self) -> str:
|
|
73
81
|
"""
|
|
74
|
-
.. admonition::
|
|
82
|
+
.. admonition:: user string
|
|
83
|
+
|
|
84
|
+
Construct string 'Sentinel(flavor)' where the flavor
|
|
85
|
+
is displayed with ``str()``.
|
|
75
86
|
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
:returns: A string meaningful to an end user.
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
return "Sentinel('" + str(self._flavor) + "')"
|
|
91
|
+
|
|
92
|
+
def flavor(self) -> H:
|
|
93
|
+
"""
|
|
94
|
+
.. admonition:: get flavor
|
|
78
95
|
|
|
79
|
-
|
|
96
|
+
:returns: The sentinel's flavor.
|
|
80
97
|
|
|
81
98
|
"""
|
|
82
99
|
return self._flavor
|
|
@@ -12,117 +12,176 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
import threading
|
|
16
|
+
from typing import ClassVar, final
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
not potentially, missing value.
|
|
18
|
+
__all__ = ['NoValue']
|
|
20
19
|
|
|
21
|
-
``NoValue()`` is a singleton object representing a missing value.
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
@final
|
|
22
|
+
class NoValue:
|
|
23
|
+
"""
|
|
24
|
+
.. admonition:: missing value
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
Singleton class representing an actual, not
|
|
27
|
+
potential, missing value.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
While ``None`` and ``()`` are frequently used as sentinel values,
|
|
30
|
+
I prefer to think of them as
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
- ``None`` as returns, or returned, no values.
|
|
33
|
+
- ``()`` as an empty, possibly typed, iterable collection.
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
.. important::
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
y: int | NoValue
|
|
37
|
+
Given variables
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
as equal. If one or both of theses values are missing, then what is
|
|
40
|
-
there to compare?
|
|
39
|
+
.. code:: python
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
x: int | NoValue
|
|
42
|
+
y: int | NoValue
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
+===========+===========+========+========+
|
|
47
|
-
| NoValue() | false | false | false |
|
|
48
|
-
+-----------+-----------+--------+--------+
|
|
49
|
-
| 42 | false | true | false |
|
|
50
|
-
+-----------+-----------+--------+--------+
|
|
51
|
-
| 57 | false | false | true |
|
|
52
|
-
+-----------+-----------+--------+--------+
|
|
44
|
+
Equality between ``x`` and ``y`` means both values exist
|
|
45
|
+
and compare as equal.
|
|
53
46
|
|
|
54
|
-
|
|
47
|
+
.. table:: ``x == y``
|
|
55
48
|
|
|
56
|
-
|
|
49
|
+
+-------------------+-------------------+------------+------------+
|
|
50
|
+
| | | | |
|
|
51
|
+
+===================+===================+============+============+
|
|
52
|
+
| | ``y = NoValue()`` | ``y = 42`` | ``y = 57`` |
|
|
53
|
+
+-------------------+-------------------+------------+------------+
|
|
54
|
+
| ``x = NoValue()`` | ``False`` | ``False`` | ``False`` |
|
|
55
|
+
+-------------------+-------------------+------------+------------+
|
|
56
|
+
| ``x = 42`` | ``False`` | ``True`` | ``False`` |
|
|
57
|
+
+-------------------+-------------------+------------+------------+
|
|
58
|
+
| ``x = 57`` | ``False`` | ``False`` | ``True`` |
|
|
59
|
+
+-------------------+-------------------+------------+------------+
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
| x∖y | NoValue() | 42 | 57 |
|
|
60
|
-
+===========+===========+========+========+
|
|
61
|
-
| NoValue() | false | false | false |
|
|
62
|
-
+-----------+-----------+--------+--------+
|
|
63
|
-
| 42 | false | false | true |
|
|
64
|
-
+-----------+-----------+--------+--------+
|
|
65
|
-
| 57 | false | true | false |
|
|
66
|
-
+-----------+-----------+--------+--------+
|
|
61
|
+
.. table:: ``x != y``
|
|
67
62
|
|
|
68
|
-
|
|
63
|
+
+-------------------+-------------------+------------+------------+
|
|
64
|
+
| | | | |
|
|
65
|
+
+===================+===================+============+============+
|
|
66
|
+
| | ``y = NoValue()`` | ``y = 42`` | ``y = 57`` |
|
|
67
|
+
+-------------------+-------------------+------------+------------+
|
|
68
|
+
| ``x = NoValue()`` | ``False`` | ``False`` | ``False`` |
|
|
69
|
+
+-------------------+-------------------+------------+------------+
|
|
70
|
+
| ``x = 42`` | ``False`` | ``False`` | ``True`` |
|
|
71
|
+
+-------------------+-------------------+------------+------------+
|
|
72
|
+
| ``x = 57`` | ``False`` | ``True`` | ``False`` |
|
|
73
|
+
+-------------------+-------------------+------------+------------+
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
identity the ``NoValue`` singleton, use ``is`` and ``is not``
|
|
72
|
-
instead.
|
|
75
|
+
.. warning::
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
- use ``==`` or ``!=`` only in value comparisons
|
|
78
|
+
- use ``is`` and ``is not`` to identity the ``NoValue()``
|
|
79
|
+
singleton itself
|
|
75
80
|
|
|
76
|
-
|
|
81
|
+
.. tip::
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
Use in a union type when creating "optional" arguments
|
|
84
|
+
to functions and methods.
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
To help ensure the abstraction stays a hidden implementation
|
|
87
|
+
detail and does not leak out into user code,
|
|
82
88
|
|
|
83
|
-
|
|
89
|
+
- Do not export the sentinel value.
|
|
84
90
|
|
|
85
|
-
|
|
86
|
-
- Use ``@overload`` to keep the NoValue type out of documentation and IDEs.
|
|
87
|
-
|
|
88
|
-
"""
|
|
89
|
-
import threading
|
|
90
|
-
from typing import ClassVar, final
|
|
91
|
+
- A new reference can always be generated via ``NoValue()``.
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
- Use ``@overload`` to keep the ``NoValue`` type out of
|
|
94
|
+
documentation and IDEs.
|
|
93
95
|
|
|
96
|
+
"""
|
|
94
97
|
|
|
95
|
-
@final
|
|
96
|
-
class NoValue():
|
|
97
98
|
__slots__ = ()
|
|
98
99
|
|
|
99
100
|
_instance: 'ClassVar[NoValue | None]' = None
|
|
100
101
|
_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
102
|
+
_hash: ClassVar[int] = 0
|
|
101
103
|
|
|
102
104
|
def __new__(cls) -> 'NoValue':
|
|
103
105
|
"""
|
|
104
|
-
|
|
106
|
+
.. admonition:: new
|
|
107
|
+
|
|
108
|
+
:returns: The ``NoValue()`` singleton instance.
|
|
105
109
|
|
|
106
110
|
"""
|
|
107
111
|
if cls._instance is None:
|
|
108
112
|
with cls._lock:
|
|
109
113
|
if cls._instance is None:
|
|
114
|
+
cls._hash = id(cls)
|
|
110
115
|
cls._instance = super().__new__(cls)
|
|
111
116
|
return cls._instance
|
|
112
117
|
|
|
118
|
+
def __hash__(self) -> int:
|
|
119
|
+
"""
|
|
120
|
+
.. admonition:: hash
|
|
121
|
+
|
|
122
|
+
:returns: The singleton's unique integer hash value.
|
|
123
|
+
"""
|
|
124
|
+
return type(self)._hash
|
|
125
|
+
|
|
113
126
|
def __repr__(self) -> str:
|
|
127
|
+
"""
|
|
128
|
+
.. admonition:: repr string
|
|
129
|
+
|
|
130
|
+
:returns: The string 'NoValue()'.
|
|
131
|
+
|
|
132
|
+
"""
|
|
114
133
|
return 'NoValue()'
|
|
115
134
|
|
|
135
|
+
def __bool__(self) -> bool:
|
|
136
|
+
"""
|
|
137
|
+
.. admonition:: bool
|
|
138
|
+
|
|
139
|
+
Always falsy.
|
|
140
|
+
|
|
141
|
+
:returns: False
|
|
142
|
+
|
|
143
|
+
.. tip
|
|
144
|
+
|
|
145
|
+
Can be used to provide a fallback value when used
|
|
146
|
+
with Python shortcut logic.
|
|
147
|
+
|
|
148
|
+
.. code:: python
|
|
149
|
+
|
|
150
|
+
result: str | NoValue = NoValue()
|
|
151
|
+
if predicate(x):
|
|
152
|
+
result = 'some non-empty string'
|
|
153
|
+
value = result or 'fallback string'
|
|
154
|
+
|
|
155
|
+
"""
|
|
156
|
+
return False
|
|
157
|
+
|
|
116
158
|
def __eq__(self, other: object) -> bool:
|
|
117
159
|
"""
|
|
118
|
-
|
|
160
|
+
.. admonition:: Equality comparison
|
|
161
|
+
|
|
162
|
+
:param other: The object to be compared.
|
|
163
|
+
:returns: ``False`` even if compared to itself.
|
|
164
|
+
|
|
165
|
+
.. warning::
|
|
166
|
+
|
|
167
|
+
- non-standard comparison semantics
|
|
168
|
+
- always returns ``False``
|
|
169
|
+
- if one or both values are missing,
|
|
170
|
+
then what is there to compare?
|
|
119
171
|
|
|
120
172
|
"""
|
|
121
173
|
return False
|
|
122
174
|
|
|
123
175
|
def __ne__(self, other: object) -> bool:
|
|
124
176
|
"""
|
|
125
|
-
|
|
177
|
+
.. admonition:: not equal
|
|
178
|
+
|
|
179
|
+
:returns: ``False``
|
|
180
|
+
|
|
181
|
+
.. warning::
|
|
182
|
+
|
|
183
|
+
- non-standard comparison semantics
|
|
184
|
+
- always returns ``False``
|
|
126
185
|
|
|
127
186
|
"""
|
|
128
187
|
return False
|
pythonic_fp/gadgets/wrap.py
CHANGED
|
@@ -11,15 +11,6 @@
|
|
|
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
|
-
"""
|
|
23
14
|
|
|
24
15
|
__all__ = ['Wrap', 'HWrap']
|
|
25
16
|
|
|
@@ -28,9 +19,13 @@ from collections.abc import Callable, Iterator, Hashable
|
|
|
28
19
|
|
|
29
20
|
class Wrap[T]():
|
|
30
21
|
"""
|
|
31
|
-
.. admonition:: Wrap
|
|
22
|
+
.. admonition:: Wrap
|
|
23
|
+
|
|
24
|
+
Immutablely wrap exactly one item.
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+
.. tip::
|
|
27
|
+
|
|
28
|
+
``Wrap`` objects are matchable.
|
|
34
29
|
|
|
35
30
|
"""
|
|
36
31
|
__slots__ = ('_item',)
|
|
@@ -38,43 +33,55 @@ class Wrap[T]():
|
|
|
38
33
|
|
|
39
34
|
def __init__(self, item: T) -> None:
|
|
40
35
|
"""
|
|
41
|
-
|
|
36
|
+
.. admonition:: init
|
|
37
|
+
|
|
38
|
+
Initialize ``Wrap`` with 1 required item.
|
|
39
|
+
|
|
40
|
+
:param item: Item to be wrapped.
|
|
42
41
|
|
|
43
42
|
"""
|
|
44
43
|
self._item = item
|
|
45
44
|
|
|
46
45
|
def __bool__(self) -> bool:
|
|
47
46
|
"""
|
|
48
|
-
.. admonition::
|
|
47
|
+
.. admonition:: bool
|
|
49
48
|
|
|
50
49
|
Truthiness same as wrapped object.
|
|
51
50
|
|
|
52
51
|
"""
|
|
53
52
|
return bool(self._item)
|
|
54
53
|
|
|
54
|
+
def __len__(self) -> int:
|
|
55
|
+
"""
|
|
56
|
+
.. admonition:: len
|
|
57
|
+
|
|
58
|
+
Wrapped items always contain just one item.
|
|
59
|
+
|
|
60
|
+
:returns: 1
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
return 1
|
|
64
|
+
|
|
55
65
|
def __iter__(self) -> Iterator[T]:
|
|
56
66
|
"""
|
|
57
|
-
.. admonition::
|
|
67
|
+
.. admonition:: iter
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
:yields: A reference to the wrapped item.
|
|
60
70
|
|
|
61
71
|
"""
|
|
62
72
|
if self:
|
|
63
73
|
yield self._item
|
|
64
74
|
|
|
65
|
-
def __repr__(self) -> str:
|
|
66
|
-
return 'Wrap(' + repr(self._item) + ')'
|
|
67
|
-
|
|
68
75
|
def __eq__(self, other: object) -> bool:
|
|
69
76
|
"""
|
|
70
|
-
.. admonition::
|
|
77
|
+
.. admonition:: equality comparison
|
|
71
78
|
|
|
72
|
-
|
|
79
|
+
Compare ``Wrap`` to another object.
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
:param other: Object to be compared.
|
|
82
|
+
:returns: ``True`` if ``other`` is of type Wrap and wraps
|
|
83
|
+
an item which compares as equal to the wrapped
|
|
84
|
+
item, otherwise ``False``.
|
|
78
85
|
|
|
79
86
|
"""
|
|
80
87
|
if not isinstance(other, type(self)):
|
|
@@ -84,28 +91,50 @@ class Wrap[T]():
|
|
|
84
91
|
return True
|
|
85
92
|
return self._item == other._item
|
|
86
93
|
|
|
94
|
+
def __repr__(self) -> str:
|
|
95
|
+
"""
|
|
96
|
+
.. admonition:: repr string
|
|
97
|
+
|
|
98
|
+
Construct string 'Wrap(item_str)'
|
|
99
|
+
where ``item_str = repr(item)`` for the contained item.
|
|
100
|
+
|
|
101
|
+
:returns: A string to reproduce of the wrapped item.
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
return 'Wrap(' + repr(self._item) + ')'
|
|
105
|
+
|
|
106
|
+
def __str__(self) -> str:
|
|
107
|
+
"""
|
|
108
|
+
.. admonition:: user string
|
|
109
|
+
|
|
110
|
+
Construct string 'Wrap(item_str)'
|
|
111
|
+
where ``item_str = str(item)`` for the contained item.
|
|
112
|
+
|
|
113
|
+
:returns: A string meaningful to an end user.
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
return 'Wrap(' + str(self._item) + ')'
|
|
117
|
+
|
|
87
118
|
def map[U](self, f: Callable[[T], U]) -> 'Wrap[U]':
|
|
88
119
|
"""
|
|
89
|
-
.. admonition::
|
|
120
|
+
.. admonition:: map
|
|
90
121
|
|
|
91
122
|
Map function ``f`` over contents.
|
|
92
123
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
:param f: Mapping function.
|
|
96
|
-
:returns: New instance.
|
|
124
|
+
:param f: Mapping function.
|
|
125
|
+
:returns: New instance.
|
|
97
126
|
|
|
98
127
|
"""
|
|
99
128
|
return Wrap(f(self._item))
|
|
100
129
|
|
|
101
130
|
def bind[U](self, f: Callable[[T], 'Wrap[U]']) -> 'Wrap[U]':
|
|
102
131
|
"""
|
|
103
|
-
.. admonition::
|
|
132
|
+
.. admonition:: bind
|
|
104
133
|
|
|
105
134
|
Flatmap wrapped object with function ``f``.
|
|
106
135
|
|
|
107
|
-
|
|
108
|
-
|
|
136
|
+
:param f: Binding function.
|
|
137
|
+
:returns: New instance.
|
|
109
138
|
|
|
110
139
|
"""
|
|
111
140
|
return f(self._item)
|
|
@@ -113,23 +142,28 @@ class Wrap[T]():
|
|
|
113
142
|
|
|
114
143
|
class HWrap[T: Hashable](Hashable):
|
|
115
144
|
"""
|
|
116
|
-
.. admonition::
|
|
145
|
+
.. admonition:: HWrap
|
|
117
146
|
|
|
118
|
-
Immutablely wrap exactly one
|
|
147
|
+
Immutablely wrap exactly one hashable item.
|
|
119
148
|
|
|
120
|
-
|
|
149
|
+
.. tip::
|
|
121
150
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
.. tip::
|
|
125
|
-
|
|
126
|
-
``HWrap`` objects are hashable.
|
|
151
|
+
``HWrap`` objects are hashable and matchable.
|
|
127
152
|
|
|
128
153
|
"""
|
|
154
|
+
|
|
129
155
|
__slots__ = ('_item', '_hash')
|
|
130
156
|
__match_args__ = ('_item',)
|
|
131
157
|
|
|
132
158
|
def __init__(self, item: T) -> None:
|
|
159
|
+
"""
|
|
160
|
+
.. admonition:: init
|
|
161
|
+
|
|
162
|
+
Initialize ``HWrap`` with 1 required item.
|
|
163
|
+
|
|
164
|
+
:param item: Item to be wrapped.
|
|
165
|
+
|
|
166
|
+
"""
|
|
133
167
|
self._item, self._hash = item, hash(item)
|
|
134
168
|
|
|
135
169
|
def __hash__(self) -> int:
|
|
@@ -137,36 +171,44 @@ class HWrap[T: Hashable](Hashable):
|
|
|
137
171
|
|
|
138
172
|
def __bool__(self) -> bool:
|
|
139
173
|
"""
|
|
140
|
-
.. admonition::
|
|
174
|
+
.. admonition:: bool
|
|
141
175
|
|
|
142
176
|
Truthiness same as wrapped object.
|
|
143
177
|
|
|
144
178
|
"""
|
|
145
179
|
return bool(self._item)
|
|
146
180
|
|
|
181
|
+
def __len__(self) -> int:
|
|
182
|
+
"""
|
|
183
|
+
.. admonition:: len
|
|
184
|
+
|
|
185
|
+
HWrapped items always contain just one item.
|
|
186
|
+
|
|
187
|
+
:returns: 1
|
|
188
|
+
|
|
189
|
+
"""
|
|
190
|
+
return 1
|
|
191
|
+
|
|
147
192
|
def __iter__(self) -> Iterator[T]:
|
|
148
193
|
"""
|
|
149
|
-
.. admonition::
|
|
194
|
+
.. admonition:: iter
|
|
150
195
|
|
|
151
|
-
|
|
196
|
+
:yields: A reference to the wrapped item.
|
|
152
197
|
|
|
153
198
|
"""
|
|
154
199
|
if self:
|
|
155
200
|
yield self._item
|
|
156
201
|
|
|
157
|
-
def __repr__(self) -> str:
|
|
158
|
-
return 'Wrap(' + repr(self._item) + ')'
|
|
159
|
-
|
|
160
202
|
def __eq__(self, other: object) -> bool:
|
|
161
203
|
"""
|
|
162
|
-
.. admonition::
|
|
204
|
+
.. admonition:: equality comparison
|
|
163
205
|
|
|
164
|
-
|
|
206
|
+
Compare ``HWrap`` to another object.
|
|
165
207
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
208
|
+
:param other: Object to be compared.
|
|
209
|
+
:returns: ``True`` if ``other`` is of type HWrap and wraps
|
|
210
|
+
an item which compares as equal to the wrapped
|
|
211
|
+
item, otherwise ``False``.
|
|
170
212
|
|
|
171
213
|
"""
|
|
172
214
|
if not isinstance(other, type(self)):
|
|
@@ -178,27 +220,51 @@ class HWrap[T: Hashable](Hashable):
|
|
|
178
220
|
return True
|
|
179
221
|
return self._item == other._item
|
|
180
222
|
|
|
223
|
+
def __repr__(self) -> str:
|
|
224
|
+
"""
|
|
225
|
+
.. admonition:: repr string
|
|
226
|
+
|
|
227
|
+
Construct string 'HWrap(item_str)'
|
|
228
|
+
where ``item_str = repr(item)`` for the contained item.
|
|
229
|
+
|
|
230
|
+
:returns: A string to reproduce of the wrapped object.
|
|
231
|
+
|
|
232
|
+
"""
|
|
233
|
+
return 'Wrap(' + repr(self._item) + ')'
|
|
234
|
+
|
|
235
|
+
def __str__(self) -> str:
|
|
236
|
+
"""
|
|
237
|
+
.. admonition:: user string
|
|
238
|
+
|
|
239
|
+
Construct string 'HWrap(item_str)'
|
|
240
|
+
where ``item_str = str(item)`` for the contained item.
|
|
241
|
+
|
|
242
|
+
:returns: A string meaningful to an end user.
|
|
243
|
+
|
|
244
|
+
"""
|
|
245
|
+
return 'Wrap(' + str(self._item) + ')'
|
|
246
|
+
|
|
181
247
|
def map[U](self, f: Callable[[T], U]) -> 'HWrap[U]':
|
|
182
248
|
"""
|
|
183
|
-
.. admonition::
|
|
249
|
+
.. admonition:: map
|
|
184
250
|
|
|
185
251
|
Map function ``f`` over wrapped the wrapped object
|
|
186
252
|
returning a new ``HWrap`` instance.
|
|
187
253
|
|
|
188
|
-
|
|
189
|
-
|
|
254
|
+
:param f: Mapping function.
|
|
255
|
+
:returns: New instance.
|
|
190
256
|
|
|
191
257
|
"""
|
|
192
258
|
return HWrap(f(self._item))
|
|
193
259
|
|
|
194
260
|
def bind[U](self, f: Callable[[T], 'HWrap[U]']) -> 'HWrap[U]':
|
|
195
261
|
"""
|
|
196
|
-
.. admonition::
|
|
262
|
+
.. admonition:: bind
|
|
197
263
|
|
|
198
264
|
Flatmap ``Box`` with function ``f``.
|
|
199
265
|
|
|
200
|
-
|
|
201
|
-
|
|
266
|
+
:param f: Binding function.
|
|
267
|
+
:returns: New instance.
|
|
202
268
|
|
|
203
269
|
"""
|
|
204
270
|
return f(self._item)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-gadgets
|
|
3
|
-
Version: 4.0
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: Gadgets
|
|
5
5
|
Keywords: gadgets
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
@@ -17,8 +17,8 @@ License-File: LICENSE
|
|
|
17
17
|
Requires-Dist: pytest>=8.4.1 ; extra == "test"
|
|
18
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
|
|
21
|
-
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
20
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/projects/gadgets.html
|
|
21
|
+
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/
|
|
22
22
|
Project-URL: Source, https://github.com/grscheller/pythonic-fp-gadgets
|
|
23
23
|
Provides-Extra: test
|
|
24
24
|
|
|
@@ -35,22 +35,22 @@ outside the Python Standard Library.
|
|
|
35
35
|
- Gadgets
|
|
36
36
|
|
|
37
37
|
- single item box
|
|
38
|
-
- wrapped (hashable) references
|
|
38
|
+
- immutable wrapped (hashable) references
|
|
39
39
|
- function returning iterator of its arguments
|
|
40
40
|
- function to find the latest common ancestor of two classes
|
|
41
41
|
- sentinel values
|
|
42
42
|
|
|
43
43
|
Part of the
|
|
44
44
|
`pythonic-fp
|
|
45
|
-
<https://grscheller.github.io/pythonic-fp
|
|
45
|
+
<https://grscheller.github.io/pythonic-fp/>`_
|
|
46
46
|
PyPI projects.
|
|
47
47
|
|
|
48
48
|
Documentation
|
|
49
49
|
-------------
|
|
50
50
|
|
|
51
|
-
Documentation for this project
|
|
51
|
+
Documentation and other links for this project are hosted on
|
|
52
52
|
`GitHub Pages
|
|
53
|
-
<https://grscheller.github.io/pythonic-fp
|
|
53
|
+
<https://grscheller.github.io/pythonic-fp/projects/gadgets.html>`_.
|
|
54
54
|
|
|
55
55
|
Copyright and License
|
|
56
56
|
---------------------
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
pythonic_fp/gadgets/__init__.py,sha256=zwRgxkaQYUbqjR-kX8pQeuPqipCB1bllVOEVBtGXl6I,2807
|
|
2
|
+
pythonic_fp/gadgets/__init__.pyi,sha256=-O921ioE28UPnDm_EL928vl6dDxhrfXHBQenusBo1_o,224
|
|
3
|
+
pythonic_fp/gadgets/box.py,sha256=gcW9mg-QCjc2lLTcOeqYJK0NAkHAbFs1JxhFjVTW1uQ,7115
|
|
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=Bdi-0rg7x37NWd0ciRi_IeDrsmlKQHJOMY9HcCnKt9M,6465
|
|
7
|
+
pythonic_fp/gadgets/wrap.pyi,sha256=TRbBph_517VNCKchwU-pdtPCn73c09gq8EchDFM7Uyo,868
|
|
8
|
+
pythonic_fp/gadgets/sentinels/__init__.py,sha256=Xh63-GTwiqqcBqs5OEYBSiLXuWtq_CVHfUz0mKO_2H0,775
|
|
9
|
+
pythonic_fp/gadgets/sentinels/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
pythonic_fp/gadgets/sentinels/flavored.py,sha256=LPmA-XOadcN5gJgxxo2prSnwRvq8bJ7o0Ae2_Y70Au0,2774
|
|
11
|
+
pythonic_fp/gadgets/sentinels/flavored.pyi,sha256=K3YSyXLyylPII2ahRP0olhzLJruOeR73TFJDC6rCUwk,212
|
|
12
|
+
pythonic_fp/gadgets/sentinels/novalue.py,sha256=gaQNm1TRtphbmWgDV8O0sblH7eU2M-Zymu_B67mwsJ8,6097
|
|
13
|
+
pythonic_fp/gadgets/sentinels/novalue.pyi,sha256=1_iUI6FEwYma8P4XXVCb6CKhSYmfq53S8dLmiwNtJw4,244
|
|
14
|
+
pythonic_fp_gadgets-4.1.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
15
|
+
pythonic_fp_gadgets-4.1.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
16
|
+
pythonic_fp_gadgets-4.1.0.dist-info/METADATA,sha256=eI5gy-KQSFKzOW1E18RF8lzF7EQcEcF-WWWFEeX63Ko,1894
|
|
17
|
+
pythonic_fp_gadgets-4.1.0.dist-info/RECORD,,
|
|
@@ -1,17 +0,0 @@
|
|
|
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,,
|
|
File without changes
|
{pythonic_fp_gadgets-4.0.3.dist-info → pythonic_fp_gadgets-4.1.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|