Repository: lmfit/uncertainties

Issue:
Should `UFloat.__bool__` be removed?
Previously, if `x = ufloat(1, 0.1)` then `x.__bool__()` was equivalent to `x == 0`. This was in turn equivalent to `x.n == 0 and x.s == 0`. However, the resolution to #310 is looking like it is going to eliminate equality comparison between `UFloat` and `float` (or it will always return `False` or something). This leaves us with the following options for `UFloat.__bool__`:

1. Remove `UFloat.__bool__`. Thinking of `UFloat` as a random variable, it doesn't make sense to talk about a boolean value for a `UFloat`.
2. Define `__bool__` to be `x.n == 0 and x.s == 0`. this will be backwards compatible
3. Define `__bool__` to be `x.n == 0`

These are in order of my preference. If we decide to remove it we should include a deprecation warning for it right away.

Hints from issue comments:
@wshanks: I am okay with option 1 since we have agreed on only partially supporting standard deviation of 0. I am okay with option 2 as well.@newville: I vote for Option 1. 

Solution patch:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..dd5fd15
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,44 @@
+name: Upload Python Package
+
+on:
+  release:
+    types: [published]
+
+permissions:
+  contents: read
+
+jobs:
+  release-build:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.x"
+      - name: Build release distributions
+        run: |
+          python -m pip install build
+          python -m build
+      - name: Upload distributions
+        uses: actions/upload-artifact@v4
+        with:
+          name: release-dists
+          path: dist/
+
+  pypi-publish:
+    runs-on: ubuntu-latest
+    needs:
+      - release-build
+    permissions:
+      id-token: write
+    environment:
+      name: pypi-publish
+      url: https://pypi.org/project/uncertainties/
+    steps:
+      - name: Retrieve release distributions
+        uses: actions/download-artifact@v4
+        with:
+          name: release-dists
+          path: dist/
+      - name: Publish release distributions to PyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/.github/workflows/python-package.yml b/.github/workflows/test.yml
similarity index 99%
rename from .github/workflows/python-package.yml
rename to .github/workflows/test.yml
index 6c10ad5..a5d95b3 100644
--- a/.github/workflows/python-package.yml
+++ b/.github/workflows/test.yml
@@ -1,7 +1,7 @@
 # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
 # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
 
-name: Python package
+name: Run Tests
 
 on:
   push:
diff --git a/CHANGES.rst b/CHANGES.rst
index 2e15dbc..1a15b82 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -6,6 +6,10 @@ Unreleased
 
 Fixes:
 
+Adds:
+
+- Add github action CI to automatically publish a new package version to ``pypi`` when
+   a github release of a new version is published.
 - Increases the stacklevel of the warning about `std_dev==0` so that it blames
   the caller rather than blaming the `ufloat()` function.
 - Adjusts the Sphinx configuration to allow for reproducible builds using
@@ -58,7 +62,7 @@ Deprecates:
    `floor`, `fmod`, `frexp`, `ldexp`, `modf`, `trunc`. The following
    `AffineScalarFunc`/`UFloat` methods are marked as deprecated:
    `__floordiv__`, `__mod__`, `__abs__`, `__trunc__`, `__lt__`,
-   `__le__`, `__gt__`, `__ge__`.
+   `__le__`, `__gt__`, `__ge__`, `__bool__`.
 
 3.2.2   2024-July-08
 -----------------------
diff --git a/uncertainties/ops.py b/uncertainties/ops.py
index 53e64c8..5df483a 100644
--- a/uncertainties/ops.py
+++ b/uncertainties/ops.py
@@ -5,6 +5,7 @@ import sys
 import itertools
 from inspect import getfullargspec
 import numbers
+from warnings import warn
 
 # Some types known to not depend on Variable objects are put in
 # CONSTANT_TYPES.  The most common types can be put in front, as this
@@ -806,6 +807,11 @@ def add_comparative_ops(cls):
         # __nonzero__ works fine if subtracting the 0 float from a
         # vector of the linear space works as if 0 were the null
         # vector of that space):
+        msg = (
+            f"{self.__class__.__name__}.__bool__() is deprecated. In future releases "
+            f"it will defer to object.__bool__() and always return True."
+        )
+        warn(msg, FutureWarning, stacklevel=2)
         return self != 0.0  # Uses the AffineScalarFunc.__ne__ function
 
     cls.__bool__ = __bool__


Test patch:
diff --git a/tests/test_uncertainties.py b/tests/test_uncertainties.py
index 2b444a6..003e6bc 100644
--- a/tests/test_uncertainties.py
+++ b/tests/test_uncertainties.py
@@ -1358,6 +1358,11 @@ def test_deprecated_method(method_name):
             getattr(x, method_name)(y)
 
 
+def test_deprecated_bool():
+    with pytest.warns(FutureWarning, match="is deprecated.*will defer to"):
+        bool(ufloat(0, 0))
+
+
 def test_zero_std_dev_warn():
     with pytest.warns(UserWarning, match="std_dev==0.*unexpected results"):
         ufloat(1, 0)