pythonic-fp-gadgets 4.3.1__py3-none-any.whl → 4.5.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 +23 -18
- pythonic_fp/gadgets/box.py +4 -7
- pythonic_fp/gadgets/wrap.py +10 -11
- {pythonic_fp_gadgets-4.3.1.dist-info → pythonic_fp_gadgets-4.5.0.dist-info}/METADATA +11 -10
- pythonic_fp_gadgets-4.5.0.dist-info/RECORD +14 -0
- pythonic_fp/gadgets/__init__.pyi +0 -6
- pythonic_fp/gadgets/box.pyi +0 -27
- pythonic_fp/gadgets/wrap.pyi +0 -23
- pythonic_fp_gadgets-4.3.1.dist-info/RECORD +0 -17
- {pythonic_fp_gadgets-4.3.1.dist-info → pythonic_fp_gadgets-4.5.0.dist-info}/WHEEL +0 -0
- {pythonic_fp_gadgets-4.3.1.dist-info → pythonic_fp_gadgets-4.5.0.dist-info}/licenses/LICENSE +0 -0
pythonic_fp/gadgets/__init__.py
CHANGED
|
@@ -27,7 +27,6 @@ Gadgets
|
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
from collections.abc import Iterator
|
|
30
|
-
from inspect import getmro
|
|
31
30
|
|
|
32
31
|
__all__ = ['first_common_ancestor', 'iterate_over_arguments']
|
|
33
32
|
|
|
@@ -38,27 +37,33 @@ __license__ = 'Apache License 2.0'
|
|
|
38
37
|
|
|
39
38
|
def first_common_ancestor(cls1: type, cls2: type) -> type:
|
|
40
39
|
"""
|
|
41
|
-
.. admonition::
|
|
40
|
+
.. admonition:: First common ancestor
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
of two classes.
|
|
42
|
+
Best effort to find the least upper bound in the inheritance
|
|
43
|
+
graph of two classes.
|
|
45
44
|
|
|
46
45
|
:param cls1: A class in the inheritance hierarchy.
|
|
47
46
|
:param cls2: A class in the inheritance hierarchy.
|
|
48
|
-
:returns: First common ancestor
|
|
49
|
-
:raises TypeError:
|
|
50
|
-
|
|
47
|
+
:returns: First common ancestor in ``cls1.__mro__`` order.
|
|
48
|
+
:raises TypeError: Defensively raised when no common ancestor
|
|
49
|
+
is found.
|
|
51
50
|
|
|
52
|
-
..
|
|
51
|
+
.. note::
|
|
52
|
+
|
|
53
|
+
The function is not symmetric in its arguments. In genuine
|
|
54
|
+
multiple inheritance graphs, swapping ``cls1`` and ``cls2``
|
|
55
|
+
can yield a different ancestor. Also, a virtual ancestor
|
|
56
|
+
registered with an ABC may be a tighter bound than anything
|
|
57
|
+
in the actual MRO.
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
seen are
|
|
59
|
+
.. note::
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
Since ``object`` terminates all actual MRO's, ``TypeError``
|
|
62
|
+
is unlikely to ever be thrown, except in the case of some
|
|
63
|
+
exotic metaclass breaking this assumption. This exception
|
|
64
|
+
is here mainly to let typing tools know that object ``None``
|
|
65
|
+
is not a possible return type.
|
|
59
66
|
|
|
60
|
-
This happens frequently when the function is given
|
|
61
|
-
Python builtin types or in multiple inheritance situations.
|
|
62
67
|
|
|
63
68
|
"""
|
|
64
69
|
if issubclass(cls1, cls2):
|
|
@@ -66,10 +71,10 @@ def first_common_ancestor(cls1: type, cls2: type) -> type:
|
|
|
66
71
|
if issubclass(cls2, cls1):
|
|
67
72
|
return cls1
|
|
68
73
|
|
|
69
|
-
for
|
|
70
|
-
if issubclass(
|
|
71
|
-
return
|
|
72
|
-
raise TypeError("
|
|
74
|
+
for ancestor in cls1.__mro__:
|
|
75
|
+
if issubclass(cls2, ancestor):
|
|
76
|
+
return ancestor
|
|
77
|
+
raise TypeError("first_common_ancestor: no common ancestor found!")
|
|
73
78
|
|
|
74
79
|
|
|
75
80
|
def iterate_over_arguments[A](*args: A) -> Iterator[A]:
|
pythonic_fp/gadgets/box.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from collections.abc import Callable, Iterator
|
|
16
|
-
from typing import
|
|
16
|
+
from typing import Final, cast, overload
|
|
17
17
|
|
|
18
18
|
__all__ = ['Box']
|
|
19
19
|
|
|
@@ -105,9 +105,7 @@ class Box[T]:
|
|
|
105
105
|
|
|
106
106
|
if self._item is other._item:
|
|
107
107
|
return True
|
|
108
|
-
|
|
109
|
-
return True
|
|
110
|
-
return False
|
|
108
|
+
return self._item == other._item
|
|
111
109
|
|
|
112
110
|
def __repr__(self) -> str:
|
|
113
111
|
"""
|
|
@@ -199,7 +197,6 @@ class Box[T]:
|
|
|
199
197
|
else:
|
|
200
198
|
msg = 'Box: Trying to push an item in a non-empty Box'
|
|
201
199
|
raise ValueError(msg)
|
|
202
|
-
return None
|
|
203
200
|
|
|
204
201
|
def put(self, item: T) -> None:
|
|
205
202
|
"""
|
|
@@ -228,7 +225,7 @@ class Box[T]:
|
|
|
228
225
|
self._item = new_item
|
|
229
226
|
return popped
|
|
230
227
|
|
|
231
|
-
def map[U](self, f: Callable[[T], U]) ->
|
|
228
|
+
def map[U](self, f: Callable[[T], U]) -> Box[U]:
|
|
232
229
|
"""
|
|
233
230
|
.. admonition:: Map
|
|
234
231
|
|
|
@@ -243,7 +240,7 @@ class Box[T]:
|
|
|
243
240
|
return Box()
|
|
244
241
|
return Box(f(cast(T, self._item)))
|
|
245
242
|
|
|
246
|
-
def bind[U](self, f: Callable[[T],
|
|
243
|
+
def bind[U](self, f: Callable[[T], Box[U]]) -> Box[U]:
|
|
247
244
|
"""
|
|
248
245
|
.. admonition:: Bind
|
|
249
246
|
|
pythonic_fp/gadgets/wrap.py
CHANGED
|
@@ -12,12 +12,11 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
from collections.abc import Callable, Iterator, Hashable
|
|
15
|
+
from collections.abc import Callable, Hashable, Iterator
|
|
18
16
|
|
|
17
|
+
__all__ = ['Wrap', 'HWrap']
|
|
19
18
|
|
|
20
|
-
class Wrap[T]
|
|
19
|
+
class Wrap[T]:
|
|
21
20
|
"""
|
|
22
21
|
.. admonition:: Wrap
|
|
23
22
|
|
|
@@ -115,7 +114,7 @@ class Wrap[T]():
|
|
|
115
114
|
"""
|
|
116
115
|
return 'Wrap(' + str(self._item) + ')'
|
|
117
116
|
|
|
118
|
-
def map[U](self, f: Callable[[T], U]) ->
|
|
117
|
+
def map[U](self, f: Callable[[T], U]) -> Wrap[U]:
|
|
119
118
|
"""
|
|
120
119
|
.. admonition:: map
|
|
121
120
|
|
|
@@ -127,7 +126,7 @@ class Wrap[T]():
|
|
|
127
126
|
"""
|
|
128
127
|
return Wrap(f(self._item))
|
|
129
128
|
|
|
130
|
-
def bind[U](self, f: Callable[[T],
|
|
129
|
+
def bind[U](self, f: Callable[[T], Wrap[U]]) -> Wrap[U]:
|
|
131
130
|
"""
|
|
132
131
|
.. admonition:: bind
|
|
133
132
|
|
|
@@ -148,11 +147,11 @@ class HWrap[T: Hashable](Hashable):
|
|
|
148
147
|
|
|
149
148
|
.. tip::
|
|
150
149
|
|
|
151
|
-
``HWrap`` objects are
|
|
150
|
+
``HWrap`` objects are matchable and hashable.
|
|
152
151
|
|
|
153
152
|
"""
|
|
154
153
|
|
|
155
|
-
__slots__ = ('
|
|
154
|
+
__slots__ = ('_hash', '_item')
|
|
156
155
|
__match_args__ = ('_item',)
|
|
157
156
|
|
|
158
157
|
def __init__(self, item: T) -> None:
|
|
@@ -164,7 +163,7 @@ class HWrap[T: Hashable](Hashable):
|
|
|
164
163
|
:param item: Item to be wrapped.
|
|
165
164
|
|
|
166
165
|
"""
|
|
167
|
-
self._item, self._hash = item, hash(item)
|
|
166
|
+
self._item, self._hash = item, hash((item, '_hwrap'))
|
|
168
167
|
|
|
169
168
|
def __hash__(self) -> int:
|
|
170
169
|
return self._hash
|
|
@@ -244,7 +243,7 @@ class HWrap[T: Hashable](Hashable):
|
|
|
244
243
|
"""
|
|
245
244
|
return 'Wrap(' + str(self._item) + ')'
|
|
246
245
|
|
|
247
|
-
def map[U](self, f: Callable[[T], U]) ->
|
|
246
|
+
def map[U](self, f: Callable[[T], U]) -> HWrap[U]:
|
|
248
247
|
"""
|
|
249
248
|
.. admonition:: map
|
|
250
249
|
|
|
@@ -257,7 +256,7 @@ class HWrap[T: Hashable](Hashable):
|
|
|
257
256
|
"""
|
|
258
257
|
return HWrap(f(self._item))
|
|
259
258
|
|
|
260
|
-
def bind[U](self, f: Callable[[T],
|
|
259
|
+
def bind[U](self, f: Callable[[T], HWrap[U]]) -> HWrap[U]:
|
|
261
260
|
"""
|
|
262
261
|
.. admonition:: bind
|
|
263
262
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-gadgets
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.5.0
|
|
4
4
|
Summary: Gadgets without external Pythonic FP dependencies.
|
|
5
|
-
Keywords: gadgets
|
|
5
|
+
Keywords: gadgets,no-external-dependencies
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
7
|
Requires-Python: >=3.14
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
@@ -31,18 +31,19 @@ Part of the
|
|
|
31
31
|
[pythonic-fp](https://grscheller.github.io/pythonic-fp/)
|
|
32
32
|
PyPI projects.
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Description
|
|
35
35
|
|
|
36
|
+
Project Pythonic FP Gadgets contains
|
|
37
|
+
|
|
38
|
+
- single item box
|
|
39
|
+
- immutable wrapper classes, matchable, hashable and non-hashable versions
|
|
40
|
+
- sentinel values
|
|
41
|
+
- function returning iterator of its arguments
|
|
42
|
+
- function to find the latest common ancestor of two classes
|
|
43
|
+
|
|
36
44
|
Documentation and other links for this project are hosted on
|
|
37
45
|
[GitHub Pages](https://grscheller.github.io/pythonic-fp/projects/gadgets.html).
|
|
38
46
|
|
|
39
|
-
- Gadgets
|
|
40
|
-
- single item box
|
|
41
|
-
- immutable wrapped (hashable) references
|
|
42
|
-
- function returning iterator of its arguments
|
|
43
|
-
- function to find the latest common ancestor of two classes
|
|
44
|
-
- sentinel values
|
|
45
|
-
|
|
46
47
|
## Copyright and License
|
|
47
48
|
|
|
48
49
|
Copyright (c) 2025-2026 Geoffrey R. Scheller. Licensed under the Apache
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
pythonic_fp/gadgets/__init__.py,sha256=XcjEjYz5Wi8VcSJ3BEqCWDyZ_6w_Q1m1XyUpFngBRUk,2973
|
|
2
|
+
pythonic_fp/gadgets/box.py,sha256=9BPmCp_pYjNr6si444p0C2n8Tfb1mtQn6IwAi_1oO54,7047
|
|
3
|
+
pythonic_fp/gadgets/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
pythonic_fp/gadgets/wrap.py,sha256=QUN8ILCsqOqukDHBs9dZJmfwIkfp1E5jAQGLS9qwhi0,6462
|
|
5
|
+
pythonic_fp/gadgets/sentinels/__init__.py,sha256=Xh63-GTwiqqcBqs5OEYBSiLXuWtq_CVHfUz0mKO_2H0,775
|
|
6
|
+
pythonic_fp/gadgets/sentinels/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
pythonic_fp/gadgets/sentinels/flavored.py,sha256=LPmA-XOadcN5gJgxxo2prSnwRvq8bJ7o0Ae2_Y70Au0,2774
|
|
8
|
+
pythonic_fp/gadgets/sentinels/flavored.pyi,sha256=K3YSyXLyylPII2ahRP0olhzLJruOeR73TFJDC6rCUwk,212
|
|
9
|
+
pythonic_fp/gadgets/sentinels/novalue.py,sha256=gaQNm1TRtphbmWgDV8O0sblH7eU2M-Zymu_B67mwsJ8,6097
|
|
10
|
+
pythonic_fp/gadgets/sentinels/novalue.pyi,sha256=1_iUI6FEwYma8P4XXVCb6CKhSYmfq53S8dLmiwNtJw4,244
|
|
11
|
+
pythonic_fp_gadgets-4.5.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
12
|
+
pythonic_fp_gadgets-4.5.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
13
|
+
pythonic_fp_gadgets-4.5.0.dist-info/METADATA,sha256=vAT0Ldrr9Qyy2Uh4hkyidkSZ446UerMAOLBdnerSulo,1873
|
|
14
|
+
pythonic_fp_gadgets-4.5.0.dist-info/RECORD,,
|
pythonic_fp/gadgets/__init__.pyi
DELETED
pythonic_fp/gadgets/box.pyi
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from _typeshed import Incomplete
|
|
2
|
-
from collections.abc import Callable, Iterator
|
|
3
|
-
from typing import overload
|
|
4
|
-
|
|
5
|
-
__all__ = ['Box']
|
|
6
|
-
|
|
7
|
-
type _Sentinel = object
|
|
8
|
-
class Box[T]:
|
|
9
|
-
__match_args__: Incomplete
|
|
10
|
-
@overload
|
|
11
|
-
def __init__(self, item: T) -> None: ...
|
|
12
|
-
@overload
|
|
13
|
-
def __init__(self) -> None: ...
|
|
14
|
-
def __bool__(self) -> bool: ...
|
|
15
|
-
def __iter__(self) -> Iterator[T]: ...
|
|
16
|
-
def __len__(self) -> int: ...
|
|
17
|
-
def __eq__(self, other: object) -> bool: ...
|
|
18
|
-
@overload
|
|
19
|
-
def get(self) -> T: ...
|
|
20
|
-
@overload
|
|
21
|
-
def get(self, alt: T) -> T: ...
|
|
22
|
-
def pop(self) -> T: ...
|
|
23
|
-
def push(self, item: T) -> None: ...
|
|
24
|
-
def put(self, item: T) -> None: ...
|
|
25
|
-
def exchange(self, new_item: T) -> T: ...
|
|
26
|
-
def map[U](self, f: Callable[[T], U]) -> Box[U]: ...
|
|
27
|
-
def bind[U](self, f: Callable[[T], 'Box[U]']) -> Box[U]: ...
|
pythonic_fp/gadgets/wrap.pyi
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from _typeshed import Incomplete
|
|
2
|
-
from collections.abc import Callable, Hashable, Iterator
|
|
3
|
-
|
|
4
|
-
__all__ = ['Wrap', 'HWrap']
|
|
5
|
-
|
|
6
|
-
class Wrap[T]:
|
|
7
|
-
__match_args__: Incomplete
|
|
8
|
-
def __init__(self, item: T) -> None: ...
|
|
9
|
-
def __bool__(self) -> bool: ...
|
|
10
|
-
def __iter__(self) -> Iterator[T]: ...
|
|
11
|
-
def __eq__(self, other: object) -> bool: ...
|
|
12
|
-
def map[U](self, f: Callable[[T], U]) -> Wrap[U]: ...
|
|
13
|
-
def bind[U](self, f: Callable[[T], 'Wrap[U]']) -> Wrap[U]: ...
|
|
14
|
-
|
|
15
|
-
class HWrap[T: Hashable](Hashable):
|
|
16
|
-
__match_args__: Incomplete
|
|
17
|
-
def __init__(self, item: T) -> None: ...
|
|
18
|
-
def __hash__(self) -> int: ...
|
|
19
|
-
def __bool__(self) -> bool: ...
|
|
20
|
-
def __iter__(self) -> Iterator[T]: ...
|
|
21
|
-
def __eq__(self, other: object) -> bool: ...
|
|
22
|
-
def map[U](self, f: Callable[[T], U]) -> HWrap[U]: ...
|
|
23
|
-
def bind[U](self, f: Callable[[T], 'HWrap[U]']) -> HWrap[U]: ...
|
|
@@ -1,17 +0,0 @@
|
|
|
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.3.1.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
15
|
-
pythonic_fp_gadgets-4.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
16
|
-
pythonic_fp_gadgets-4.3.1.dist-info/METADATA,sha256=IVjIF3Na-O4SOI3GOpr7jPtVShlsWa6Mlb-CMBupWgc,1798
|
|
17
|
-
pythonic_fp_gadgets-4.3.1.dist-info/RECORD,,
|
|
File without changes
|
{pythonic_fp_gadgets-4.3.1.dist-info → pythonic_fp_gadgets-4.5.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|