BUG: can't use annotate_timestamp with code units
<!--To help us understand and resolve your issue, please fill out the form to
the best of your ability.-->
<!--You can feel free to delete the sections that do not apply.-->

### Bug report

**Bug summary**

When loading a data set using code units, `p.annotate_timestamp()` fails.

**Code for reproduction**

<!--A minimum code snippet required to reproduce the bug, also minimizing the
number of dependencies required.-->

<!-- If you need to use a data file to trigger the issue you're having, consider
using one of the datasets from the yt data hub (http://yt-project.org/data). If
your issue cannot be triggered using a public dataset, you can use the yt
curldrop (https://docs.hub.yt/services.html#curldrop) to share data
files. Please include a link to the dataset in the issue if you use the
curldrop.-->

```python
import yt
from yt.testing import fake_random_ds

ds = fake_random_ds(64, unit_system="code")
p = yt.SlicePlot(ds,"x",("gas", "density"))
p.annotate_timestamp()
p.save("timestamp.png")
```

**Actual outcome**

```
$ python timestamp.py
yt : [INFO     ] 2022-03-29 16:08:23,834 Parameters: current_time              = 0.0
yt : [INFO     ] 2022-03-29 16:08:23,834 Parameters: domain_dimensions         = [64 64 64]
yt : [INFO     ] 2022-03-29 16:08:23,834 Parameters: domain_left_edge          = [0. 0. 0.]
yt : [INFO     ] 2022-03-29 16:08:23,835 Parameters: domain_right_edge         = [1. 1. 1.]
yt : [INFO     ] 2022-03-29 16:08:23,835 Parameters: cosmological_simulation   = 0
yt : [INFO     ] 2022-03-29 16:08:24,111 xlim = 0.000000 1.000000
yt : [INFO     ] 2022-03-29 16:08:24,111 ylim = 0.000000 1.000000
yt : [INFO     ] 2022-03-29 16:08:24,111 xlim = 0.000000 1.000000
yt : [INFO     ] 2022-03-29 16:08:24,111 ylim = 0.000000 1.000000
yt : [INFO     ] 2022-03-29 16:08:24,112 Making a fixed resolution buffer of (('gas', 'density')) 800 by 800
Traceback (most recent call last):
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_modifications.py", line 2530, in __call__
    un = self.time_unit.latex_representation()
AttributeError: 'Symbol' object has no attribute 'latex_representation'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_window.py", line 1399, in run_callbacks
    callback(cbw)
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_modifications.py", line 41, in _check_geometry
    return func(self, plot)
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_modifications.py", line 2534, in __call__
    raise RuntimeError(
RuntimeError: The time unit str repr didn't match expectations, something is wrong.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "~/Documents/IPAG/ReposDivers/bugs_yt/timestamp.py", line 7, in <module>
    p.save("timestamp.png")
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_container.py", line 109, in newfunc
    args[0]._setup_plots()
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_window.py", line 1265, in _setup_plots
    self.run_callbacks()
  File "~/.pyenv/versions/yt-timestamp/lib/python3.9/site-packages/yt/visualization/plot_window.py", line 1403, in run_callbacks
    raise YTPlotCallbackError(callback._type_name) from e
yt.utilities.exceptions.YTPlotCallbackError: annotate_timestamp callback failed

```

**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: Debian 5.10.106-1 x86_64 GNU/Linux
  * Python Version: 3.9.9
  * yt version: 4.0.2 (installed through `pip install yt`) and 4.1.dev0 (through `pip install -e .` in cloned repo)

<!--Please tell us how you installed yt and python e.g., from source,
pip, conda. If you installed from conda, please specify which channel you used
if not the default-->

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 934229ed3..0943441ed 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -28,7 +28,7 @@ repos:
     - id: check-yaml
 
 -   repo: https://github.com/psf/black
-    rev: 23.1.0
+    rev: 23.3.0
     hooks:
     - id: black-jupyter
 
@@ -39,13 +39,13 @@ repos:
         additional_dependencies: [black==23.1.0]
 
 - repo: https://github.com/charliermarsh/ruff-pre-commit
-  rev: v0.0.254
+  rev: v0.0.261
   hooks:
   - id: ruff
     args: [--fix]
 
 - repo: https://github.com/nbQA-dev/nbQA
-  rev: 1.6.3
+  rev: 1.7.0
   hooks:
   - id: nbqa-ruff
     args: [--fix, --extend-ignore=E402]
@@ -56,7 +56,7 @@ repos:
     -   id: rst-backticks
 
 - repo: https://github.com/MarcoGorelli/cython-lint
-  rev: v0.12.5
+  rev: v0.15.0
   hooks:
   - id: cython-lint
     args: [--no-pycodestyle]
diff --git a/pyproject.toml b/pyproject.toml
index 6ae9b5ee2..62aea0b84 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -265,7 +265,6 @@ exclude = '''
 '''
 
 [tool.ruff]
-target-version = "py38"  # https://github.com/charliermarsh/ruff/issues/2039
 exclude = [
     "doc",
     "benchmarks",
@@ -293,6 +292,7 @@ select = [
 ignore = [
     "E501",  # line too long
     "E741",  # Do not use variables named 'I', 'O', or 'l'
+    "B018",  # Found useless expression. # disabled because ds.index is idiomatic
 ]
 
 
diff --git a/yt/data_objects/construction_data_containers.py b/yt/data_objects/construction_data_containers.py
index e8cb04866..016ca47f2 100644
--- a/yt/data_objects/construction_data_containers.py
+++ b/yt/data_objects/construction_data_containers.py
@@ -1490,6 +1490,7 @@ class YTSmoothedCoveringGrid(YTCoveringGrid):
                 "This is likely due to missing ghost-zones support "
                 f"in class {type(self.ds)}",
                 category=RuntimeWarning,
+                stacklevel=1,
             )
             mylog.debug("Caught %d runtime errors.", runtime_errors_count)
         for field, v in zip(fields, ls.fields):
diff --git a/yt/data_objects/static_output.py b/yt/data_objects/static_output.py
index 39b66ff25..7ce7f8f1c 100644
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -236,7 +236,8 @@ class Dataset(abc.ABC):
             warnings.warn(
                 f"Overwritting {cls.__name__}, which was previously registered. "
                 "This is expected if you're importing a yt extension with a "
-                "frontend that was already migrated to the main code base."
+                "frontend that was already migrated to the main code base.",
+                stacklevel=2,
             )
         output_type_registry[cls.__name__] = cls
         mylog.debug("Registering: %s as %s", cls.__name__, cls)
diff --git a/yt/frontends/amrvac/data_structures.py b/yt/frontends/amrvac/data_structures.py
index 4ddbd0289..d5c66bda3 100644
--- a/yt/frontends/amrvac/data_structures.py
+++ b/yt/frontends/amrvac/data_structures.py
@@ -97,6 +97,7 @@ class AMRVACGrid(AMRGridPatch):
                 "ghost-zones interpolation/smoothing is not "
                 "currently supported for AMRVAC data.",
                 category=RuntimeWarning,
+                stacklevel=2,
             )
             smoothed = False
         return super().retrieve_ghost_zones(
diff --git a/yt/funcs.py b/yt/funcs.py
index 3f48268a0..6be779b92 100644
--- a/yt/funcs.py
+++ b/yt/funcs.py
@@ -607,7 +607,8 @@ def fancy_download_file(url, filename, requests=None):
             iterations = int(float(total_length) / float(blocksize))
 
             pbar = get_pbar(
-                "Downloading %s to %s " % os.path.split(filename)[::-1], iterations
+                "Downloading {} to {} ".format(*os.path.split(filename)[::-1]),
+                iterations,
             )
             iteration = 0
             for chunk in response.iter_content(chunk_size=blocksize):
diff --git a/yt/loaders.py b/yt/loaders.py
index 0974abef6..57cffd81b 100644
--- a/yt/loaders.py
+++ b/yt/loaders.py
@@ -1678,7 +1678,8 @@ def load_archive(
     """
 
     warnings.warn(
-        "The 'load_archive' function is still experimental and may be unstable."
+        "The 'load_archive' function is still experimental and may be unstable.",
+        stacklevel=2,
     )
 
     fn = os.path.expanduser(fn)
diff --git a/yt/utilities/answer_testing/framework.py b/yt/utilities/answer_testing/framework.py
index 0e72ffe6b..c738b408b 100644
--- a/yt/utilities/answer_testing/framework.py
+++ b/yt/utilities/answer_testing/framework.py
@@ -797,7 +797,8 @@ def ensure_image_comparability(a, b):
 
     warnings.warn(
         f"Images have different shapes {a.shape} and {b.shape}. "
-        "Padding nans to make them comparable."
+        "Padding nans to make them comparable.",
+        stacklevel=2,
     )
     smallest_containing_shape = (
         max(a.shape[0], b.shape[0]),
diff --git a/yt/utilities/configure.py b/yt/utilities/configure.py
index adcf9d262..7894b6331 100644
--- a/yt/utilities/configure.py
+++ b/yt/utilities/configure.py
@@ -94,7 +94,8 @@ class YTConfig:
                     data = tomllib.load(fh)
             except tomllib.TOMLDecodeError as exc:
                 warnings.warn(
-                    f"Could not load configuration file {fname} (invalid TOML: {exc})"
+                    f"Could not load configuration file {fname} (invalid TOML: {exc})",
+                    stacklevel=2,
                 )
             else:
                 self.update(data, metadata=metadata)
@@ -117,7 +118,9 @@ class YTConfig:
         else:
             pdir = file_path.parent
             if not pdir.exists():
-                warnings.warn(f"{pdir!s} does not exist, creating it (recursively)")
+                warnings.warn(
+                    f"{pdir!s} does not exist, creating it (recursively)", stacklevel=2
+                )
                 os.makedirs(pdir)
             file_path.write_text(config_as_str)
 
diff --git a/yt/visualization/_commons.py b/yt/visualization/_commons.py
index f07484cf9..6f87f949c 100644
--- a/yt/visualization/_commons.py
+++ b/yt/visualization/_commons.py
@@ -96,7 +96,8 @@ def validate_image_name(filename, suffix: Optional[str] = None) -> str:
         if suffix in _get_supported_image_file_formats() and suffix != psuffix:
             warnings.warn(
                 f"Received two valid image formats {psuffix!r} (from filename) "
-                f"and {suffix!r} (from suffix). The former is ignored."
+                f"and {suffix!r} (from suffix). The former is ignored.",
+                stacklevel=2,
             )
             return f"{name}.{suffix}"
         return str(filename)
diff --git a/yt/visualization/base_plot_types.py b/yt/visualization/base_plot_types.py
index a4e782eb2..7e6d8b689 100644
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -337,7 +337,8 @@ class ImagePlotMPL(PlotMPL, ABC):
                         "with matplotlib versions older than 3.5\n"
                         "Please try upgrading matplotlib to a more recent version. "
                         "If the problem persists, please file a report to "
-                        "https://github.com/yt-project/yt/issues/new"
+                        "https://github.com/yt-project/yt/issues/new",
+                        stacklevel=2,
                     )
                 else:
                     raise exc
diff --git a/yt/visualization/plot_container.py b/yt/visualization/plot_container.py
index eb2b30744..6b5198ba2 100644
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -532,7 +532,8 @@ class PlotContainer(abc.ABC):
             if new_suffix != suffix:
                 warnings.warn(
                     f"Overriding suffix {suffix!r} with mpl_kwargs['format'] = {new_suffix!r}. "
-                    "Use the `suffix` argument directly to suppress this warning."
+                    "Use the `suffix` argument directly to suppress this warning.",
+                    stacklevel=2,
                 )
             suffix = new_suffix
 
diff --git a/yt/visualization/plot_modifications.py b/yt/visualization/plot_modifications.py
index c050e35e9..2adb5487d 100644
--- a/yt/visualization/plot_modifications.py
+++ b/yt/visualization/plot_modifications.py
@@ -1714,7 +1714,7 @@ class ArrowCallback(PlotCallback):
             dy = (yy1 - yy0) * 2 ** (0.5) * self.length
         # If the arrow is 0 length
         if dx == dy == 0:
-            warnings.warn("The arrow has zero length.  Not annotating.")
+            warnings.warn("The arrow has zero length. Not annotating.", stacklevel=2)
             return
 
         x, y, dx, dy = self._sanitize_xy_order(plot, x, y, dx, dy)
@@ -2586,7 +2586,8 @@ class TimestampCallback(PlotCallback):
         if self.redshift and not hasattr(plot.data.ds, "current_redshift"):
             warnings.warn(
                 f"dataset {plot.data.ds} does not have current_redshift attribute. "
-                "Set redshift=False to silence this warning."
+                "Set redshift=False to silence this warning.",
+                stacklevel=2,
             )
             self.redshift = False
 
['yt/utilities/answer_testing/framework.py', 'yt/utilities/configure.py', 'yt/data_objects/static_output.py', 'yt/loaders.py', 'yt/funcs.py', 'yt/visualization/plot_modifications.py', 'pyproject.toml', 'yt/visualization/base_plot_types.py', 'yt/visualization/plot_container.py', 'yt/visualization/_commons.py', '.pre-commit-config.yaml', 'yt/frontends/amrvac/data_structures.py', 'yt/data_objects/construction_data_containers.py']