Skip to content

Commit c9a06dd

Browse files
committed
document defaults
1 parent 8a626c2 commit c9a06dd

File tree

1 file changed

+54
-10
lines changed

1 file changed

+54
-10
lines changed

src/scanpy/_settings.py

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
from __future__ import annotations
22

33
import inspect
4+
import re
45
import sys
56
from contextlib import contextmanager
67
from enum import EnumMeta, IntEnum, StrEnum, auto
7-
from functools import cached_property
8+
from functools import cached_property, partial, wraps
89
from logging import getLevelNamesMapping
910
from pathlib import Path
1011
from time import time
11-
from typing import TYPE_CHECKING, Literal, get_args
12+
from typing import TYPE_CHECKING, Literal, LiteralString, TypeVar, get_args
1213

1314
from . import logging
1415
from ._compat import deprecated, old_positionals
1516
from ._singleton import SingletonMeta
1617
from .logging import _RootLogger, _set_log_file, _set_log_level
1718

1819
if TYPE_CHECKING:
19-
from collections.abc import Generator, Iterable
20+
from collections.abc import Callable, Generator, Iterable, Mapping
2021
from typing import Any, ClassVar, Self, TextIO
2122

2223
from ._types import HVGFlavor
@@ -30,10 +31,50 @@
3031
_VerbosityName = Literal["error", "warning", "info", "hint", "debug"]
3132
_LoggingLevelName = Literal["CRITICAL", "ERROR", "WARNING", "INFO", "HINT", "DEBUG"]
3233

34+
T = TypeVar("T", bound=LiteralString)
35+
3336

3437
AnnDataFileFormat = Literal["h5ad", "zarr"]
3538

3639

40+
_preset_postprocessors: list[Callable[[], None]] = []
41+
42+
43+
def _postprocess_preset_prop(
44+
prop: cached_property[T],
45+
param: str,
46+
get_map: Callable[[], Mapping[Preset, LiteralString]],
47+
) -> None:
48+
map = get_map()
49+
50+
map_type = inspect.signature(get_map).return_annotation
51+
value_type = re.fullmatch(r"Mapping\[Preset, (.*)\]", map_type)[1]
52+
53+
added_doc = "\n".join(
54+
f":attr:`{k.name}`\n Default: `{param}={v!r}`" for k, v in map.items()
55+
)
56+
57+
prop.__doc__ = f"{prop.__doc__}\n\n{added_doc}"
58+
prop.func.__annotations__["return"] = value_type
59+
60+
61+
def _preset_property(
62+
param: str,
63+
) -> Callable[[Callable[[], Mapping[Preset, T]]], cached_property[T]]:
64+
def decorator(get_map: Callable[[], Mapping[Preset, T]]) -> cached_property[T]:
65+
@wraps(get_map)
66+
def get(self: Preset) -> T:
67+
return get_map()[self]
68+
69+
prop = cached_property(get)
70+
_preset_postprocessors.append(
71+
partial(_postprocess_preset_prop, prop, param, get_map)
72+
)
73+
return prop
74+
75+
return decorator
76+
77+
3778
class Preset(StrEnum):
3879
"""Presets for :attr:`scanpy.settings.preset`.
3980
@@ -46,14 +87,17 @@ class Preset(StrEnum):
4687
SeuratV5 = auto()
4788
"""Try to match Seurat 5.* as closely as possible."""
4889

49-
@cached_property
50-
def highly_variable_genes(self) -> HVGFlavor:
90+
@_preset_property("flavor")
91+
def highly_variable_genes() -> Mapping[Preset, HVGFlavor]:
5192
"""Flavor for :func:`~scanpy.pp.highly_variable_genes`."""
52-
match self:
53-
case Preset.ScanpyV1:
54-
return "seurat"
55-
case Preset.SeuratV5:
56-
return "seurat_v3"
93+
return {
94+
Preset.ScanpyV1: "seurat",
95+
Preset.SeuratV5: "seurat_v3",
96+
}
97+
98+
99+
for _postprocess in _preset_postprocessors:
100+
_postprocess()
57101

58102

59103
_VERBOSITY_TO_LOGLEVEL: dict[int | _VerbosityName, _LoggingLevelName] = {

0 commit comments

Comments
 (0)