Repository: scverse/scanpy

Issue:
scanpy 1.10.0rc1 breaks anndata pre-release tests
### Please make sure these conditions are met

- [X] I have checked that this issue has not already been reported.
- [X] I have confirmed this bug exists on the latest version of scanpy.
- [X] (optional) I have confirmed this bug exists on the master branch of scanpy.

### What happened?

`@doctest_needs` decorator causes test failures on scanpy import in anndata test suite

https://dev.azure.com/scverse/anndata/_build/results?buildId=5802&view=logs&jobId=0497d03e-5796-547f-cc56-989f8152a63c&j=0497d03e-5796-547f-cc56-989f8152a63c&t=ea3acdad-0250-5b8b-a1da-6cd02463cf17



### Minimal code sample

```python
NA
```


### Error output

```pytb
else:
            enum_member = enum_class._new_member_(enum_class, *args)
        if not hasattr(enum_member, '_value_'):
            if enum_class._member_type_ is object:
                enum_member._value_ = value
            else:
                try:
                    enum_member._value_ = enum_class._member_type_(*args)
                except Exception as exc:
                    new_exc = TypeError(
                            '_value_ not set in __new__, unable to create it'
                            )
                    new_exc.__cause__ = exc
>                   raise new_exc
E                   TypeError: _value_ not set in __new__, unable to create it
```


### Versions

<details>

```
See anndata test failure
```

</details>



Discussion:

Resolving patch:
diff --git a/scanpy/__init__.py b/scanpy/__init__.py
--- a/scanpy/__init__.py
+++ b/scanpy/__init__.py
@@ -1,6 +1,8 @@
 """Single-Cell Analysis in Python."""
 from __future__ import annotations
 
+import sys
+
 try:  # See https://github.com/maresb/hatch-vcs-footgun-example
     from setuptools_scm import get_version
 
@@ -21,6 +23,11 @@
 
 # the actual API
 # (start with settings as several tools are using it)
+
+from ._settings import Verbosity, settings
+
+set_figure_params = settings.set_figure_params
+
 from anndata import (
     AnnData,
     concat,
@@ -38,15 +45,10 @@
 from . import plotting as pl
 from . import preprocessing as pp
 from . import tools as tl
-from ._settings import Verbosity, settings
 from .neighbors import Neighbors
 from .readwrite import read, read_10x_h5, read_10x_mtx, read_visium, write
 
-set_figure_params = settings.set_figure_params
-
 # has to be done at the end, after everything has been imported
-import sys
-
 sys.modules.update({f"{__name__}.{m}": globals()[m] for m in ["tl", "pp", "pl"]})
 from ._utils import annotate_doc_types
 


Test patch:
diff --git a/scanpy/testing/_doctests.py b/scanpy/testing/_doctests.py
--- a/scanpy/testing/_doctests.py
+++ b/scanpy/testing/_doctests.py
@@ -9,22 +9,8 @@
 def doctest_needs(mod: str) -> Callable[[F], F]:
     """Mark function with doctest dependency."""
 
-    try:
-        from ._pytest.marks import needs
-    except ImportError:
-        mark = None
-    else:
-        try:
-            mark = needs[mod]
-        except KeyError:
-            raise KeyError(
-                f"Unknown dependency {mod}. If it isn’t a typo, "
-                "please add it to `needs` enum in `scanpy.testing._pytests.marks`."
-            ) from None
-
     def decorator(func: F) -> F:
-        if mark is not None:
-            func._doctest_needs = mark
+        func._doctest_needs = mod
         return func
 
     return decorator
diff --git a/scanpy/testing/_pytest/__init__.py b/scanpy/testing/_pytest/__init__.py
--- a/scanpy/testing/_pytest/__init__.py
+++ b/scanpy/testing/_pytest/__init__.py
@@ -10,12 +10,11 @@
 
 from ..._utils import _import_name
 from .fixtures import *  # noqa: F403
+from .marks import needs
 
 if TYPE_CHECKING:
     from collections.abc import Generator, Iterable
 
-    from .marks import needs
-
 
 # Defining it here because it’s autouse.
 @pytest.fixture(autouse=True)
@@ -113,9 +112,9 @@ def _modify_doctests(request: pytest.FixtureRequest) -> None:
     request.getfixturevalue("_doctest_env")
 
     func = _import_name(request.node.name)
-    needs_marker: needs | None
-    if needs_marker := getattr(func, "_doctest_needs", None):
-        assert needs_marker.mark.name == "skipif"
+    needs_mod: str | None
+    if needs_mod := getattr(func, "_doctest_needs", None):
+        needs_marker = needs[needs_mod]
         if needs_marker.mark.args[0]:
             pytest.skip(reason=needs_marker.mark.kwargs["reason"])
     skip_reason: str | None
diff --git a/scanpy/testing/_pytest/marks.py b/scanpy/testing/_pytest/marks.py
--- a/scanpy/testing/_pytest/marks.py
+++ b/scanpy/testing/_pytest/marks.py
@@ -57,4 +57,4 @@ def __init__(self, mod: str) -> None:
         if self._name_.casefold() != mod.casefold().replace("-", "_"):
             reason = f"{reason} (`pip install {mod}`)"
         dec = pytest.mark.skipif(not find_spec(self._name_), reason=reason)
-        super().__init__(dec.mark)
+        super().__init__(dec.mark, _ispytest=True)