Repository: PlasmaPy/PlasmaPy

Issue:
Enable inline code highlighting via Sphinx 5.0.0
Sphinx 5.0.0 was released today, and it turns out that it's now possible to have [inline code syntax highlighting](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#inline-code-highlighting) (!!!!!) just like in `code-block` directives.  This change would require making a new role for reStructuredText, so it wouldn't automagically get applied to code snippets with double back ticks. This change would probably make us require `sphinx >= 5.0.0`, and since this release is only a few hours old, and my inclination would be to make this change after our 0.8.0 release.

 - [ ] Add new role (`:py:` or `:python:`?) to [`rst_prolog`](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-rst_prolog) in `docs/conf.py` (which is similar to [`rst_epilog`](https://github.com/PlasmaPy/PlasmaPy/blob/1b9238439c1e4a7c1d35b8f812b4805872f0aae6/docs/conf.py#L187) but would need to be defined).
 - [ ] Describe this capability in the documentation guide
 - [ ] Update the requirements to `sphinx >= 5.0.0`



Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1698?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) Report
> Merging [#1698](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/1698?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) (2b8e1eb) into [main](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/ae2ad84ab73b0c96101127d1737b88d7bcef2032?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy) (ae2ad84) will **not change** coverage.
> The diff coverage is `n/a`.

> :exclamation: Current head 2b8e1eb differs from pull request most recent head 74f2d08. Consider uploading reports for the commit 74f2d08 to get more accurate results

```diff
@@           Coverage Diff           @@
##             main    #1698   +/-   ##
=======================================
  Coverage   97.65%   97.65%           
=======================================
  Files          85       85           
  Lines        8128     8128           
=======================================
  Hits         7937     7937           
  Misses        191      191           
```



Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PlasmaPy)

namurphy: ![Screenshot from 2022-08-25 23-09-58](https://user-images.githubusercontent.com/8931994/186809662-08de02dc-41f5-4c37-b91a-04d49c8b9d98.png)

From a test I did in the changelog entry.  It works!


Patch:
diff --git a/changelog/1540.trivial.rst b/changelog/1540.trivial.rst
deleted file mode 100644
index cd126945..00000000
--- a/changelog/1540.trivial.rst
+++ /dev/null
@@ -1,1 +0,0 @@
-Updated the minimum required version of NumPy to 1.20.0.
diff --git a/changelog/1697.breaking.rst b/changelog/1697.breaking.rst
new file mode 100644
index 00000000..becda938
--- /dev/null
+++ b/changelog/1697.breaking.rst
@@ -0,0 +1,2 @@
+Moved ``plasmapy.particles.particle_collections.ionic_levels`` to
+`plasmapy.particles.atomic.ionic_levels`.
diff --git a/changelog/1698.doc.1.rst b/changelog/1698.doc.1.rst
new file mode 100644
index 00000000..89325d00
--- /dev/null
+++ b/changelog/1698.doc.1.rst
@@ -0,0 +1,1 @@
+Enabled ``:py:`` as a reST_ role for inline code formatting.
diff --git a/changelog/1698.doc.2.rst b/changelog/1698.doc.2.rst
new file mode 100644
index 00000000..db9e7a7b
--- /dev/null
+++ b/changelog/1698.doc.2.rst
@@ -0,0 +1,1 @@
+Increase the minimum version of Sphinx_ to 5.0.0.
diff --git a/docs/conf.py b/docs/conf.py
index c2a19952..4dc9a534 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -80,7 +80,7 @@
 
 # If your documentation needs a minimal Sphinx version, state it here.
 
-needs_sphinx = "4.4"
+needs_sphinx = "5.0.0"
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -173,6 +173,7 @@
 project = "PlasmaPy"
 author = "PlasmaPy Community"
 copyright = f"2015–{datetime.utcnow().year}, {author}"
+language = "en"
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -194,12 +195,10 @@
 with open("common_links.rst") as cl:
     rst_epilog += cl.read()
 
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = "en"
+rst_prolog = """
+.. role:: py(code)
+   :language: python
+"""
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
@@ -383,9 +382,6 @@
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-# html_theme = 'alabaster'
-# html_theme = 'traditional'
-# html_theme = 'agogo'
 html_theme = "sphinx_rtd_theme"
 
 # Theme options are theme-specific and customize the look and feel of a theme
diff --git a/docs/contributing/coding_guide.rst b/docs/contributing/coding_guide.rst
index 4c2ec2c2..5d4e1090 100644
--- a/docs/contributing/coding_guide.rst
+++ b/docs/contributing/coding_guide.rst
@@ -65,7 +65,7 @@ Coding guidelines
   these parameters should be made :term:`keyword-only` to avoid
   ambiguity and reduce the chance of errors.
 
-  .. code-block::
+  .. code-block:: python
 
      def f(*, T_i, T_e):
          ...
@@ -74,7 +74,7 @@ Coding guidelines
   exceptions. If the comparison for equality is being made between
   objects of different types, these methods should return `False`
   instead. This behavior is for consistency with operations like
-  ``1 == "1"`` which will return `False`.
+  :py:`1 == "1"` which will return `False`.
 
 * Limit usage of ``lambda`` functions to one-liners, such as when
   defining the default factory of a `~collections.defaultdict`). For
@@ -91,7 +91,7 @@ Coding guidelines
   A comprehension might be more readable when spread out over multiple
   lines.
 
-  .. code-block::
+  .. code-block:: pycon
 
      >>> {
      ...     x: x ** 2
@@ -126,7 +126,7 @@ Coding guidelines
 
   .. tip::
 
-     Normally, ``numpy.nan == numpy.nan`` evaluates to `False`, which
+     Normally, :py:`numpy.nan == numpy.nan` evaluates to `False`, which
      complicates testing |nan| behavior. The ``equal_nan`` keyword of
      functions like `numpy.allclose` and `numpy.testing.assert_allclose`
      makes it so that |nan| is considered equal to itself.
@@ -302,10 +302,11 @@ Imports
   decrease readability without providing commensurately more
   information.
 
-* Use absolute imports (e.g., ``from plasmapy.particles import Particle``)
-  rather than relative imports (e.g., ``from ..particles import Particle``).
+* Use absolute imports (e.g., :py:`from plasmapy.particles import
+  Particle`) rather than relative imports (e.g., :py:`from ..particles
+  import Particle`).
 
-* Do not use star imports (e.g., ``from package.subpackage import *``),
+* Do not use star imports (e.g., :py:`from package.subpackage import *`),
   except in very limited situations.
 
 Requirements
@@ -637,8 +638,8 @@ adjacent fields such as astronomy and heliophysics. To get started with
   .. caution::
 
      Recent versions of Astropy_ allow unit-aware |Quantity|
-     annotations such as ``u.Quantity[u.m]``. However, these annotations
-     are not yet compatible with |validate_quantities|.
+     annotations such as :py:`u.Quantity[u.m]`. However, these
+     annotations are not yet compatible with |validate_quantities|.
 
 * Avoid using electron-volts as a unit of temperature within PlasmaPy
   because it is defined as a unit of energy. However, functions in
@@ -877,10 +878,10 @@ that corresponds to ``function`` as would be defined in
   ``lite`` attribute using the
   `~plasmapy.utils.decorators.lite_func.bind_lite_func` decorator. This
   allows the :term:`lite-function` to also be accessed like
-  ``thermal_speed.lite()``.
+  :py:`thermal_speed.lite()`.
 
-* If a :term:`lite-function` is decorated with something like ``@njit``,
-  then it should also be decorated with
+* If a :term:`lite-function` is decorated with something like
+  :py:`@njit`, then it should also be decorated with
   `~plasmapy.utils.decorators.helpers.preserve_signature`.  This
   preserves the function signature so interpreters can still
   give hints about function arguments.
diff --git a/docs/contributing/doc_guide.rst b/docs/contributing/doc_guide.rst
index 0287a4d2..858696f0 100644
--- a/docs/contributing/doc_guide.rst
+++ b/docs/contributing/doc_guide.rst
@@ -202,8 +202,8 @@ the same length as that heading.
 We can link to code objects by enclosing them in single back ticks.
 This linking will work for Python_ commands as well as certain packages
 like NumPy_, SciPy_, Astropy_, and pandas_. This linking is described in
-the section on :ref:`external-references`. In-line code examples are
-enclosed in double back ticks.
+the section on :ref:`external-references`. In-line code examples may be
+enclosed in double back ticks or specified using the ``:py:`` role.
 
 .. code-block:: rst
 
@@ -215,7 +215,10 @@ enclosed in double back ticks.
    but shortens the display so only "particles" is displayed.
 
    Double backticks are used to show inline code that is not
-   cross-referenced: ``import astropy.units as u``.
+   cross-referenced: ``plasmapy.particles``.
+
+   The ``:py:`` role can be used for inline code highlighting:
+   :py:`import astropy.units as u`.
 
 This reST_ block renders as:
 
@@ -227,7 +230,10 @@ This reST_ block renders as:
    but shortens the display so only "particles" is displayed.
 
    Double backticks are used to show inline code that is not
-   cross-referenced: ``import astropy.units as u``.
+   cross-referenced: ``plasmapy.particles``.
+
+   The ``:py:`` role can be used for inline code highlighting:
+   :py:`import astropy.units as u`.
 
 Sphinx_ can format code blocks for Python_ and the Python_ console
 using the :rst:dir:`code-block` :term:`directive`.
diff --git a/docs/whatsnew/0.7.0.rst b/docs/whatsnew/0.7.0.rst
index 1c113710..88add704 100644
--- a/docs/whatsnew/0.7.0.rst
+++ b/docs/whatsnew/0.7.0.rst
@@ -139,7 +139,7 @@ Features
   related to analytical dispersion solutions. (`#1208 <https://github.com/plasmapy/plasmapy/pull/1208>`__)
 - Implemented ``__eq__``, ``__ne__`` and ``__hash__`` to allow
   |CustomParticle| instances to be used as `dict` keys. (`#1216 <https://github.com/plasmapy/plasmapy/pull/1216>`__)
-- Added the `~plasmapy.particles.particle_collections.ionic_levels` function to create a
+- Added the ``plasmapy.particles.particle_collections.ionic_levels`` function to create a
   |ParticleList| initialized with different ionic levels of an element or isotope. (`#1223 <https://github.com/plasmapy/plasmapy/pull/1223>`__)
 
 
diff --git a/plasmapy/particles/__init__.py b/plasmapy/particles/__init__.py
index 618759ba..d26eb76b 100644
--- a/plasmapy/particles/__init__.py
+++ b/plasmapy/particles/__init__.py
@@ -13,6 +13,7 @@
     common_isotopes,
     electric_charge,
     half_life,
+    ionic_levels,
     is_stable,
     isotopic_abundance,
     known_isotopes,
@@ -35,11 +36,7 @@
     Particle,
     ParticleLike,
 )
-from plasmapy.particles.particle_collections import (
-    ionic_levels,
-    ParticleList,
-    ParticleListLike,
-)
+from plasmapy.particles.particle_collections import ParticleList, ParticleListLike
 from plasmapy.particles.serialization import (
     json_load_particle,
     json_loads_particle,
diff --git a/plasmapy/particles/atomic.py b/plasmapy/particles/atomic.py
index 01665b24..769e5c45 100644
--- a/plasmapy/particles/atomic.py
+++ b/plasmapy/particles/atomic.py
@@ -6,6 +6,7 @@
     "common_isotopes",
     "electric_charge",
     "half_life",
+    "ionic_levels",
     "isotopic_abundance",
     "is_stable",
     "known_isotopes",
@@ -29,15 +30,15 @@
 from plasmapy.particles import _elements, _isotopes
 from plasmapy.particles.decorators import particle_input
 from plasmapy.particles.exceptions import (
+    ChargeError,
     InvalidElementError,
     InvalidIsotopeError,
     InvalidParticleError,
     MissingParticleDataError,
 )
 from plasmapy.particles.particle_class import Particle
+from plasmapy.particles.particle_collections import ParticleList
 from plasmapy.particles.symbols import atomic_symbol
-from plasmapy.utils.decorators.deprecation import deprecated
-from plasmapy.utils.exceptions import PlasmaPyFutureWarning
 
 __all__.sort()
 
@@ -1109,6 +1110,59 @@ def periodic_table_category(argument: Union[str, Integral]) -> str:
     return _elements.data_about_elements[symbol]["category"]
 
 
+@particle_input(any_of={"element", "isotope", "ion"})
+def ionic_levels(
+    particle: Particle,
+    min_charge: Integral = 0,
+    max_charge: Optional[Integral] = None,
+) -> ParticleList:
+    """
+    Return a |ParticleList| that includes different ionic levels of a
+    base atom.
+
+    Parameters
+    ----------
+    particle : `~plasmapy.particles.particle_class.ParticleLike`
+        Representation of an element, ion, or isotope.
+
+    min_charge : integer, optional
+        The starting charge number. Defaults to ``0``.
+
+    max_charge : integer, optional
+        The ending charge number, which will be included in the
+        |ParticleList|.  Defaults to the atomic number.
+
+    Returns
+    -------
+    `~plasmapy.particles.particle_collections.ParticleList`
+        The ionic levels of the atom provided from ``min_charge`` to
+        ``max_charge``.
+
+    Examples
+    --------
+    >>> from plasmapy.particles import ionic_levels
+    >>> ionic_levels("He")
+    ParticleList(['He 0+', 'He 1+', 'He 2+'])
+    >>> ionic_levels("Fe-56", min_charge=13, max_charge=15)
+    ParticleList(['Fe-56 13+', 'Fe-56 14+', 'Fe-56 15+'])
+    """
+    base_particle = Particle(particle.isotope or particle.element)
+
+    if max_charge is None:
+        max_charge = particle.atomic_number
+
+    if not min_charge <= max_charge <= particle.atomic_number:
+        raise ChargeError(
+            f"Need min_charge ({min_charge}) "
+            f"≤ max_charge ({max_charge}) "
+            f"≤ atomic number ({base_particle.atomic_number})."
+        )
+
+    return ParticleList(
+        [Particle(base_particle, Z=Z) for Z in range(min_charge, max_charge + 1)]
+    )
+
+
 def _is_electron(arg: Any) -> bool:
     """
     Return `True` if the argument corresponds to an electron, and
diff --git a/plasmapy/particles/ionization_state.py b/plasmapy/particles/ionization_state.py
index 2698977b..7b53a4b3 100644
--- a/plasmapy/particles/ionization_state.py
+++ b/plasmapy/particles/ionization_state.py
@@ -12,6 +12,7 @@
 from numbers import Integral, Real
 from typing import List, Optional, Union
 
+from plasmapy.particles.atomic import ionic_levels
 from plasmapy.particles.decorators import particle_input
 from plasmapy.particles.exceptions import (
     ChargeError,
@@ -19,10 +20,8 @@
     ParticleError,
 )
 from plasmapy.particles.particle_class import CustomParticle, Particle
-from plasmapy.particles.particle_collections import ionic_levels, ParticleList
+from plasmapy.particles.particle_collections import ParticleList
 from plasmapy.utils.decorators import validate_quantities
-from plasmapy.utils.decorators.deprecation import deprecated
-from plasmapy.utils.exceptions import PlasmaPyFutureWarning
 
 _number_density_errmsg = (
     "Number densities must be Quantity objects with units of inverse volume."
diff --git a/plasmapy/particles/particle_collections.py b/plasmapy/particles/particle_collections.py
index 1718e2af..b6836d86 100644
--- a/plasmapy/particles/particle_collections.py
+++ b/plasmapy/particles/particle_collections.py
@@ -1,6 +1,6 @@
 """Collections of `~plasmapy.particles.particle_class.Particle` objects."""
 
-__all__ = ["ionic_levels", "ParticleList", "ParticleListLike"]
+__all__ = ["ParticleList", "ParticleListLike"]
 
 import astropy.units as u
 import collections
@@ -436,60 +436,6 @@ def _average(array, weights, use_rms):
 
 ParticleList.reverse.__doc__ = """Reverse the |ParticleList| in place."""
 
-
-@particle_input(any_of={"element", "isotope", "ion"})
-def ionic_levels(
-    particle: Particle,
-    min_charge: Integral = 0,
-    max_charge: Optional[Integral] = None,
-) -> ParticleList:
-    """
-    Return a |ParticleList| that includes different ionic levels of a
-    base atom.
-
-    Parameters
-    ----------
-    particle : `~plasmapy.particles.particle_class.ParticleLike`
-        Representation of an element, ion, or isotope.
-
-    min_charge : integer, optional
-        The starting charge number. Defaults to ``0``.
-
-    max_charge : integer, optional
-        The ending charge number, which will be included in the
-        |ParticleList|.  Defaults to the atomic number.
-
-    Returns
-    -------
-    `~plasmapy.particles.particle_collections.ParticleList`
-        The ionic levels of the atom provided from ``min_charge`` to
-        ``max_charge``.
-
-    Examples
-    --------
-    >>> from plasmapy.particles import ionic_levels
-    >>> ionic_levels("He")
-    ParticleList(['He 0+', 'He 1+', 'He 2+'])
-    >>> ionic_levels("Fe-56", min_charge=13, max_charge=15)
-    ParticleList(['Fe-56 13+', 'Fe-56 14+', 'Fe-56 15+'])
-    """
-    base_particle = Particle(particle.isotope or particle.element)
-
-    if max_charge is None:
-        max_charge = particle.atomic_number
-
-    if not min_charge <= max_charge <= particle.atomic_number:
-        raise ChargeError(
-            f"Need min_charge ({min_charge}) "
-            f"≤ max_charge ({max_charge}) "
-            f"≤ atomic number ({base_particle.atomic_number})."
-        )
-
-    return ParticleList(
-        [Particle(base_particle, Z=Z) for Z in range(min_charge, max_charge + 1)]
-    )
-
-
 ParticleListLike = Union[ParticleList, Sequence[ParticleLike]]
 
 ParticleListLike.__doc__ = r"""


Test patch:
diff --git a/docs/contributing/testing_guide.rst b/docs/contributing/testing_guide.rst
index 774258fc..4f5abe6c 100644
--- a/docs/contributing/testing_guide.rst
+++ b/docs/contributing/testing_guide.rst
@@ -460,7 +460,7 @@ both will be run.
 However, this approach can lead to cumbersome, repeated code if you are
 calling the same function over and over. If you wish to run multiple
 tests for the same function, the preferred method is to decorate it with
-``@pytest.mark.parametrize``.
+:py:`@pytest.mark.parametrize`.
 
 .. code-block:: python
 
@@ -468,8 +468,8 @@ tests for the same function, the preferred method is to decorate it with
    def test_proof_if_riemann(truth_value):
         assert proof_by_riemann(truth_value)
 
-This code snippet will run ``proof_by_riemann(truth_value)`` for each
-``truth_value`` in ``[True, False]``. Both of the above
+This code snippet will run :py:`proof_by_riemann(truth_value)` for each
+``truth_value`` in :py:`[True, False]`. Both of the above
 tests will be run regardless of failures. This approach is much cleaner
 for long lists of arguments, and has the advantage that you would only
 need to change the function call in one place if the function changes.
@@ -549,7 +549,7 @@ Property-based testing
 ----------------------
 
 Suppose a function :math:`f(x)` has a property that :math:`f(x) > 0` for
-all :math:`x`. A property-based test would verify that ``f(x)`` — the
+all :math:`x`. A property-based test would verify that :py:`f(x)` — the
 code implementation of :math:`f(x)` — returns positive output for
 multiple values of :math:`x`. The hypothesis_ package simplifies
 `property-based testing`_ for Python.
@@ -660,7 +660,7 @@ should be balanced with each other rather than absolute principles.
   increases the probability that we will lose track of what we are
   doing and slows down progress.
 
-  Decorate unavoidably slow tests with ``@pytest.mark.slow``:
+  Decorate unavoidably slow tests with :py:`@pytest.mark.slow`:
 
   .. code-block:: python
 
diff --git a/plasmapy/particles/tests/test_atomic.py b/plasmapy/particles/tests/test_atomic.py
index 8837e7b1..adec3147 100644
--- a/plasmapy/particles/tests/test_atomic.py
+++ b/plasmapy/particles/tests/test_atomic.py
@@ -12,6 +12,7 @@
     common_isotopes,
     electric_charge,
     half_life,
+    ionic_levels,
     is_stable,
     isotopic_abundance,
     known_isotopes,
@@ -26,12 +27,14 @@
     standard_atomic_weight,
 )
 from plasmapy.particles.exceptions import (
+    ChargeError,
     InvalidElementError,
     InvalidIsotopeError,
     InvalidParticleError,
     MissingParticleDataError,
     ParticleWarning,
 )
+from plasmapy.particles.particle_class import Particle
 from plasmapy.particles.symbols import atomic_symbol, element_name, isotope_symbol
 from plasmapy.utils.pytest_helpers import run_test
 
@@ -517,6 +520,39 @@ def test_missing_atomic_data(self):
             reduced_mass("Og", "H")
 
 
+def test_ion_list_example():
+    ions = ionic_levels("He-4")
+    np.testing.assert_equal(ions.charge_number, [0, 1, 2])
+    assert ions.symbols == ["He-4 0+", "He-4 1+", "He-4 2+"]
+
+
+@pytest.mark.parametrize(
+    "particle, min_charge, max_charge, expected_charge_numbers",
+    [
+        ("H-1", 0, 1, [0, 1]),
+        ("p+", 1, 1, [1]),
+        (Particle("p+"), 0, 0, [0]),
+        ("C", 3, 5, [3, 4, 5]),
+    ],
+)
+def test_ion_list(particle, min_charge, max_charge, expected_charge_numbers):
+    """Test that inputs to ionic_levels are interpreted correctly."""
+    particle = Particle(particle)
+    ions = ionic_levels(particle, min_charge, max_charge)
+    np.testing.assert_equal(ions.charge_number, expected_charge_numbers)
+    assert ions[0].element == particle.element
+    if particle.is_category("isotope"):
+        assert ions[0].isotope == particle.isotope
+
+
+@pytest.mark.parametrize(
+    "element, min_charge, max_charge", [("Li", 0, 4), ("Li", 3, 2)]
+)
+def test_invalid_inputs_to_ion_list(element, min_charge, max_charge):
+    with pytest.raises(ChargeError):
+        ionic_levels(element, min_charge, max_charge)
+
+
 str_electron_table = [
     ("e-", True),
     ("e+", False),
diff --git a/plasmapy/particles/tests/test_ionization_state.py b/plasmapy/particles/tests/test_ionization_state.py
index 40795ff3..dbddb50c 100644
--- a/plasmapy/particles/tests/test_ionization_state.py
+++ b/plasmapy/particles/tests/test_ionization_state.py
@@ -10,14 +10,14 @@
     atomic_number,
     atomic_symbol,
     charge_number,
+    ionic_levels,
     isotope_symbol,
     particle_symbol,
 )
 from plasmapy.particles.exceptions import InvalidIsotopeError, ParticleError
 from plasmapy.particles.ionization_state import IonicLevel, IonizationState
 from plasmapy.particles.particle_class import Particle
-from plasmapy.particles.particle_collections import ionic_levels, ParticleList
-from plasmapy.utils.exceptions import PlasmaPyFutureWarning
+from plasmapy.particles.particle_collections import ParticleList
 
 ionic_fraction_table = [
     ("Fe 6+", 0.52, 5.2e-6 * u.m**-3),
diff --git a/plasmapy/particles/tests/test_particle_collections.py b/plasmapy/particles/tests/test_particle_collections.py
index 559c21f2..6b9d8f97 100644
--- a/plasmapy/particles/tests/test_particle_collections.py
+++ b/plasmapy/particles/tests/test_particle_collections.py
@@ -7,7 +7,7 @@
 
 from plasmapy.particles import alpha, electron, neutron, proton
 from plasmapy.particles.atomic import atomic_number
-from plasmapy.particles.exceptions import ChargeError, InvalidParticleError
+from plasmapy.particles.exceptions import InvalidParticleError
 from plasmapy.particles.nuclear import nuclear_reaction_energy
 from plasmapy.particles.particle_class import (
     CustomParticle,
@@ -15,7 +15,7 @@
     Particle,
     ParticleLike,
 )
-from plasmapy.particles.particle_collections import ionic_levels, ParticleList
+from plasmapy.particles.particle_collections import ParticleList
 
 custom_particle = CustomParticle(mass=1e-25 * u.kg, charge=1e-18 * u.C)
 dimensionless_particle = DimensionlessParticle(mass=1.25, charge=1.58)
@@ -493,36 +493,3 @@ def test_particle_list_with_no_arguments():
     empty_particle_list = ParticleList()
     assert isinstance(empty_particle_list, ParticleList)
     assert len(empty_particle_list) == 0
-
-
-def test_ion_list_example():
-    ions = ionic_levels("He-4")
-    np.testing.assert_equal(ions.charge_number, [0, 1, 2])
-    assert ions.symbols == ["He-4 0+", "He-4 1+", "He-4 2+"]
-
-
-@pytest.mark.parametrize(
-    "particle, min_charge, max_charge, expected_charge_numbers",
-    [
-        ("H-1", 0, 1, [0, 1]),
-        ("p+", 1, 1, [1]),
-        (Particle("p+"), 0, 0, [0]),
-        ("C", 3, 5, [3, 4, 5]),
-    ],
-)
-def test_ion_list(particle, min_charge, max_charge, expected_charge_numbers):
-    """Test that inputs to ionic_levels are interpreted correctly."""
-    particle = Particle(particle)
-    ions = ionic_levels(particle, min_charge, max_charge)
-    np.testing.assert_equal(ions.charge_number, expected_charge_numbers)
-    assert ions[0].element == particle.element
-    if particle.is_category("isotope"):
-        assert ions[0].isotope == particle.isotope
-
-
-@pytest.mark.parametrize(
-    "element, min_charge, max_charge", [("Li", 0, 4), ("Li", 3, 2)]
-)
-def test_invalid_inputs_to_ion_list(element, min_charge, max_charge):
-    with pytest.raises(ChargeError):
-        ionic_levels(element, min_charge, max_charge)