pythonic-fp-booleans 1.1.2__tar.gz → 2.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-2.0.0/CHANGELOG.rst +76 -0
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/PKG-INFO +10 -10
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/README.rst +4 -3
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/pyproject.toml +5 -6
- {pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypes → pythonic_fp_booleans-2.0.0/src/pythonic_fp/booleans}/__init__.py +19 -14
- {pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypes → pythonic_fp_booleans-2.0.0/src/pythonic_fp/booleans}/flavored.py +38 -46
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/src/pythonic_fp/booleans/subtypable.py +43 -22
- {pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypes → pythonic_fp_booleans-2.0.0/src/pythonic_fp/booleans}/truthy_falsy.py +21 -32
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_bool_vs_fbool.py +1 -1
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_flavored.py +1 -1
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_flavored_non_shortcut_logic.py +1 -1
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_flavored_sbool.py +1 -1
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_true_false.py +1 -1
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_true_false_non_shortcut_logic.py +2 -2
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_typing.py +2 -2
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_variance.py +2 -2
- pythonic_fp_booleans-1.1.2/CHANGELOG.rst +0 -46
- pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/__init__.py +0 -99
- pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypable.pyi +0 -18
- pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypes/flavored.pyi +0 -19
- pythonic_fp_booleans-1.1.2/src/pythonic_fp/booleans/subtypes/truthy_falsy.pyi +0 -21
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/.gitignore +0 -0
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/LICENSE +0 -0
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/src/pythonic_fp/booleans/py.typed +0 -0
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_bool_vs_sbool.py +0 -0
- {pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_subtypable_non_shortcut_logic.py +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
CHANGELOG
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
PyPI pythonic-fp-booleans project.
|
|
5
|
+
|
|
6
|
+
Semantic Versioning
|
|
7
|
+
-------------------
|
|
8
|
+
|
|
9
|
+
Strict 3 digit semantic versioning adopted 2025-05-19.
|
|
10
|
+
|
|
11
|
+
- **MAJOR** version incremented for incompatible API changes
|
|
12
|
+
- **MINOR** version incremented for backward compatible added functionality
|
|
13
|
+
- **PATCH** version incremented for backward compatible bug fixes
|
|
14
|
+
|
|
15
|
+
See `Semantic Versioning 2.0.0 <https://semver.org>`_.
|
|
16
|
+
|
|
17
|
+
Releases and Important Milestones
|
|
18
|
+
---------------------------------
|
|
19
|
+
|
|
20
|
+
PyPI 2.0.0 - 2025-09-27
|
|
21
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
22
|
+
|
|
23
|
+
Released to get the next consistent set of Pythonic FP out (v3.2.0) out.
|
|
24
|
+
|
|
25
|
+
- PyPI documentation link now goes to root, not releases
|
|
26
|
+
- decided to flatten directory structure
|
|
27
|
+
|
|
28
|
+
- makes more sense from an end user perspective
|
|
29
|
+
- will help Sphinx docs be more homogeneous across repos
|
|
30
|
+
|
|
31
|
+
Warning: API not fully locked down, major version number change may be needed.
|
|
32
|
+
|
|
33
|
+
TODO:
|
|
34
|
+
|
|
35
|
+
- bitwise operators not symmetric when used with ``SBool`` types and ``int`` or ``bool``
|
|
36
|
+
|
|
37
|
+
- may need to define reversed bit-wise operators
|
|
38
|
+
|
|
39
|
+
- ``TS_Boolean`` has a code smell to it
|
|
40
|
+
|
|
41
|
+
- may be just a hack to get get around sub-optimal type usage
|
|
42
|
+
- Using ``TS_Bool`` as a variable type may be enough
|
|
43
|
+
|
|
44
|
+
PyPI 1.1.2 - 2025-09-09
|
|
45
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
46
|
+
|
|
47
|
+
Fixed pyproject.toml dependency issues.
|
|
48
|
+
|
|
49
|
+
PyPI 1.1.1 - 2025-09-03
|
|
50
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
51
|
+
|
|
52
|
+
Only change was to give README.rst a final edit. Missed this on
|
|
53
|
+
the v1.1.0 release.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
PyPI 1.1.0 - 2025-09-02
|
|
57
|
+
~~~~~~~~~~~~~~~~~~~~~~~
|
|
58
|
+
|
|
59
|
+
First PyPI release as pythonic-fp-booleans.
|
|
60
|
+
|
|
61
|
+
- module booleans.subtypable
|
|
62
|
+
- package booleans.subtypes
|
|
63
|
+
|
|
64
|
+
- module booleans.subtypes.flavored
|
|
65
|
+
- module booleans.subtypes.truthy_falsy
|
|
66
|
+
|
|
67
|
+
Needs
|
|
68
|
+
|
|
69
|
+
- "pythonic-fp>=3.0.0" for gadgets
|
|
70
|
+
- "pythonic-fp-sentinels>=2.1.0",
|
|
71
|
+
|
|
72
|
+
Created pythonic-fp-boolean repo - 2025-08-06
|
|
73
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
74
|
+
|
|
75
|
+
- created grscheller/pythonic-fp-boolean GitHub repo
|
|
76
|
+
- moved pythonic_fp.singletons.sbool to pythonic_fp.booleans.sbool
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonic-fp-booleans
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Subtypable Boolean
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Subtypable Boolean Class Hierarchy
|
|
5
5
|
Keywords: booleans,subtypable
|
|
6
6
|
Author-email: "Geoffrey R. Scheller" <geoffrey@scheller.com>
|
|
7
7
|
Requires-Python: >=3.13
|
|
8
8
|
Description-Content-Type: text/x-rst
|
|
9
|
-
Classifier: Development Status ::
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
10
|
Classifier: Framework :: Pytest
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -14,12 +14,11 @@ Classifier: Operating System :: OS Independent
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Classifier: Typing :: Typed
|
|
16
16
|
License-File: LICENSE
|
|
17
|
-
Requires-Dist: pythonic-fp-gadgets>=3.
|
|
18
|
-
Requires-Dist: pythonic-fp-sentinels>=2.1.0
|
|
17
|
+
Requires-Dist: pythonic-fp-gadgets>=3.1.0
|
|
19
18
|
Requires-Dist: pytest>=8.4.1 ; extra == "test"
|
|
20
19
|
Project-URL: Changelog, https://github.com/grscheller/pythonic-fp-booleans/blob/main/CHANGELOG.rst
|
|
21
|
-
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/booleans/development/build/html/
|
|
22
|
-
Project-URL: Homepage, https://github.
|
|
20
|
+
Project-URL: Documentation, https://grscheller.github.io/pythonic-fp/booleans/development/build/html/
|
|
21
|
+
Project-URL: Homepage, https://grscheller.github.io/pythonic-fp/homepage/build/html/
|
|
23
22
|
Project-URL: Source, https://github.com/grscheller/pythonic-fp-booleans
|
|
24
23
|
Provides-Extra: test
|
|
25
24
|
|
|
@@ -35,9 +34,10 @@ Subtypable Boolean like classes.
|
|
|
35
34
|
While still compatible with Python shortcut logic, these classes can be non-shortcut logically
|
|
36
35
|
composed with Python’s bitwise operators.
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
`pythonic-fp
|
|
40
|
-
<https://github.
|
|
37
|
+
Part of the
|
|
38
|
+
`pythonic-fp
|
|
39
|
+
<https://grscheller.github.io/pythonic-fp/homepage/build/html/index.html>`_
|
|
40
|
+
PyPI projects.
|
|
41
41
|
|
|
42
42
|
Documentation
|
|
43
43
|
-------------
|
|
@@ -10,9 +10,10 @@ Subtypable Boolean like classes.
|
|
|
10
10
|
While still compatible with Python shortcut logic, these classes can be non-shortcut logically
|
|
11
11
|
composed with Python’s bitwise operators.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
`pythonic-fp
|
|
15
|
-
<https://github.
|
|
13
|
+
Part of the
|
|
14
|
+
`pythonic-fp
|
|
15
|
+
<https://grscheller.github.io/pythonic-fp/homepage/build/html/index.html>`_
|
|
16
|
+
PyPI projects.
|
|
16
17
|
|
|
17
18
|
Documentation
|
|
18
19
|
-------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pythonic-fp-booleans"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
readme = "README.rst"
|
|
5
5
|
requires-python = ">=3.13"
|
|
6
6
|
license = { file = "LICENSE" }
|
|
@@ -10,7 +10,7 @@ keywords = [
|
|
|
10
10
|
"subtypable",
|
|
11
11
|
]
|
|
12
12
|
classifiers = [
|
|
13
|
-
"Development Status ::
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
14
|
"Framework :: Pytest",
|
|
15
15
|
"Intended Audience :: Developers",
|
|
16
16
|
"License :: OSI Approved :: Apache Software License",
|
|
@@ -19,15 +19,14 @@ classifiers = [
|
|
|
19
19
|
"Typing :: Typed",
|
|
20
20
|
]
|
|
21
21
|
dependencies = [
|
|
22
|
-
"pythonic-fp-gadgets>=3.
|
|
23
|
-
"pythonic-fp-sentinels>=2.1.0",
|
|
22
|
+
"pythonic-fp-gadgets>=3.1.0",
|
|
24
23
|
]
|
|
25
24
|
dynamic = ["description"]
|
|
26
25
|
|
|
27
26
|
[project.urls]
|
|
28
27
|
Changelog = "https://github.com/grscheller/pythonic-fp-booleans/blob/main/CHANGELOG.rst"
|
|
29
|
-
Documentation = "https://grscheller.github.io/pythonic-fp/booleans/development/build/html/
|
|
30
|
-
Homepage = "https://github.
|
|
28
|
+
Documentation = "https://grscheller.github.io/pythonic-fp/booleans/development/build/html/"
|
|
29
|
+
Homepage = "https://grscheller.github.io/pythonic-fp/homepage/build/html/"
|
|
31
30
|
Source = "https://github.com/grscheller/pythonic-fp-booleans"
|
|
32
31
|
|
|
33
32
|
[project.optional-dependencies]
|
|
@@ -13,23 +13,28 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Subtypable Boolean Class Hierarchy
|
|
17
|
+
==================================
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
---------------
|
|
19
|
+
.. graphviz::
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
digraph Booleans {
|
|
22
|
+
bgcolor="#957fb8";
|
|
23
|
+
node [style=filled, fillcolor="#181616", fontcolor="#dcd7ba"];
|
|
24
|
+
edge [color="#181616", fontcolor="#dcd7ba"];
|
|
25
|
+
int -> bool;
|
|
26
|
+
int -> SBool;
|
|
27
|
+
SBool -> "FBool(h1)";
|
|
28
|
+
SBool -> "FBool(h2)";
|
|
29
|
+
SBool -> "FBool(h3)";
|
|
30
|
+
SBool -> TF_Bool;
|
|
31
|
+
TF_Bool -> T_Bool;
|
|
32
|
+
TF_Bool -> F_Bool;
|
|
33
|
+
}
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- where truthy and falsy are typeable
|
|
29
|
-
- class ``TF_Bool`` consists of two disjoint subclasses
|
|
30
|
-
|
|
31
|
-
- ``T_Bool`` instances are always truthy
|
|
32
|
-
- ``F_Bool`` instances are always falsy
|
|
35
|
+
While still compatible with Python shortcut logic, ``SBool`` and its
|
|
36
|
+
subclasses can be non-shortcut logically composed with Python's bitwise
|
|
37
|
+
operators.
|
|
33
38
|
"""
|
|
34
39
|
|
|
35
40
|
__author__ = 'Geoffrey R. Scheller'
|
|
@@ -12,42 +12,46 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
"""
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
**Class F_Bool.**
|
|
17
|
+
|
|
18
|
+
When different flavors of the truth matter. Each ``FBool`` is
|
|
19
|
+
an ``SBool`` subtype corresponds to a hashable value
|
|
20
|
+
called its flavor.
|
|
21
|
+
|
|
22
|
+
.. warning::
|
|
23
|
+
|
|
24
|
+
Combining ``FBool`` instances of different flavors
|
|
25
|
+
with bitwise operators will just result in an ``SBool``.
|
|
26
|
+
|
|
27
|
+
----
|
|
28
|
+
|
|
29
|
+
**Function truthy(flavor: Hashable)**
|
|
19
30
|
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
Returns the truthy ``FBool`` of a particular ``flavor``.
|
|
32
|
+
|
|
33
|
+
----
|
|
34
|
+
|
|
35
|
+
**Function falsy(flavor: Hashable)**
|
|
36
|
+
|
|
37
|
+
Returns the falsy ``FBool`` of a particular ``flavor``.
|
|
22
38
|
"""
|
|
23
39
|
|
|
24
40
|
import threading
|
|
25
41
|
from collections.abc import Hashable
|
|
26
42
|
from typing import ClassVar, final
|
|
27
|
-
from
|
|
43
|
+
from .subtypable import SBool
|
|
28
44
|
|
|
29
45
|
__all__ = ['FBool', 'truthy', 'falsy']
|
|
30
46
|
|
|
31
47
|
|
|
32
48
|
@final
|
|
33
49
|
class FBool(SBool):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
----------------
|
|
50
|
+
_falsy_dict: 'ClassVar[dict[Hashable, FBool]]' = {}
|
|
51
|
+
_falsy_dict_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
37
52
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
This type can also do (non-shortcut) Boolean logic using Python
|
|
42
|
-
bitwise operators. Combining ``FBool`` instances of different
|
|
43
|
-
flavors in this way will just result in an ``SBool``.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
_truthy: 'ClassVar[dict[Hashable, FBool]]' = {}
|
|
47
|
-
_truthy_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
48
|
-
|
|
49
|
-
_falsy: 'ClassVar[dict[Hashable, FBool]]' = {}
|
|
50
|
-
_falsy_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
53
|
+
_truthy_dict: 'ClassVar[dict[Hashable, FBool]]' = {}
|
|
54
|
+
_truthy_dict_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
51
55
|
|
|
52
56
|
def __new__(cls, witness: object, flavor: Hashable) -> 'FBool':
|
|
53
57
|
"""
|
|
@@ -56,22 +60,21 @@ class FBool(SBool):
|
|
|
56
60
|
:returns: The truthy or falsy ``FBool`` instance of a particular ``flavor``.
|
|
57
61
|
"""
|
|
58
62
|
if witness:
|
|
59
|
-
if flavor not in cls.
|
|
63
|
+
if flavor not in cls._truthy_dict:
|
|
60
64
|
with cls._truthy_lock:
|
|
61
|
-
if flavor not in cls.
|
|
62
|
-
cls.
|
|
63
|
-
return cls.
|
|
65
|
+
if flavor not in cls._truthy_dict:
|
|
66
|
+
cls._truthy_dict[flavor] = super(SBool, cls).__new__(cls, True)
|
|
67
|
+
return cls._truthy_dict[flavor]
|
|
64
68
|
else:
|
|
65
|
-
if flavor not in cls.
|
|
66
|
-
with cls.
|
|
67
|
-
if flavor not in cls.
|
|
68
|
-
cls.
|
|
69
|
-
return cls.
|
|
69
|
+
if flavor not in cls._falsy_dict:
|
|
70
|
+
with cls._falsy_dict_lock:
|
|
71
|
+
if flavor not in cls._falsy_dict:
|
|
72
|
+
cls._falsy_dict[flavor] = super(SBool, cls).__new__(cls, False)
|
|
73
|
+
return cls._falsy_dict[flavor]
|
|
70
74
|
|
|
71
75
|
def __init__(self, witness: object, flavor: Hashable) -> None:
|
|
72
76
|
self._flavor = flavor
|
|
73
77
|
|
|
74
|
-
# override in derived classes
|
|
75
78
|
def __repr__(self) -> str:
|
|
76
79
|
if self:
|
|
77
80
|
return f'FBool(True, {repr(self._flavor)})'
|
|
@@ -110,34 +113,23 @@ class FBool(SBool):
|
|
|
110
113
|
return self ^ other
|
|
111
114
|
|
|
112
115
|
def flavor(self) -> Hashable:
|
|
113
|
-
"""
|
|
116
|
+
"""
|
|
114
117
|
:returns: The flavor of the FBool.
|
|
115
|
-
|
|
116
118
|
"""
|
|
117
119
|
return self._flavor
|
|
118
120
|
|
|
119
121
|
|
|
120
122
|
def truthy(flavor: Hashable) -> FBool:
|
|
121
123
|
"""
|
|
122
|
-
Get truthy FBool
|
|
123
|
-
----------------
|
|
124
|
-
|
|
125
|
-
Get the truthy ``FBool`` of a particular ``flavor``.
|
|
126
|
-
|
|
127
124
|
:param flavor: Hashable value to determine which singleton ``flavor`` to return.
|
|
128
|
-
:returns: The truthy singleton of a particular
|
|
125
|
+
:returns: The truthy singleton of a particular ``flavor``.
|
|
129
126
|
"""
|
|
130
127
|
return FBool(True, flavor)
|
|
131
128
|
|
|
132
129
|
|
|
133
130
|
def falsy(flavor: Hashable) -> FBool:
|
|
134
131
|
"""
|
|
135
|
-
Get falsy FBool
|
|
136
|
-
---------------
|
|
137
|
-
|
|
138
|
-
Get the falsy ``FBool`` of a particular ``flavor``.
|
|
139
|
-
|
|
140
132
|
:param flavor: Hashable value to determine which singleton ``flavor`` to return.
|
|
141
|
-
:returns: The falsy singleton of a particular
|
|
133
|
+
:returns: The falsy singleton of a particular ``flavor``.
|
|
142
134
|
"""
|
|
143
135
|
return FBool(False, flavor)
|
{pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/src/pythonic_fp/booleans/subtypable.py
RENAMED
|
@@ -12,14 +12,52 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
"""
|
|
16
|
+
**Subtypable Boolean.**
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Like Python's built in bool, class ``SBool`` is a subclass of int.
|
|
19
|
+
Unlike bool, this version can be further subclassed.
|
|
20
|
+
|
|
21
|
+
This type and its subtypes can also do (non-shortcut) Boolean logic
|
|
22
|
+
using Python bitwise operators.
|
|
23
|
+
|
|
24
|
+
+-------------------+--------+------------+
|
|
25
|
+
| Boolean operation | symbol | dunder |
|
|
26
|
+
+===================+========+============+
|
|
27
|
+
| not | ``~`` | __invert__ |
|
|
28
|
+
+-------------------+--------+------------+
|
|
29
|
+
| and | ``&`` | __and__ |
|
|
30
|
+
+-------------------+--------+------------+
|
|
31
|
+
| or | ``|`` | __or__ |
|
|
32
|
+
+-------------------+--------+------------+
|
|
33
|
+
| xor | ``^`` | __xor__ |
|
|
34
|
+
+-------------------+--------+------------+
|
|
35
|
+
|
|
36
|
+
.. note::
|
|
37
|
+
|
|
38
|
+
These operators are contravariant, that is they will return the
|
|
39
|
+
instance of the latest common ancestor of their arguments. More
|
|
40
|
+
specifically, the instance returned will have the type of the
|
|
41
|
+
least upper bound in the inheritance graph of the classes of
|
|
42
|
+
the two arguments.
|
|
43
|
+
|
|
44
|
+
While compatible with Python short-cut logic. Unfortunately, the
|
|
45
|
+
``not`` operator always returns a ``bool``. Use the bitwise ``~``
|
|
46
|
+
operator to return an opposite ``SBool`` class or subclass.
|
|
47
|
+
|
|
48
|
+
.. warning::
|
|
49
|
+
|
|
50
|
+
The "bitwise" operators can raise ``TypeError`` exceptions
|
|
51
|
+
when applied against an ``SBool`` and objects not descended
|
|
52
|
+
from ``int``.
|
|
53
|
+
|
|
54
|
+
"""
|
|
17
55
|
|
|
18
56
|
import threading
|
|
19
57
|
from collections.abc import Hashable
|
|
20
58
|
from typing import cast, ClassVar, Final, overload
|
|
21
59
|
from pythonic_fp.gadgets.latest_common_ancestor import lca
|
|
22
|
-
from pythonic_fp.sentinels.novalue import NoValue
|
|
60
|
+
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
23
61
|
|
|
24
62
|
__all__ = ['SBool', 'TRUTH', 'LIE']
|
|
25
63
|
|
|
@@ -27,17 +65,6 @@ _novalue = NoValue()
|
|
|
27
65
|
|
|
28
66
|
|
|
29
67
|
class SBool(int):
|
|
30
|
-
"""Subtypable Booleans.
|
|
31
|
-
|
|
32
|
-
Like Python's built in bool, class SBool is a subclass of int.
|
|
33
|
-
Unlike bool, this version can be further subclassed. It can be
|
|
34
|
-
used with Python ``and`` and ``or`` short-cut logic. The ``not``
|
|
35
|
-
operator will just return a ``bool``. Use the ``snot`` function
|
|
36
|
-
to return an ``SBool`` or ``SBool`` subclass.
|
|
37
|
-
|
|
38
|
-
This type and its subtypes can also do (non-shortcut) Boolean logic
|
|
39
|
-
using Python bitwise operators.
|
|
40
|
-
"""
|
|
41
68
|
_falsy: 'ClassVar[SBool | NoValue]' = _novalue
|
|
42
69
|
_falsy_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
43
70
|
|
|
@@ -88,9 +115,7 @@ class SBool(int):
|
|
|
88
115
|
if type(other) is bool:
|
|
89
116
|
base_class = int
|
|
90
117
|
else:
|
|
91
|
-
msg = (
|
|
92
|
-
f"unsupported operand type(s) for &: '{type(self)}' and '{type(other)}'"
|
|
93
|
-
)
|
|
118
|
+
msg = f"unsupported operand type(s) for &: '{type(self)}' and '{type(other)}'"
|
|
94
119
|
raise TypeError(msg)
|
|
95
120
|
|
|
96
121
|
if issubclass(base_class, SBool):
|
|
@@ -107,9 +132,7 @@ class SBool(int):
|
|
|
107
132
|
if type(other) is bool:
|
|
108
133
|
base_class = int
|
|
109
134
|
else:
|
|
110
|
-
msg = (
|
|
111
|
-
f"unsupported operand type(s) for |: '{type(self)}' and '{type(other)}'"
|
|
112
|
-
)
|
|
135
|
+
msg = f"unsupported operand type(s) for |: '{type(self)}' and '{type(other)}'"
|
|
113
136
|
raise TypeError(msg)
|
|
114
137
|
|
|
115
138
|
if issubclass(base_class, SBool):
|
|
@@ -126,9 +149,7 @@ class SBool(int):
|
|
|
126
149
|
if type(other) is bool:
|
|
127
150
|
base_class = int
|
|
128
151
|
else:
|
|
129
|
-
msg = (
|
|
130
|
-
f"unsupported operand type(s) for ^: '{type(self)}' and '{type(other)}'"
|
|
131
|
-
)
|
|
152
|
+
msg = f"unsupported operand type(s) for ^: '{type(self)}' and '{type(other)}'"
|
|
132
153
|
raise TypeError(msg)
|
|
133
154
|
|
|
134
155
|
if issubclass(base_class, SBool):
|
|
@@ -12,19 +12,33 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
16
15
|
"""
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
**Class TF_Bool**
|
|
17
|
+
|
|
18
|
+
Subclass of ``SBool`` whose truthy values and falsy values are
|
|
19
|
+
different distinct singleton subtypes.
|
|
20
|
+
|
|
21
|
+
This type can also do (non-shortcut) Boolean logic using Python
|
|
22
|
+
bitwise operators.
|
|
23
|
+
|
|
24
|
+
----
|
|
19
25
|
|
|
26
|
+
**Class T_Bool**
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
The subtype of ``TF_Bool`` which is always truthy.
|
|
29
|
+
|
|
30
|
+
----
|
|
31
|
+
|
|
32
|
+
**Class F_Bool**
|
|
33
|
+
|
|
34
|
+
The subtype of ``TF_Bool`` which is always falsy.
|
|
35
|
+
"""
|
|
22
36
|
|
|
23
37
|
import threading
|
|
24
38
|
from collections.abc import Hashable
|
|
25
39
|
from typing import cast, ClassVar, Final, final
|
|
26
|
-
from pythonic_fp.sentinels.novalue import NoValue
|
|
27
|
-
from
|
|
40
|
+
from pythonic_fp.gadgets.sentinels.novalue import NoValue
|
|
41
|
+
from .subtypable import SBool
|
|
28
42
|
|
|
29
43
|
__all__ = [
|
|
30
44
|
'TF_Bool',
|
|
@@ -39,22 +53,11 @@ _novalue = NoValue()
|
|
|
39
53
|
|
|
40
54
|
|
|
41
55
|
class TF_Bool(SBool):
|
|
42
|
-
"""
|
|
43
|
-
Truthy-Falsy Boolean
|
|
44
|
-
--------------------
|
|
45
|
-
|
|
46
|
-
Subclass of ``SBool`` whose truthy values and falsy values are
|
|
47
|
-
different singleton subtypes.
|
|
48
|
-
|
|
49
|
-
This type can also do (non-shortcut) Boolean logic using Python
|
|
50
|
-
bitwise operators.
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
56
|
def __new__(cls, witness: object, flavor: Hashable = NoValue()) -> 'TF_Bool':
|
|
54
57
|
"""
|
|
55
58
|
:param witness: Determines which subtype, ``T_Bool`` or ``F_Bool`` is returned.
|
|
56
59
|
:param flavor: Ignored parameter, only two flavors, one truthy and one falsy.
|
|
57
|
-
:returns:
|
|
60
|
+
:returns: Either The singleton truthy or singleton falsy subtypes.
|
|
58
61
|
"""
|
|
59
62
|
if witness:
|
|
60
63
|
return T_Bool()
|
|
@@ -94,13 +97,6 @@ class TF_Bool(SBool):
|
|
|
94
97
|
|
|
95
98
|
@final
|
|
96
99
|
class T_Bool(TF_Bool):
|
|
97
|
-
"""
|
|
98
|
-
Truthy TF_Bool
|
|
99
|
-
--------------
|
|
100
|
-
|
|
101
|
-
The subtype of ``TF_Bool`` which is always truthy.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
100
|
_truthy: 'ClassVar[T_Bool | NoValue]' = _novalue
|
|
105
101
|
_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
106
102
|
|
|
@@ -126,13 +122,6 @@ class T_Bool(TF_Bool):
|
|
|
126
122
|
|
|
127
123
|
@final
|
|
128
124
|
class F_Bool(TF_Bool):
|
|
129
|
-
"""
|
|
130
|
-
Falsy TF_Bool
|
|
131
|
-
-------------
|
|
132
|
-
|
|
133
|
-
The subtype of ``TF_Bool`` which is always falsy.
|
|
134
|
-
"""
|
|
135
|
-
|
|
136
125
|
_falsy: 'ClassVar[F_Bool | NoValue]' = _novalue
|
|
137
126
|
_lock: ClassVar[threading.Lock] = threading.Lock()
|
|
138
127
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from pythonic_fp.booleans.subtypable import SBool, TRUTH, LIE
|
|
16
|
-
from pythonic_fp.booleans.
|
|
16
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
17
17
|
|
|
18
18
|
class TestBooleanBehaviors():
|
|
19
19
|
def test_bool(self) -> None:
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from pythonic_fp.booleans.
|
|
15
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
16
16
|
from pythonic_fp.booleans.subtypable import TRUTH, LIE
|
|
17
17
|
|
|
18
18
|
t0_1 = FBool(1 == 1, 0)
|
{pythonic_fp_booleans-1.1.2 → pythonic_fp_booleans-2.0.0}/tests/test_flavored_non_shortcut_logic.py
RENAMED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from pythonic_fp.booleans.subtypable import TRUTH, LIE
|
|
16
|
-
from pythonic_fp.booleans.
|
|
16
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class TestBitwiseOperations():
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from pythonic_fp.booleans.
|
|
15
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
16
16
|
from pythonic_fp.booleans.subtypable import SBool, TRUTH, LIE
|
|
17
17
|
|
|
18
18
|
fbt0_1 = FBool(1 == 1, 0)
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from pythonic_fp.booleans.subtypable import TRUTH, LIE
|
|
16
|
-
from pythonic_fp.booleans.
|
|
17
|
-
from pythonic_fp.booleans.
|
|
16
|
+
from pythonic_fp.booleans.truthy_falsy import TF_Boolean, TF_Bool, T_Bool, F_Bool
|
|
17
|
+
from pythonic_fp.booleans.truthy_falsy import ALWAYS, NEVER
|
|
18
18
|
|
|
19
19
|
false0: TF_Boolean = F_Bool('ignored', 'also ignored')
|
|
20
20
|
false1: TF_Boolean = TF_Bool(1 > 42)
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
from pythonic_fp.booleans.subtypable import SBool
|
|
16
|
-
from pythonic_fp.booleans.
|
|
17
|
-
from pythonic_fp.booleans.
|
|
16
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
17
|
+
from pythonic_fp.booleans.truthy_falsy import TF_Bool, T_Bool, F_Bool
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class TestInvert:
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from pythonic_fp.booleans.
|
|
16
|
-
from pythonic_fp.booleans.
|
|
15
|
+
from pythonic_fp.booleans.truthy_falsy import TF_Bool, TF_Boolean, T_Bool, F_Bool, ALWAYS, NEVER
|
|
16
|
+
from pythonic_fp.booleans.flavored import FBool, truthy, falsy
|
|
17
17
|
from pythonic_fp.booleans.subtypable import SBool, TRUTH, LIE
|
|
18
18
|
|
|
19
19
|
class TestBoolWithInt():
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
CHANGELOG
|
|
2
|
-
=========
|
|
3
|
-
|
|
4
|
-
PyPI pythonic-fp-booleans project.
|
|
5
|
-
|
|
6
|
-
Semantic Versioning
|
|
7
|
-
-------------------
|
|
8
|
-
|
|
9
|
-
Strict 3 digit semantic versioning adopted 2025-05-19.
|
|
10
|
-
|
|
11
|
-
- **MAJOR** version incremented for incompatible API changes
|
|
12
|
-
- **MINOR** version incremented for backward compatible added functionality
|
|
13
|
-
- **PATCH** version incremented for backward compatible bug fixes
|
|
14
|
-
|
|
15
|
-
See `Semantic Versioning 2.0.0 <https://semver.org>`_.
|
|
16
|
-
|
|
17
|
-
Releases and Important Milestones
|
|
18
|
-
---------------------------------
|
|
19
|
-
|
|
20
|
-
PyPI v1.1.1 - 2025-09-03
|
|
21
|
-
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
22
|
-
|
|
23
|
-
Only change was to give README.rst a final edit. Missed this on
|
|
24
|
-
the v1.1.0 release.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
PyPI v1.1.0 - 2025-09-02
|
|
28
|
-
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
29
|
-
|
|
30
|
-
First PyPI release as pythonic-fp-booleans.
|
|
31
|
-
|
|
32
|
-
- module booleans.subtypable
|
|
33
|
-
- package booleans.subtypes
|
|
34
|
-
|
|
35
|
-
- module booleans.subtypes.flavored
|
|
36
|
-
- module booleans.subtypes.truthy_falsy
|
|
37
|
-
|
|
38
|
-
Needs
|
|
39
|
-
|
|
40
|
-
- "pythonic-fp>=3.0.0" for gadgets
|
|
41
|
-
- "pythonic-fp-sentinels>=2.1.0",
|
|
42
|
-
|
|
43
|
-
Created pythonic-fp-boolean GitHub repo - 2025-08-06
|
|
44
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
45
|
-
|
|
46
|
-
Moved pythonic_fp.singletons.sbool -> pythonic_fp.booleans.sbool
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# Copyright 2023-2025 Geoffrey R. Scheller
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
"""
|
|
16
|
-
Subtypable Boolean like classes
|
|
17
|
-
===============================
|
|
18
|
-
|
|
19
|
-
While still compatible with Python shortcut logic, these classes can
|
|
20
|
-
be non-shortcut logically composed with Python's bitwise operators.
|
|
21
|
-
These classes are implemented with the Singleton Pattern.
|
|
22
|
-
|
|
23
|
-
Covariant class hierarchy
|
|
24
|
-
-------------------------
|
|
25
|
-
|
|
26
|
-
.. graphviz::
|
|
27
|
-
|
|
28
|
-
digraph Booleans {
|
|
29
|
-
bgcolor="deepskyblue";
|
|
30
|
-
int -> bool;
|
|
31
|
-
int -> SBool;
|
|
32
|
-
SBool -> "FBool(h1)";
|
|
33
|
-
SBool -> "FBool(h2)";
|
|
34
|
-
SBool -> "FBool(h3)";
|
|
35
|
-
SBool -> TF_Bool;
|
|
36
|
-
TF_Bool -> T_Bool;
|
|
37
|
-
TF_Bool -> F_Bool;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
Contravariant non-shortcut "bitwise" operators
|
|
41
|
-
----------------------------------------------
|
|
42
|
-
|
|
43
|
-
+-------------------+--------+------------+
|
|
44
|
-
| Boolean operation | symbol | dunder |
|
|
45
|
-
+===================+========+============+
|
|
46
|
-
| not | ``~`` | __invert__ |
|
|
47
|
-
+-------------------+--------+------------+
|
|
48
|
-
| and | ``&`` | __and__ |
|
|
49
|
-
+-------------------+--------+------------+
|
|
50
|
-
| or | ``|`` | __or__ |
|
|
51
|
-
+-------------------+--------+------------+
|
|
52
|
-
| xor | ``^`` | __xor__ |
|
|
53
|
-
+-------------------+--------+------------+
|
|
54
|
-
|
|
55
|
-
These operators are contravariant, that is they will return
|
|
56
|
-
the instance of the latest common ancestor of their arguments.
|
|
57
|
-
More specifically, the instance returned will have the type
|
|
58
|
-
of the least upper bound in the inheritance graph of the classes
|
|
59
|
-
of the two arguments.
|
|
60
|
-
|
|
61
|
-
.. warning::
|
|
62
|
-
|
|
63
|
-
These "bitwise" operators could raise ``TypeError`` exceptions
|
|
64
|
-
when applied against an ``SBool`` and objects not descended
|
|
65
|
-
from ``int``.
|
|
66
|
-
|
|
67
|
-
Classes
|
|
68
|
-
-------
|
|
69
|
-
|
|
70
|
-
Class SBool
|
|
71
|
-
~~~~~~~~~~~
|
|
72
|
-
|
|
73
|
-
Base of the hierarchy.
|
|
74
|
-
|
|
75
|
-
Like Python's built-in ``bool``, ``SBool`` is a subclass of ``int``,
|
|
76
|
-
unlike ``bool``, class ``SBool`` can be further subclassed.
|
|
77
|
-
|
|
78
|
-
Class FBool
|
|
79
|
-
~~~~~~~~~~~
|
|
80
|
-
|
|
81
|
-
For when you need to deal with different "flavors" of the truth.
|
|
82
|
-
|
|
83
|
-
Each "flavor" corresponds to a hashable value. Instances of ``FBool``
|
|
84
|
-
are invariant in their flavor. Best to think of the "flavor" as an
|
|
85
|
-
index.
|
|
86
|
-
|
|
87
|
-
Class TF_Bool
|
|
88
|
-
~~~~~~~~~~~~~
|
|
89
|
-
|
|
90
|
-
Class ``TF_Bool`` consists of just two disjoint subclasses, each one
|
|
91
|
-
a singleton.
|
|
92
|
-
|
|
93
|
-
- class ``T_Bool`` is the always truthy ``TF_Bool`` subtype
|
|
94
|
-
- class ``F_Bool`` is the always falsy ``TF_Bool`` subtype
|
|
95
|
-
"""
|
|
96
|
-
|
|
97
|
-
__author__ = 'Geoffrey R. Scheller'
|
|
98
|
-
__copyright__ = 'Copyright (c) 2025 Geoffrey R. Scheller'
|
|
99
|
-
__license__ = 'Apache License 2.0'
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from collections.abc import Hashable
|
|
2
|
-
from typing import Final, overload
|
|
3
|
-
|
|
4
|
-
__all__ = ['SBool', 'TRUTH', 'LIE']
|
|
5
|
-
|
|
6
|
-
class SBool(int):
|
|
7
|
-
@overload
|
|
8
|
-
def __new__(cls) -> SBool: ...
|
|
9
|
-
@overload
|
|
10
|
-
def __new__(cls, witness: object) -> SBool: ...
|
|
11
|
-
def __init__(self, witness: object = False, flavor: Hashable = ...) -> None: ...
|
|
12
|
-
def __invert__(self) -> SBool: ...
|
|
13
|
-
def __and__(self, other: int) -> int: ...
|
|
14
|
-
def __or__(self, other: int) -> int: ...
|
|
15
|
-
def __xor__(self, other: int) -> int: ...
|
|
16
|
-
|
|
17
|
-
TRUTH: Final[SBool]
|
|
18
|
-
LIE: Final[SBool]
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
from ..subtypable import SBool
|
|
2
|
-
from collections.abc import Hashable
|
|
3
|
-
|
|
4
|
-
__all__ = ['FBool', 'truthy', 'falsy']
|
|
5
|
-
|
|
6
|
-
class FBool(SBool):
|
|
7
|
-
def __new__(cls, witness: object, flavor: Hashable) -> FBool: ...
|
|
8
|
-
def __init__(self, witness: object, flavor: Hashable) -> None: ...
|
|
9
|
-
def __invert__(self) -> FBool: ...
|
|
10
|
-
def __and__(self, other: int) -> SBool: ...
|
|
11
|
-
def __rand__(self, other: int) -> SBool: ...
|
|
12
|
-
def __or__(self, other: int) -> SBool: ...
|
|
13
|
-
def __ror__(self, other: int) -> SBool: ...
|
|
14
|
-
def __xor__(self, other: int) -> SBool: ...
|
|
15
|
-
def __rxor__(self, other: int) -> SBool: ...
|
|
16
|
-
def flavor(self) -> Hashable: ...
|
|
17
|
-
|
|
18
|
-
def truthy(flavor: Hashable) -> FBool: ...
|
|
19
|
-
def falsy(flavor: Hashable) -> FBool: ...
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from ..subtypable import SBool
|
|
2
|
-
from collections.abc import Hashable
|
|
3
|
-
from typing import Final
|
|
4
|
-
|
|
5
|
-
__all__ = ['TF_Bool', 'T_Bool', 'F_Bool', 'ALWAYS', 'NEVER', 'TF_Boolean']
|
|
6
|
-
|
|
7
|
-
class TF_Bool(SBool):
|
|
8
|
-
def __new__(cls, witness: object, flavor: Hashable = ...) -> TF_Bool: ...
|
|
9
|
-
def __invert__(self) -> TF_Bool: ...
|
|
10
|
-
def __and__(self, other: int) -> SBool: ...
|
|
11
|
-
def __or__(self, other: int) -> SBool: ...
|
|
12
|
-
def __xor__(self, other: int) -> SBool: ...
|
|
13
|
-
|
|
14
|
-
class T_Bool(TF_Bool):
|
|
15
|
-
def __new__(cls, witness: object = ..., flavor: Hashable = ...) -> T_Bool: ...
|
|
16
|
-
|
|
17
|
-
class F_Bool(TF_Bool):
|
|
18
|
-
def __new__(cls, witness: object = ..., flavor: Hashable = ...) -> F_Bool: ...
|
|
19
|
-
TF_Boolean = T_Bool | F_Bool | TF_Bool
|
|
20
|
-
ALWAYS: Final[TF_Boolean]
|
|
21
|
-
NEVER: Final[TF_Boolean]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|