Repository: yt-project/unyt (language: python)

Issue:
TST: issue with testing unyt 3.0.2 in isolation
* unyt version: 3.0.2
* Python version: 3.12.2
* Operating System: MacOS

### Description
This is to keep track of an issue I faced in the process of releasing uny 3.0.2, where I found that one test would fail when running in isolation.

### What I Did

```shell
python -m venv .venv
source .venv/bin/activate
python -m pip install unyt pytest
pytest --pyargs unyt
```

<details><summary>Log</summary>

```
=========================== test session starts ============================
platform darwin -- Python 3.12.2, pytest-8.1.1, pluggy-1.4.0
rootdir: /private/tmp
collected 471 items / 1 skipped

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py . [  0%]
...................xxsssssssssss.ss................................. [ 14%]
....................................................s............... [ 29%]
.....................................F....................ssss...... [ 43%]
...............................................                      [ 53%]
.venv/lib/python3.12/site-packages/unyt/tests/test_define_unit.py .. [ 53%]
                                                                     [ 53%]
.venv/lib/python3.12/site-packages/unyt/tests/test_mpl_interface.py s [ 54%]
sssssssssssssss                                                      [ 57%]
.venv/lib/python3.12/site-packages/unyt/tests/test_no_duplicates.py . [ 57%]
                                                                     [ 57%]
.venv/lib/python3.12/site-packages/unyt/tests/test_unit_registry.py . [ 57%]
.........                                                            [ 59%]
.venv/lib/python3.12/site-packages/unyt/tests/test_unit_systems.py . [ 59%]
......                                                               [ 61%]
.venv/lib/python3.12/site-packages/unyt/tests/test_units.py ........ [ 62%]
..........................................                           [ 71%]
.venv/lib/python3.12/site-packages/unyt/tests/test_unyt_array.py ... [ 72%]
.........x.......sss....s........................................... [ 86%]
.....................................................                [ 98%]
.venv/lib/python3.12/site-packages/unyt/tests/test_unyt_testing.py . [ 98%]
........                                                             [100%]

================================= FAILURES =================================
_______________________________ test_savetxt _______________________________

tmp_path = PosixPath('/private/var/folders/47/t9k4zdz96vzd4v1rxyv07nvh0000gn/T/pytest-of-clm/pytest-16/test_savetxt0')

    def test_savetxt(tmp_path):
        a = [1, 2, 3] * cm
>       with pytest.raises(
            UserWarning,
            match=re.escape(
                "numpy.savetxt does not preserve units, "
                "and will only save the raw numerical data from the unyt_array object.\n"
                "If this is the intended behaviour, call `numpy.savetxt(file, arr.d)` "
                "to silence this warning.\n"
                "If you want to preserve units, use `unyt.savetxt` "
                "(and `unyt.loadtxt`) instead."
            ),
        ):
E       Failed: DID NOT RAISE <class 'UserWarning'>

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:1407: Failed
============================= warnings summary =============================
.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function mirr was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function mirr was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function irr was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function irr was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function npv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function npv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function pmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function pmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function nper was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function nper was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function ipmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function ipmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function ppmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function ppmt was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function rate was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function rate was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function fv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function fv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:214: DeprecationWarning: In accordance with NEP 32, the function pv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    if hasattr(np, func):

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215
  /private/tmp/.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py:215: DeprecationWarning: In accordance with NEP 32, the function pv was removed from NumPy version 1.20.  A replacement for this function is available in the numpy_financial library: https://pypi.org/project/numpy-financial
    NOT_HANDLED_FUNCTIONS.add(getattr(np, func))

.venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py::test_savetxt
  /private/tmp/.venv/lib/python3.12/site-packages/_pytest/python.py:195: UserWarning: numpy.savetxt does not preserve units, and will only save the raw numerical data from the unyt_array object.
  If this is the intended behaviour, call `numpy.savetxt(file, arr.d)` to silence this warning.
  If you want to preserve units, use `unyt.savetxt` (and `unyt.loadtxt`) instead.
    result = testfunction(**testargs)

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
========================= short test summary info ==========================
FAILED .venv/lib/python3.12/site-packages/unyt/tests/test_array_functions.py::test_savetxt - Failed: DID NOT RAISE <class 'UserWarning'>
==== 1 failed, 429 passed, 39 skipped, 3 xfailed, 21 warnings in 1.37s =====
```

</details>

further details:
- this still happens if I downgrade pytest (8.1.1 is known to cause issues so I checked)
- the failing test reports that a warning didn't go off, but the very same warning is still reported in logs
- there are multiple other warnings that we usually don't see in CI (because they are explicitly filtered in pytest configuration, stored in `pyproject.toml`)
- I manually checked that the piece of code under test actually behaved as intended in the same environment

