pythonic-fp-booleans 4.3.0__tar.gz → 5.0.0__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.
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/PKG-INFO +3 -3
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/README.md +1 -1
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/pyproject.toml +8 -3
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/__init__.py +2 -2
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/flavored.py +37 -1
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/subtypable.py +53 -8
- pythonic_fp_booleans-5.0.0/src/pythonic_fp/booleans/truthy_falsy.py +285 -0
- pythonic_fp_booleans-4.3.0/src/pythonic_fp/booleans/truthy_falsy.py +0 -229
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/LICENSE +0 -0
- {pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/py.typed +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-booleans
|
|
3
|
-
Version:
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 5.0.0
|
|
4
|
+
Summary: Boolean like classes.
|
|
5
5
|
Keywords: booleans,subtypable
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
7
|
Requires-Python: >=3.14
|
|
@@ -23,7 +23,7 @@ Project-URL: Source, https://github.com/grscheller/pythonic-fp-booleans
|
|
|
23
23
|
|
|
24
24
|
# Pythonic FP - Booleans
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Boolean like classes.
|
|
27
27
|
|
|
28
28
|
PyPI project
|
|
29
29
|
[pythonic-fp-booleans](https://pypi.org/project/pythonic-fp-booleans).
|
|
@@ -4,10 +4,10 @@ build-backend = "flit_core.buildapi"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pythonic-fp-booleans"
|
|
7
|
-
version = "
|
|
8
|
-
description = "
|
|
7
|
+
version = "5.0.0"
|
|
8
|
+
description = "Boolean like classes."
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.14" # floor: PEP 649/749 deferred annotations — class-level self-reference
|
|
10
|
+
requires-python = ">=3.14" # floor: PEP 649/749 deferred annotations — class-level self-reference NameErrors on <3.14
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "Geoffrey R. Scheller", email = "geoffrey@scheller.com" },
|
|
13
13
|
]
|
|
@@ -51,6 +51,11 @@ name = "pythonic_fp.booleans"
|
|
|
51
51
|
exclude = [
|
|
52
52
|
"docs/",
|
|
53
53
|
"tests/",
|
|
54
|
+
"**/.mypy_cache/",
|
|
55
|
+
"**/.ruff_cache/",
|
|
56
|
+
"**/.pytest_cache/",
|
|
57
|
+
"**/__pycache__/",
|
|
58
|
+
"**/.dmypy.json",
|
|
54
59
|
]
|
|
55
60
|
|
|
56
61
|
[tool.pytest]
|
{pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/__init__.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
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.
|
|
@@ -26,5 +26,5 @@ Booleans
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
__author__ = 'Geoffrey R. Scheller'
|
|
29
|
-
__copyright__ = 'Copyright (c)
|
|
29
|
+
__copyright__ = 'Copyright (c) 2023-2026 Geoffrey R. Scheller'
|
|
30
30
|
__license__ = 'Apache License 2.0'
|
{pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/flavored.py
RENAMED
|
@@ -86,6 +86,18 @@ class FBool(SBool):
|
|
|
86
86
|
self._flavor = flavor
|
|
87
87
|
|
|
88
88
|
def __and__(self, other: int) -> int:
|
|
89
|
+
"""
|
|
90
|
+
.. admonition:: bitwise and operator
|
|
91
|
+
|
|
92
|
+
Overloading ``&`` to perform Boolean "and" if ``other`` is
|
|
93
|
+
another FBool of the same flavor.
|
|
94
|
+
|
|
95
|
+
:param other: Any object derived from int.
|
|
96
|
+
:returns: Boolean "and" if other is an FBool of the same
|
|
97
|
+
flavor, otherwise returns bitwise "and".
|
|
98
|
+
:raises: ValueError if other is an FBool of a different flavor.
|
|
99
|
+
|
|
100
|
+
"""
|
|
89
101
|
if type(other) is type(self):
|
|
90
102
|
if other.flavor() != self._flavor:
|
|
91
103
|
msg = 'Error: diffent flavored booleans compared with & operator'
|
|
@@ -97,6 +109,18 @@ class FBool(SBool):
|
|
|
97
109
|
return super().__and__(other)
|
|
98
110
|
|
|
99
111
|
def __or__(self, other: int) -> int:
|
|
112
|
+
"""
|
|
113
|
+
.. admonition:: bitwise or operator
|
|
114
|
+
|
|
115
|
+
Overloading ``|`` to perform Boolean "or" if ``other`` is
|
|
116
|
+
another FBool of the same flavor.
|
|
117
|
+
|
|
118
|
+
:param other: Any object derived from int.
|
|
119
|
+
:returns: Boolean "or" if other is an FBool of the same
|
|
120
|
+
flavor, otherwise returns bitwise "or".
|
|
121
|
+
:raises: ValueError if other is an FBool of a different flavor.
|
|
122
|
+
|
|
123
|
+
"""
|
|
100
124
|
if type(other) is type(self):
|
|
101
125
|
if other.flavor() != self.flavor():
|
|
102
126
|
msg = 'Error: diffent flavored booleans compared with | operator'
|
|
@@ -108,6 +132,18 @@ class FBool(SBool):
|
|
|
108
132
|
return super().__or__(other)
|
|
109
133
|
|
|
110
134
|
def __xor__(self, other: int) -> int:
|
|
135
|
+
"""
|
|
136
|
+
.. admonition:: bitwise xor operator
|
|
137
|
+
|
|
138
|
+
Overloading ``^`` to perform Boolean "xor" if ``other`` is
|
|
139
|
+
another FBool of the same flavor.
|
|
140
|
+
|
|
141
|
+
:param other: Any object derived from int.
|
|
142
|
+
:returns: Boolean "xor" if other is an FBool of the same
|
|
143
|
+
flavor, otherwise returns bitwise "or".
|
|
144
|
+
:raises: ValueError if other is an FBool of a different flavor.
|
|
145
|
+
|
|
146
|
+
"""
|
|
111
147
|
if type(other) is type(self):
|
|
112
148
|
if other.flavor() != self._flavor:
|
|
113
149
|
msg = 'Error: diffent flavored booleans compared with ^ operator'
|
|
@@ -160,7 +196,7 @@ class FBool(SBool):
|
|
|
160
196
|
|
|
161
197
|
Get the flavor of the ``FBool``, a hashable value.
|
|
162
198
|
|
|
163
|
-
:returns: The flavor.
|
|
199
|
+
:returns: The flavor of the FBool.
|
|
164
200
|
|
|
165
201
|
"""
|
|
166
202
|
return self._flavor
|
{pythonic_fp_booleans-4.3.0 → pythonic_fp_booleans-5.0.0}/src/pythonic_fp/booleans/subtypable.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2023-
|
|
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.
|
|
@@ -91,7 +91,7 @@ class SBool(int):
|
|
|
91
91
|
.. admonition:: new
|
|
92
92
|
|
|
93
93
|
:param witness: Determines truthiness of the ``SBool``.
|
|
94
|
-
:param flavor: Ignored
|
|
94
|
+
:param flavor: Ignored, here for Liskov substitution principle
|
|
95
95
|
:returns: The truthy or falsy ``SBool`` class instance.
|
|
96
96
|
|
|
97
97
|
"""
|
|
@@ -128,11 +128,32 @@ class SBool(int):
|
|
|
128
128
|
self._flavor: Hashable | NoValue = NoValue()
|
|
129
129
|
|
|
130
130
|
def __invert__(self) -> int:
|
|
131
|
+
"""
|
|
132
|
+
.. admonition:: bitwise invert operator
|
|
133
|
+
|
|
134
|
+
Inverts the value of an SBool.
|
|
135
|
+
|
|
136
|
+
:returns: The inverted value of the SBool.
|
|
137
|
+
|
|
138
|
+
"""
|
|
131
139
|
if self:
|
|
132
140
|
return type(self)(False, self._flavor)
|
|
133
141
|
return type(self)(True, self._flavor)
|
|
134
142
|
|
|
135
143
|
def __and__(self, other: int) -> int:
|
|
144
|
+
"""
|
|
145
|
+
.. admonition:: bitwise and operator
|
|
146
|
+
|
|
147
|
+
Overloading ``&`` to perform Boolean "and" if ``other``
|
|
148
|
+
is another ``SBool``.
|
|
149
|
+
|
|
150
|
+
:param other: Any object derived from int.
|
|
151
|
+
:returns: Boolean "and" if other is an SBool
|
|
152
|
+
otherwise returns bitwise "and".
|
|
153
|
+
:rtype: First common ancestor of the types of self and other
|
|
154
|
+
if both of type SBool, otherwise int.
|
|
155
|
+
|
|
156
|
+
"""
|
|
136
157
|
base_class = fca(type(self), type(other))
|
|
137
158
|
|
|
138
159
|
if issubclass(base_class, SBool):
|
|
@@ -148,6 +169,19 @@ class SBool(int):
|
|
|
148
169
|
return int(self) & int(other)
|
|
149
170
|
|
|
150
171
|
def __or__(self, other: int) -> int:
|
|
172
|
+
"""
|
|
173
|
+
.. admonition:: bitwise or operator
|
|
174
|
+
|
|
175
|
+
Overloading ``|`` to perform Boolean "or" if ``other``
|
|
176
|
+
is another ``SBool``.
|
|
177
|
+
|
|
178
|
+
:param other: Any object derived from int.
|
|
179
|
+
:returns: Boolean "and" if other is an SBool
|
|
180
|
+
otherwise returns bitwise "and".
|
|
181
|
+
:rtype: First common ancestor of the types of self and other
|
|
182
|
+
if both of type SBool, otherwise int.
|
|
183
|
+
|
|
184
|
+
"""
|
|
151
185
|
base_class = fca(type(self), type(other))
|
|
152
186
|
if issubclass(base_class, SBool):
|
|
153
187
|
if self._flavor == cast(SBool, other)._flavor:
|
|
@@ -162,6 +196,19 @@ class SBool(int):
|
|
|
162
196
|
return int(self) | int(other)
|
|
163
197
|
|
|
164
198
|
def __xor__(self, other: int) -> int:
|
|
199
|
+
"""
|
|
200
|
+
.. admonition:: bitwise xor operator
|
|
201
|
+
|
|
202
|
+
Overloading ``^`` to perform Boolean "xor" if ``other``
|
|
203
|
+
is another ``SBool``.
|
|
204
|
+
|
|
205
|
+
:param other: Any object derived from int.
|
|
206
|
+
:returns: Boolean "and" if other is an SBool
|
|
207
|
+
otherwise returns bitwise "and".
|
|
208
|
+
:rtype: First common ancestor of the types of self and other
|
|
209
|
+
if both of type SBool, otherwise int.
|
|
210
|
+
|
|
211
|
+
"""
|
|
165
212
|
base_class = fca(type(self), type(other))
|
|
166
213
|
|
|
167
214
|
if issubclass(base_class, SBool):
|
|
@@ -181,10 +228,9 @@ class SBool(int):
|
|
|
181
228
|
"""
|
|
182
229
|
.. admonition:: repr string
|
|
183
230
|
|
|
184
|
-
|
|
185
|
-
- 'SBool(False)' if falsy
|
|
231
|
+
A string to reproduce the ``SBool``.
|
|
186
232
|
|
|
187
|
-
:returns:
|
|
233
|
+
:returns: 'SBool(True)' if truthy, 'SBool(False)' if falsy.
|
|
188
234
|
|
|
189
235
|
"""
|
|
190
236
|
if self:
|
|
@@ -196,10 +242,9 @@ class SBool(int):
|
|
|
196
242
|
"""
|
|
197
243
|
.. admonition:: user string
|
|
198
244
|
|
|
199
|
-
|
|
200
|
-
- 'LIE' if falsy
|
|
245
|
+
A string meaningful to an end user.
|
|
201
246
|
|
|
202
|
-
:returns:
|
|
247
|
+
:returns: 'TRUTH' if truthy, 'LIE' if falsy.
|
|
203
248
|
|
|
204
249
|
"""
|
|
205
250
|
if self:
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Copyright 2023-2026 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 Hashable
|
|
16
|
+
from threading import Lock
|
|
17
|
+
from typing import ClassVar, Final, Self, cast, final
|
|
18
|
+
|
|
19
|
+
from .subtypable import SBool
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
'TF_Bool',
|
|
23
|
+
'T_Bool',
|
|
24
|
+
'F_Bool',
|
|
25
|
+
'ALWAYS',
|
|
26
|
+
'NEVER',
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TF_Bool(SBool):
|
|
31
|
+
"""
|
|
32
|
+
.. admonition:: Truthy-Falsy Booleans
|
|
33
|
+
|
|
34
|
+
A Boolean implementation whose distinct truthy and falsy
|
|
35
|
+
values are distinct singleton subclasses, not just
|
|
36
|
+
distinct singleton values.
|
|
37
|
+
|
|
38
|
+
.. important::
|
|
39
|
+
|
|
40
|
+
Do not subclass ``TF_Bool`` itself. Subclassing it is
|
|
41
|
+
designed to fail at runtime.
|
|
42
|
+
|
|
43
|
+
.. tip::
|
|
44
|
+
|
|
45
|
+
Logically combine these using Python's bitwise operators.
|
|
46
|
+
|
|
47
|
+
.. warning::
|
|
48
|
+
|
|
49
|
+
Although these datastructures are completely compatible
|
|
50
|
+
with Python shortcut evaluation, care needs to be taken
|
|
51
|
+
when using them with the ``and``, ``or``, and ``not`` builtins.
|
|
52
|
+
|
|
53
|
+
For example:
|
|
54
|
+
|
|
55
|
+
- ``~ALWAYS is NEVER``
|
|
56
|
+
- ``not ALWAYS is False``
|
|
57
|
+
- ``(ALWAYS and False) is False``
|
|
58
|
+
- ``(ALWAYS or False) is ALWAYS``
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __new__(cls, witness: object, flavor: Hashable = None) -> Self:
|
|
63
|
+
"""
|
|
64
|
+
.. admonition:: new
|
|
65
|
+
|
|
66
|
+
:param witness: Determines which subtype,
|
|
67
|
+
``T_Bool`` or ``F_Bool``,
|
|
68
|
+
of ``TF_Bool`` to return.
|
|
69
|
+
:param flavor: Ignored parameter, only two flavors,
|
|
70
|
+
one truthy and one falsy.
|
|
71
|
+
:returns: The singleton truthy or singleton falsy instance.
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
if witness:
|
|
75
|
+
return cast(Self, T_Bool())
|
|
76
|
+
return cast(Self, F_Bool())
|
|
77
|
+
|
|
78
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
79
|
+
super().__init_subclass__(**kwargs)
|
|
80
|
+
if TF_Bool in cls.__bases__ and cls.__module__ != TF_Bool.__module__:
|
|
81
|
+
msg = 'TF_Bool is sealed'
|
|
82
|
+
raise TypeError(msg)
|
|
83
|
+
|
|
84
|
+
def __invert__(self) -> TF_Bool:
|
|
85
|
+
"""
|
|
86
|
+
.. admonition:: bitwise invert operator
|
|
87
|
+
|
|
88
|
+
Inverts the value of an TF_Bool.
|
|
89
|
+
|
|
90
|
+
:returns: The inverted value of the SBool.
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
if self:
|
|
94
|
+
return F_Bool()
|
|
95
|
+
return T_Bool()
|
|
96
|
+
|
|
97
|
+
def __repr__(self) -> str:
|
|
98
|
+
"""
|
|
99
|
+
.. admonition:: repr string
|
|
100
|
+
|
|
101
|
+
A string to reproduce the TF_Bool.
|
|
102
|
+
|
|
103
|
+
:returns: 'T_Bool()' if truthy, otherwise `F_Bool()`
|
|
104
|
+
|
|
105
|
+
"""
|
|
106
|
+
if self:
|
|
107
|
+
return 'T_Bool()'
|
|
108
|
+
return 'F_Bool()'
|
|
109
|
+
|
|
110
|
+
def __str__(self) -> str:
|
|
111
|
+
"""
|
|
112
|
+
.. admonition:: user string
|
|
113
|
+
|
|
114
|
+
A string meaningful to an end user.
|
|
115
|
+
|
|
116
|
+
:returns: 'ALWAYS' if truthy, otherwise 'NEVER'
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
if self:
|
|
120
|
+
return 'ALWAYS'
|
|
121
|
+
return 'NEVER'
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@final
|
|
125
|
+
class T_Bool(TF_Bool):
|
|
126
|
+
"""
|
|
127
|
+
.. admonition:: Truthy TF_Bool subclass
|
|
128
|
+
|
|
129
|
+
Type of the truthy singleton TF_Bool instance.
|
|
130
|
+
A distinct type from F_Bool.
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
_lock: ClassVar[Lock] = Lock()
|
|
135
|
+
|
|
136
|
+
def __new__(cls, witness: object = None, flavor: Hashable = None) -> Self:
|
|
137
|
+
"""
|
|
138
|
+
.. admonition:: new
|
|
139
|
+
|
|
140
|
+
:param witness: Ignored parameter, a T_Bool or T_Bool subtype is always truthy.
|
|
141
|
+
:param flavor: Ignored parameter, only one truthy "flavor" for each T_Bool subtype.
|
|
142
|
+
:returns: The truthy T_Bool or T_Bool subtype singleton instance.
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
inst = cls.__dict__.get('_truthy')
|
|
146
|
+
if inst is None:
|
|
147
|
+
with T_Bool._lock:
|
|
148
|
+
inst = cls.__dict__.get('_truthy')
|
|
149
|
+
if inst is None:
|
|
150
|
+
inst = super(SBool, cls).__new__(cls, 1)
|
|
151
|
+
cls._truthy = inst
|
|
152
|
+
return cast(Self, inst)
|
|
153
|
+
|
|
154
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
155
|
+
super().__init_subclass__(**kwargs)
|
|
156
|
+
if T_Bool in cls.__bases__ and cls.__module__ != T_Bool.__module__:
|
|
157
|
+
msg = 'T_Bool is final'
|
|
158
|
+
raise TypeError(msg)
|
|
159
|
+
|
|
160
|
+
def __and__(self, other: int) -> int:
|
|
161
|
+
"""
|
|
162
|
+
.. admonition:: bitwise and operator
|
|
163
|
+
|
|
164
|
+
Overloading ``&`` to perform Boolean "and" if ``other``
|
|
165
|
+
is another ``TF_Bool``.
|
|
166
|
+
|
|
167
|
+
:param other: Any object derived from int.
|
|
168
|
+
:returns: Boolean "and" if other is an SBool
|
|
169
|
+
otherwise returns bitwise "and".
|
|
170
|
+
:rtype: First common ancestor of the types of self and other
|
|
171
|
+
if both of type SBool, otherwise int.
|
|
172
|
+
|
|
173
|
+
"""
|
|
174
|
+
if isinstance(other, TF_Bool):
|
|
175
|
+
return other
|
|
176
|
+
return super().__and__(other)
|
|
177
|
+
|
|
178
|
+
def __or__(self, other: int) -> int:
|
|
179
|
+
"""
|
|
180
|
+
.. admonition:: bitwise or operator
|
|
181
|
+
|
|
182
|
+
Overloading ``|`` to perform Boolean "or" if ``other``
|
|
183
|
+
is another ``TF_Bool``.
|
|
184
|
+
|
|
185
|
+
:param other: Any object derived from int.
|
|
186
|
+
:returns: Boolean "or" if other is an SBool
|
|
187
|
+
otherwise returns bitwise "or".
|
|
188
|
+
:rtype: First common ancestor of the types of self and other
|
|
189
|
+
if both of type SBool, otherwise int.
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
if isinstance(other, TF_Bool):
|
|
193
|
+
return self
|
|
194
|
+
return super().__or__(other)
|
|
195
|
+
|
|
196
|
+
def __xor__(self, other: int) -> int:
|
|
197
|
+
"""
|
|
198
|
+
.. admonition:: bitwise xor operator
|
|
199
|
+
|
|
200
|
+
Overloading ``^`` to perform Boolean "xor" if ``other``
|
|
201
|
+
is another ``TF_Bool``.
|
|
202
|
+
|
|
203
|
+
:param other: Any object derived from int.
|
|
204
|
+
:returns: Boolean "xor" if other is an SBool
|
|
205
|
+
otherwise returns bitwise "xor".
|
|
206
|
+
:rtype: First common ancestor of the types of self and other
|
|
207
|
+
if both of type SBool, otherwise int.
|
|
208
|
+
|
|
209
|
+
"""
|
|
210
|
+
if isinstance(other, TF_Bool):
|
|
211
|
+
if other:
|
|
212
|
+
return ~self
|
|
213
|
+
return self
|
|
214
|
+
return super().__xor__(other)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@final
|
|
218
|
+
class F_Bool(TF_Bool):
|
|
219
|
+
"""
|
|
220
|
+
.. admonition:: Falsy TF_Bool subclass
|
|
221
|
+
|
|
222
|
+
Type of the falsy singleton TF_Bool instance.
|
|
223
|
+
A distinct type from T_Bool.
|
|
224
|
+
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
_lock: ClassVar[Lock] = Lock()
|
|
228
|
+
|
|
229
|
+
def __new__(cls, witness: object = None, flavor: Hashable = None) -> Self:
|
|
230
|
+
"""
|
|
231
|
+
.. admonition:: new
|
|
232
|
+
|
|
233
|
+
:param witness: Ignored parameter, an F_Bool or F_Bool subtype is always truthy.
|
|
234
|
+
:param flavor: Ignored parameter, only one truthy "flavor" for each F_Bool subtype.
|
|
235
|
+
:returns: The truthy F_Bool or F_Bool subtype singleton instance.
|
|
236
|
+
|
|
237
|
+
"""
|
|
238
|
+
inst = cls.__dict__.get('_falsy')
|
|
239
|
+
if inst is None:
|
|
240
|
+
with T_Bool._lock:
|
|
241
|
+
inst = cls.__dict__.get('_falsy')
|
|
242
|
+
if inst is None:
|
|
243
|
+
inst = super(SBool, cls).__new__(cls, 0)
|
|
244
|
+
cls._falsy = inst
|
|
245
|
+
return cast(Self, inst)
|
|
246
|
+
|
|
247
|
+
def __init_subclass__(cls, **kwargs: object) -> None:
|
|
248
|
+
super().__init_subclass__(**kwargs)
|
|
249
|
+
if F_Bool in cls.__bases__ and cls.__module__ != F_Bool.__module__:
|
|
250
|
+
msg = 'F_Bool is final'
|
|
251
|
+
raise TypeError(msg)
|
|
252
|
+
|
|
253
|
+
def __and__(self, other: int) -> int:
|
|
254
|
+
if issubclass(type(other), TF_Bool):
|
|
255
|
+
return self
|
|
256
|
+
return super().__and__(other)
|
|
257
|
+
|
|
258
|
+
def __or__(self, other: int) -> int:
|
|
259
|
+
if issubclass(type(other), TF_Bool):
|
|
260
|
+
return other
|
|
261
|
+
return super().__or__(other)
|
|
262
|
+
|
|
263
|
+
def __xor__(self, other: int) -> int:
|
|
264
|
+
if issubclass(type(other), TF_Bool):
|
|
265
|
+
if other:
|
|
266
|
+
return other
|
|
267
|
+
return self
|
|
268
|
+
return super().__xor__(other)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
ALWAYS: Final[TF_Bool] = T_Bool()
|
|
272
|
+
"""
|
|
273
|
+
.. admonition:: ALWAYS
|
|
274
|
+
|
|
275
|
+
:var ALWAYS: The truthy singleton TF_Bool subtyped instance.
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
NEVER: Final[TF_Bool] = F_Bool()
|
|
280
|
+
"""
|
|
281
|
+
.. admonition:: NEVER
|
|
282
|
+
|
|
283
|
+
:var NEVER: The falsy singleton TF_Bool subtyped instance.
|
|
284
|
+
|
|
285
|
+
"""
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
# Copyright 2023-2026 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 Hashable
|
|
16
|
-
from threading import Lock
|
|
17
|
-
from typing import ClassVar, Final, Self, cast
|
|
18
|
-
|
|
19
|
-
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
20
|
-
|
|
21
|
-
from .subtypable import SBool
|
|
22
|
-
|
|
23
|
-
__all__ = [
|
|
24
|
-
'TF_Bool',
|
|
25
|
-
'T_Bool',
|
|
26
|
-
'F_Bool',
|
|
27
|
-
'ALWAYS',
|
|
28
|
-
'NEVER',
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class TF_Bool(SBool):
|
|
33
|
-
"""
|
|
34
|
-
.. admonition:: Truthy-Falsy Booleans
|
|
35
|
-
|
|
36
|
-
A Boolean implementation whose distinct truthy and falsy
|
|
37
|
-
values are distinct singleton subclasses, not just
|
|
38
|
-
distinct singleton values.
|
|
39
|
-
|
|
40
|
-
A subtype of SBool.
|
|
41
|
-
|
|
42
|
-
.. tip::
|
|
43
|
-
|
|
44
|
-
Logically combine these using Python's bitwise operators.
|
|
45
|
-
|
|
46
|
-
.. warning::
|
|
47
|
-
|
|
48
|
-
Although these datastructures are completely compatible
|
|
49
|
-
with Python shortcut evaluation, care needs to be taken when
|
|
50
|
-
using them with the "and", "or", and "not" builtins.
|
|
51
|
-
|
|
52
|
-
For example, ``~ALWAYS is NEVER`` but ``not ALWAYS is False``
|
|
53
|
-
because ``ALWAYS`` is truthy.
|
|
54
|
-
|
|
55
|
-
Similarly, ``(ALWAYS and False) is False`` while
|
|
56
|
-
``(ALWAYS or False) is ALWAYS``.
|
|
57
|
-
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
no_value = NoValue()
|
|
61
|
-
|
|
62
|
-
def __new__(
|
|
63
|
-
cls,
|
|
64
|
-
witness: object,
|
|
65
|
-
flavor: Hashable = no_value,
|
|
66
|
-
) -> Self:
|
|
67
|
-
"""
|
|
68
|
-
.. admonition:: new
|
|
69
|
-
|
|
70
|
-
:param witness: Determines which subtype, T_Bool or F_Bool to return.
|
|
71
|
-
:param flavor: Ignored parameter, only two flavors, one truthy and one falsy.
|
|
72
|
-
:returns: The singleton truthy or singleton falsy instances.
|
|
73
|
-
|
|
74
|
-
"""
|
|
75
|
-
if witness:
|
|
76
|
-
return cast(Self, T_Bool())
|
|
77
|
-
return cast(Self, F_Bool())
|
|
78
|
-
|
|
79
|
-
def __invert__(self) -> TF_Bool:
|
|
80
|
-
if self:
|
|
81
|
-
return F_Bool()
|
|
82
|
-
return T_Bool()
|
|
83
|
-
|
|
84
|
-
def __repr__(self) -> str:
|
|
85
|
-
"""
|
|
86
|
-
.. admonition:: repr string
|
|
87
|
-
|
|
88
|
-
- if truthy return 'TF_Bool(True)'
|
|
89
|
-
- if falsy return 'TF_Bool(False)'
|
|
90
|
-
|
|
91
|
-
:returns: A string to reproduce the TF_Bool.
|
|
92
|
-
|
|
93
|
-
"""
|
|
94
|
-
if self:
|
|
95
|
-
return 'TF_Bool(True)'
|
|
96
|
-
return 'TF_Bool(False)'
|
|
97
|
-
|
|
98
|
-
def __str__(self) -> str:
|
|
99
|
-
"""
|
|
100
|
-
.. admonition:: user string
|
|
101
|
-
|
|
102
|
-
- if truthy return 'ALWAYS'
|
|
103
|
-
- if falsy return 'NEVER'
|
|
104
|
-
|
|
105
|
-
:returns: A string meaningful to an end user.
|
|
106
|
-
|
|
107
|
-
"""
|
|
108
|
-
if self:
|
|
109
|
-
return 'ALWAYS'
|
|
110
|
-
return 'NEVER'
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class T_Bool(TF_Bool):
|
|
114
|
-
"""
|
|
115
|
-
.. admonition:: Truthy TF_Bool subclass
|
|
116
|
-
|
|
117
|
-
Type of the truthy singleton TS_Bool instance.
|
|
118
|
-
A distinct type from F_Bool.
|
|
119
|
-
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
no_value = NoValue()
|
|
123
|
-
|
|
124
|
-
_truthy: ClassVar[T_Bool | NoValue] = no_value
|
|
125
|
-
_lock: ClassVar[Lock] = Lock()
|
|
126
|
-
|
|
127
|
-
def __new__(
|
|
128
|
-
cls,
|
|
129
|
-
witness: object = no_value,
|
|
130
|
-
flavor: Hashable | NoValue = no_value,
|
|
131
|
-
) -> Self:
|
|
132
|
-
"""
|
|
133
|
-
.. admonition:: new
|
|
134
|
-
|
|
135
|
-
:param witness: Ignored parameter, a T_Bool is always truthy.
|
|
136
|
-
:param flavor: Ignored parameter, only one truthy "flavor".
|
|
137
|
-
:returns: The truthy T_Bool singleton instance.
|
|
138
|
-
|
|
139
|
-
"""
|
|
140
|
-
if cls._truthy is (no_value := NoValue()):
|
|
141
|
-
with cls._lock:
|
|
142
|
-
if cls._truthy is no_value:
|
|
143
|
-
cls._truthy = super(SBool, cls).__new__(cls, 1)
|
|
144
|
-
return cast(Self, cls._truthy)
|
|
145
|
-
|
|
146
|
-
def __and__(self, other: int) -> int:
|
|
147
|
-
if isinstance(other, TF_Bool):
|
|
148
|
-
return other
|
|
149
|
-
return super().__and__(other)
|
|
150
|
-
|
|
151
|
-
def __or__(self, other: int) -> int:
|
|
152
|
-
if isinstance(other, TF_Bool):
|
|
153
|
-
return self
|
|
154
|
-
return super().__or__(other)
|
|
155
|
-
|
|
156
|
-
def __xor__(self, other: int) -> int:
|
|
157
|
-
if isinstance(other, TF_Bool):
|
|
158
|
-
if other:
|
|
159
|
-
return ~self
|
|
160
|
-
return self
|
|
161
|
-
return super().__xor__(other)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
class F_Bool(TF_Bool):
|
|
165
|
-
"""
|
|
166
|
-
.. admonition:: Falsy TF_Bool subclass
|
|
167
|
-
|
|
168
|
-
Type of the falsy singleton TS_Bool instance.
|
|
169
|
-
A distinct type from T_Bool.
|
|
170
|
-
|
|
171
|
-
"""
|
|
172
|
-
|
|
173
|
-
no_value = NoValue()
|
|
174
|
-
|
|
175
|
-
_falsy: ClassVar[F_Bool | NoValue] = no_value
|
|
176
|
-
_lock: ClassVar[Lock] = Lock()
|
|
177
|
-
|
|
178
|
-
def __new__(
|
|
179
|
-
cls,
|
|
180
|
-
witness: object = NoValue(),
|
|
181
|
-
flavor: Hashable | NoValue = no_value,
|
|
182
|
-
) -> Self:
|
|
183
|
-
"""
|
|
184
|
-
.. admonition:: new
|
|
185
|
-
|
|
186
|
-
:param witness: Parameter ignored, an F_Bool is always falsy.
|
|
187
|
-
:param flavor: Parameter ignored, only one falsy "flavor".
|
|
188
|
-
:returns: The falsy F_Bool singleton instance.
|
|
189
|
-
|
|
190
|
-
"""
|
|
191
|
-
if cls._falsy is (no_value := NoValue()):
|
|
192
|
-
with cls._lock:
|
|
193
|
-
if cls._falsy is no_value:
|
|
194
|
-
cls._falsy = super(SBool, cls).__new__(cls, 0)
|
|
195
|
-
return cast(Self, cls._falsy)
|
|
196
|
-
|
|
197
|
-
def __and__(self, other: int) -> int:
|
|
198
|
-
if issubclass(type(other), TF_Bool):
|
|
199
|
-
return self
|
|
200
|
-
return super().__and__(other)
|
|
201
|
-
|
|
202
|
-
def __or__(self, other: int) -> int:
|
|
203
|
-
if issubclass(type(other), TF_Bool):
|
|
204
|
-
return other
|
|
205
|
-
return super().__or__(other)
|
|
206
|
-
|
|
207
|
-
def __xor__(self, other: int) -> int:
|
|
208
|
-
if issubclass(type(other), TF_Bool):
|
|
209
|
-
if other:
|
|
210
|
-
return other
|
|
211
|
-
return self
|
|
212
|
-
return super().__xor__(other)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
ALWAYS: Final[TF_Bool] = T_Bool()
|
|
216
|
-
"""
|
|
217
|
-
.. admonition:: ALWAYS
|
|
218
|
-
|
|
219
|
-
:var ALWAYS: The truthy singleton TF_Bool subtyped instance.
|
|
220
|
-
|
|
221
|
-
"""
|
|
222
|
-
|
|
223
|
-
NEVER: Final[TF_Bool] = F_Bool()
|
|
224
|
-
"""
|
|
225
|
-
.. admonition:: Never
|
|
226
|
-
|
|
227
|
-
:var NEVER: The falsy singleton TF_Bool subtyped instance.
|
|
228
|
-
|
|
229
|
-
"""
|
|
File without changes
|
|
File without changes
|