Repository: yt-project/yt

Issue:
DEPR: `VisibleDeprecationWarning` considered noisy
Context:
yt doesn't use builtin `DeprecationWarning`s but instead uses a custom class `VisibleDeprecationWarning`, whose sole intent is to work around Python's default warning filters which hide `DeprecationWarning`s by default (the idea being that they should only be made visible if users opt-in).

The design currently used in yt made sense a while back, because we want deprecation warnings to reach all users, not just maintainers of dependent code with high quality standards. The trade-off being that our warnings will surface to users no matter how many layers of dependencies there are between the code being written and yt; for instance, if `yt_astro_analysis` or `trident` uses deprecated yt API, *their* users don't have much control over it and it can be argued they shouldn't see these "noisy" warnings by default. 

Since Python 3.7 ([PEP 565](https://peps.python.org/pep-0565/)), `DeprecationWarnings` attributed to the `__main__` module are again showed by default, meaning they will reach direct users (including in REPLs) but will not surface (by default) when deprecated API calls live in an intermediate dependency layer.

It seems to me that our current solution isn't necessary anymore and that we should use simple `DeprecationWarning`s from now on.


Discussion:

Resolving patch:
diff --git a/yt/_maintenance/deprecation.py b/yt/_maintenance/deprecation.py
--- a/yt/_maintenance/deprecation.py
+++ b/yt/_maintenance/deprecation.py
@@ -4,19 +4,6 @@
 from typing import Dict, Optional
 
 
-class VisibleDeprecationWarning(UserWarning):
-    """Visible deprecation warning, adapted from NumPy
-
-    The nose runner does not show users DeprecationWarning.
-    This ensures that a deprecation warning is visible to users
-    if that is desired.
-    """
-
-    # this class becomes useless after the tests are migrated from nose to pytest
-
-    pass
-
-
 def issue_deprecation_warning(
     msg: str,
     *,
@@ -55,7 +42,7 @@ def issue_deprecation_warning(
     msg += f"\nDeprecated since yt {since}"
     if removal is not None:
         msg += f"\nThis feature is planned for removal in yt {removal}"
-    warnings.warn(msg, VisibleDeprecationWarning, stacklevel=stacklevel)
+    warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel)
 
 
 def future_positional_only(positions2names: Dict[int, str], /, **depr_kwargs):


Test patch:
diff --git a/yt/tests/test_load_errors.py b/yt/tests/test_load_errors.py
--- a/yt/tests/test_load_errors.py
+++ b/yt/tests/test_load_errors.py
@@ -1,6 +1,5 @@
 import pytest
 
-from yt._maintenance.deprecation import VisibleDeprecationWarning
 from yt.data_objects.static_output import Dataset
 from yt.geometry.grid_geometry_handler import GridIndex
 from yt.loaders import load, load_simulation
@@ -199,8 +198,7 @@ def _is_valid(cls, *args, **kwargs):
 
 @pytest.mark.usefixtures("catchall_dataset_class")
 def test_depr_load_keyword(tmp_path):
-    with pytest.raises(
-        VisibleDeprecationWarning,
+    with pytest.deprecated_call(
         match=r"Using the 'fn' argument as keyword \(on position 0\) is deprecated\.",
     ):
         load(fn=tmp_path)
diff --git a/yt/visualization/tests/test_set_zlim.py b/yt/visualization/tests/test_set_zlim.py
--- a/yt/visualization/tests/test_set_zlim.py
+++ b/yt/visualization/tests/test_set_zlim.py
@@ -2,7 +2,6 @@
 import numpy.testing as npt
 import pytest
 
-from yt._maintenance.deprecation import VisibleDeprecationWarning
 from yt.testing import fake_amr_ds
 from yt.visualization.api import SlicePlot
 
@@ -136,12 +135,10 @@ def test_set_dynamic_range_with_None():
     cb = p.plots[field].image.colorbar
     vmin = cb.vmin
 
-    with pytest.raises(
-        VisibleDeprecationWarning, match="Passing `zmin=None` explicitly is deprecated"
-    ):
+    with pytest.deprecated_call(match="Passing `zmin=None` explicitly is deprecated"):
         p.set_zlim(field, zmin=None, dynamic_range=2)
 
-        p.render()
-        cb = p.plots[field].image.colorbar
-        new_lims = np.array((cb.vmin, cb.vmax))
-        npt.assert_almost_equal(new_lims, (vmin, 2 * vmin))
+    p.render()
+    cb = p.plots[field].image.colorbar
+    new_lims = np.array((cb.vmin, cb.vmax))
+    npt.assert_almost_equal(new_lims, (vmin, 2 * vmin))