All these clues lead me to believe that this was purely a testing defect, not an actual bug, so I still pushed the release as is on PyPI. However I'd like to fix it for next time.

I think what may be happening is that the success of the test suite is dependent on our exact pytest configuration, which is apparently lost in packaging, but I need to inspect this more closely.


Discussion / hints:

Fix patch:
diff --git a/pyproject.toml b/pyproject.toml
index 492fd5ba..53eb2e60 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -124,7 +124,6 @@ filterwarnings = [
     "error",
     "ignore:Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.:UserWarning",
     "ignore:FigureCanvasAgg is non-interactive, and thus cannot be shown:UserWarning",
-    "ignore:In accordance with NEP 32:DeprecationWarning",
     "ignore:distutils Version classes are deprecated. Use packaging.version instead.:DeprecationWarning",
     'ignore:datetime\.datetime\.utcfromtimestamp\(\) is deprecated:DeprecationWarning', # https://github.com/dateutil/dateutil/pull/1285
     'ignore:mpnumeric is deprecated:DeprecationWarning', # sympy 1.12 VS mpmath 1.4, solution: https://github.com/sympy/sympy/pull/25290


Test patch:
diff --git a/unyt/tests/test_array_functions.py b/unyt/tests/test_array_functions.py
index 077f9998..f879f781 100644
--- a/unyt/tests/test_array_functions.py
+++ b/unyt/tests/test_array_functions.py
@@ -1,5 +1,6 @@
 # tests for NumPy __array_function__ support
 import re
+import warnings
 from importlib.metadata import version
 
 import numpy as np
@@ -184,35 +185,47 @@
     np.savez_compressed,
 }
 
-
+# map subsets of deprecated functions to the version they were removed
+# so that we can drop the ones that are not present in any version we support
 DEPRECATED_FUNCTIONS = {
-    "alen",  # deprecated in numpy 1.18, removed in 1.22
-    "asscalar",  # deprecated in numpy 1.18, removed in 1.22
-    "fv",  # deprecated in numpy 1.18, removed in 1.20
-    "ipmt",  # deprecated in numpy 1.18, removed in 1.20
-    "irr",  # deprecated in numpy 1.18, removed in 1.20
-    "mirr",  # deprecated in numpy 1.18, removed in 1.20
-    "nper",  # deprecated in numpy 1.18, removed in 1.20
-    "npv",  # deprecated in numpy 1.18, removed in 1.20
-    "pmt",  # deprecated in numpy 1.18, removed in 1.20
-    "ppmt",  # deprecated in numpy 1.18, removed in 1.20
-    "pv",  # deprecated in numpy 1.18, removed in 1.20
-    "rank",  # deprecated in numpy 1.10, removed in 1.18
-    "rate",  # deprecated in numpy 1.18, removed in 1.20
-    "msort",  # deprecated in numpy 1.24
-    # numpy 1.25 deprecations
-    "product",
-    "cumproduct",
-    "round_",  # removed in 2.0
-    "sometrue",
-    "alltrue",
+    Version("1.20"): {
+        "fv",
+        "ipmt",
+        "irr",
+        "mirr",
+        "nper",
+        "npv",
+        "pmt",
+        "ppmt",
+        "pv",
+        "rate",
+    },
+    Version("1.22"): {
+        "alen",
+        "asscalar",
+    },
+    Version("2.0.0b1"): {
+        "msort",
+        "product",
+        "cumproduct",
+        "round_",
+        "sometrue",
+        "alltrue",
+    },
+    # functions that are deprecated but not yet removed in any known version
+    # should be added here
+    Version("999.999.999"): set(),
 }
 
 NOT_HANDLED_FUNCTIONS = NOOP_FUNCTIONS | UNSUPPORTED_FUNCTIONS | IGNORED_FUNCTIONS
 
-for func in DEPRECATED_FUNCTIONS:
-    if hasattr(np, func):
-        NOT_HANDLED_FUNCTIONS.add(getattr(np, func))
+with warnings.catch_warnings():
+    warnings.simplefilter("ignore", DeprecationWarning)
+    for removal_version, functions in DEPRECATED_FUNCTIONS.items():
+        if NUMPY_VERSION >= removal_version:
+            continue
+        for func in functions:
+            NOT_HANDLED_FUNCTIONS.add(getattr(np, func))
 
 
 def get_decorators(func):
@@ -1404,7 +1417,7 @@ def test_eigvals(func):
 
 def test_savetxt(tmp_path):
     a = [1, 2, 3] * cm
-    with pytest.raises(
+    with pytest.warns(
         UserWarning,
         match=re.escape(
             "numpy.savetxt does not preserve units, "