Skip to content

Commit

Permalink
add EM to ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep committed Jan 13, 2025
1 parent 903f0b0 commit 977ae5d
Show file tree
Hide file tree
Showing 72 changed files with 539 additions and 368 deletions.
3 changes: 2 additions & 1 deletion docs/extensions/param_police.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def show_param_warnings(app, exception):
line,
)
if param_warnings:
raise RuntimeError("Encountered text parameter type. Use annotations.")
msg = "Encountered text parameter type. Use annotations."
raise RuntimeError(msg)


def setup(app: Sphinx):
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ select = [
"W", # Warning detected by Pycodestyle
"UP", # pyupgrade
"I", # isort
"TCH", # manage type checking blocks
"TC", # manage type checking blocks
"TID251", # Banned imports
"ICN", # Follow import conventions
"PTH", # Pathlib instead of os.path
Expand All @@ -239,6 +239,7 @@ select = [
"FBT", # No positional boolean parameters
"PT", # Pytest style
"SIM", # Simplify control flow
"EM", # Traceback-friendly error messages
]
ignore = [
# line too long -> we accept long comment lines; black gets rid of long code lines
Expand Down
5 changes: 2 additions & 3 deletions src/scanpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
try:
from ._version import __version__
except ModuleNotFoundError:
raise RuntimeError(
"scanpy is not correctly installed. Please install it, e.g. with pip."
)
msg = "scanpy is not correctly installed. Please install it, e.g. with pip."
raise RuntimeError(msg)

from ._utils import check_versions

Expand Down
12 changes: 8 additions & 4 deletions src/scanpy/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ def _type_check(var: Any, varname: str, types: type | tuple[type, ...]):
else:
type_names = [t.__name__ for t in types]
possible_types_str = f"{', '.join(type_names[:-1])} or {type_names[-1]}"
raise TypeError(f"{varname} must be of type {possible_types_str}")
msg = f"{varname} must be of type {possible_types_str}"
raise TypeError(msg)

Check warning on line 87 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L86-L87

Added lines #L86 - L87 were not covered by tests


class ScanpyConfig:
Expand Down Expand Up @@ -180,10 +181,11 @@ def verbosity(self, verbosity: Verbosity | int | str):
elif isinstance(verbosity, str):
verbosity = verbosity.lower()
if verbosity not in verbosity_str_options:
raise ValueError(
msg = (

Check warning on line 184 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L184

Added line #L184 was not covered by tests
f"Cannot set verbosity to {verbosity}. "
f"Accepted string values are: {verbosity_str_options}"
)
raise ValueError(msg)

Check warning on line 188 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L188

Added line #L188 was not covered by tests
else:
self._verbosity = Verbosity(verbosity_str_options.index(verbosity))
else:
Expand Down Expand Up @@ -214,10 +216,11 @@ def file_format_data(self, file_format: str):
_type_check(file_format, "file_format_data", str)
file_format_options = {"txt", "csv", "h5ad"}
if file_format not in file_format_options:
raise ValueError(
msg = (

Check warning on line 219 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L219

Added line #L219 was not covered by tests
f"Cannot set file_format_data to {file_format}. "
f"Must be one of {file_format_options}"
)
raise ValueError(msg)

Check warning on line 223 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L223

Added line #L223 was not covered by tests
self._file_format_data = file_format

@property
Expand Down Expand Up @@ -322,10 +325,11 @@ def cache_compression(self) -> str | None:
@cache_compression.setter
def cache_compression(self, cache_compression: str | None):
if cache_compression not in {"lzf", "gzip", None}:
raise ValueError(
msg = (

Check warning on line 328 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L328

Added line #L328 was not covered by tests
f"`cache_compression` ({cache_compression}) "
"must be in {'lzf', 'gzip', None}"
)
raise ValueError(msg)

Check warning on line 332 in src/scanpy/_settings.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_settings.py#L332

Added line #L332 was not covered by tests
self._cache_compression = cache_compression

@property
Expand Down
60 changes: 32 additions & 28 deletions src/scanpy/_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ def __getattr__(self, attr: str):
def ensure_igraph() -> None:
if importlib.util.find_spec("igraph"):
return
raise ImportError(
msg = (

Check warning on line 96 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L96

Added line #L96 was not covered by tests
"Please install the igraph package: "
"`conda install -c conda-forge python-igraph` or "
"`pip3 install igraph`."
)
raise ImportError(msg)

Check warning on line 101 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L101

Added line #L101 was not covered by tests


@contextmanager
Expand All @@ -120,10 +121,11 @@ def check_versions():
if Version(anndata_version) < Version("0.6.10"):
from .. import __version__

raise ImportError(
msg = (

Check warning on line 124 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L124

Added line #L124 was not covered by tests
f"Scanpy {__version__} needs anndata version >=0.6.10, "
f"not {anndata_version}.\nRun `pip install anndata -U --no-deps`."
)
raise ImportError(msg)

Check warning on line 128 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L128

Added line #L128 was not covered by tests


def getdoc(c_or_f: Callable | type) -> str | None:
Expand Down Expand Up @@ -256,9 +258,8 @@ def _check_array_function_arguments(**kwargs):
# TODO: Figure out a better solution for documenting dispatched functions
invalid_args = [k for k, v in kwargs.items() if v is not None]
if len(invalid_args) > 0:
raise TypeError(
f"Arguments {invalid_args} are only valid if an AnnData object is passed."
)
msg = f"Arguments {invalid_args} are only valid if an AnnData object is passed."
raise TypeError(msg)

Check warning on line 262 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L261-L262

Added lines #L261 - L262 were not covered by tests


def _check_use_raw(
Expand Down Expand Up @@ -351,9 +352,8 @@ def compute_association_matrix_of_groups(
reference labels, entries are proportional to degree of association.
"""
if normalization not in {"prediction", "reference"}:
raise ValueError(
'`normalization` needs to be either "prediction" or "reference".'
)
msg = '`normalization` needs to be either "prediction" or "reference".'
raise ValueError(msg)

Check warning on line 356 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L355-L356

Added lines #L355 - L356 were not covered by tests
sanitize_anndata(adata)
cats = adata.obs[reference].cat.categories
for cat in cats:
Expand Down Expand Up @@ -604,7 +604,8 @@ def broadcast_axis(divisor: Scaling_T, axis: Literal[0, 1]) -> Scaling_T:

def check_op(op):
if op not in {truediv, mul}:
raise ValueError(f"{op} not one of truediv or mul")
msg = f"{op} not one of truediv or mul"
raise ValueError(msg)


@singledispatch
Expand Down Expand Up @@ -639,9 +640,8 @@ def _(
) -> sparse.csr_matrix | sparse.csc_matrix:
check_op(op)
if out is not None and X.data is not out.data:
raise ValueError(
"`out` argument provided but not equal to X. This behavior is not supported for sparse matrix scaling."
)
msg = "`out` argument provided but not equal to X. This behavior is not supported for sparse matrix scaling."
raise ValueError(msg)
if not allow_divide_by_zero and op is truediv:
scaling_array = scaling_array.copy() + (scaling_array == 0)

Expand Down Expand Up @@ -697,9 +697,8 @@ def _(
) -> DaskArray:
check_op(op)
if out is not None:
raise TypeError(
"`out` is not `None`. Do not do in-place modifications on dask arrays."
)
msg = "`out` is not `None`. Do not do in-place modifications on dask arrays."
raise TypeError(msg)

import dask.array as da

Expand Down Expand Up @@ -805,9 +804,8 @@ def sum_drop_keepdims(*args, **kwargs):
axis = kwargs["axis"]
if isinstance(axis, tuple):
if len(axis) != 1:
raise ValueError(
f"`axis_sum` can only sum over one axis when `axis` arg is provided but got {axis} instead"
)
msg = f"`axis_sum` can only sum over one axis when `axis` arg is provided but got {axis} instead"
raise ValueError(msg)

Check warning on line 808 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L807-L808

Added lines #L807 - L808 were not covered by tests
kwargs["axis"] = axis[0]
# returns a np.matrix normally, which is undesireable
return np.array(np.sum(*args, dtype=dtype, **kwargs))
Expand Down Expand Up @@ -959,7 +957,8 @@ def subsample(
Xsampled = np.array(X[rows])
else:
if seed < 0:
raise ValueError(f"Invalid seed value < 0: {seed}")
msg = f"Invalid seed value < 0: {seed}"
raise ValueError(msg)

Check warning on line 961 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L960-L961

Added lines #L960 - L961 were not covered by tests
n = int(X.shape[0] / subsample)
np.random.seed(seed)
Xsampled, rows = subsample_n(X, n=n)
Expand Down Expand Up @@ -989,7 +988,8 @@ def subsample_n(
Indices of rows that are stored in Xsampled.
"""
if n < 0:
raise ValueError("n must be greater 0")
msg = "n must be greater 0"
raise ValueError(msg)

Check warning on line 992 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L991-L992

Added lines #L991 - L992 were not covered by tests
np.random.seed(seed)
n = X.shape[0] if (n == 0 or n > X.shape[0]) else n
rows = np.random.choice(X.shape[0], size=n, replace=False)
Expand Down Expand Up @@ -1069,13 +1069,15 @@ def __init__(self, adata: AnnData, key=None):

if key is None or key == "neighbors":
if "neighbors" not in adata.uns:
raise KeyError('No "neighbors" in .uns')
msg = 'No "neighbors" in .uns'
raise KeyError(msg)

Check warning on line 1073 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L1072-L1073

Added lines #L1072 - L1073 were not covered by tests
self._neighbors_dict = adata.uns["neighbors"]
self._conns_key = "connectivities"
self._dists_key = "distances"
else:
if key not in adata.uns:
raise KeyError(f'No "{key}" in .uns')
msg = f'No "{key}" in .uns'
raise KeyError(msg)

Check warning on line 1080 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L1079-L1080

Added lines #L1079 - L1080 were not covered by tests
self._neighbors_dict = adata.uns[key]
self._conns_key = self._neighbors_dict["connectivities_key"]
self._dists_key = self._neighbors_dict["distances_key"]
Expand Down Expand Up @@ -1108,11 +1110,13 @@ def __getitem__(self, key: Literal["connectivities_key"]) -> str: ...
def __getitem__(self, key: str):
if key == "distances":
if "distances" not in self:
raise KeyError(f'No "{self._dists_key}" in .obsp')
msg = f'No "{self._dists_key}" in .obsp'
raise KeyError(msg)

Check warning on line 1114 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L1113-L1114

Added lines #L1113 - L1114 were not covered by tests
return self._distances
elif key == "connectivities":
if "connectivities" not in self:
raise KeyError(f'No "{self._conns_key}" in .obsp')
msg = f'No "{self._conns_key}" in .obsp'
raise KeyError(msg)

Check warning on line 1119 in src/scanpy/_utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L1118-L1119

Added lines #L1118 - L1119 were not covered by tests
return self._connectivities
elif key == "connectivities_key":
return self._conns_key
Expand Down Expand Up @@ -1153,7 +1157,8 @@ def _resolve_axis(
return (0, "obs")
if axis in {1, "var"}:
return (1, "var")
raise ValueError(f"`axis` must be either 0, 1, 'obs', or 'var', was {axis!r}")
msg = f"`axis` must be either 0, 1, 'obs', or 'var', was {axis!r}"
raise ValueError(msg)


def is_backed_type(X: object) -> bool:
Expand All @@ -1162,6 +1167,5 @@ def is_backed_type(X: object) -> bool:

def raise_not_implemented_error_if_backed_type(X: object, method_name: str) -> None:
if is_backed_type(X):
raise NotImplementedError(
f"{method_name} is not implemented for matrices of type {type(X)}"
)
msg = f"{method_name} is not implemented for matrices of type {type(X)}"
raise NotImplementedError(msg)
3 changes: 2 additions & 1 deletion src/scanpy/_utils/_doctests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def decorator(func: F) -> F:
def doctest_skip(reason: str) -> Callable[[F], F]:
"""Mark function so doctest is skipped."""
if not reason:
raise ValueError("reason must not be empty")
msg = "reason must not be empty"
raise ValueError(msg)

Check warning on line 23 in src/scanpy/_utils/_doctests.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/_doctests.py#L22-L23

Added lines #L22 - L23 were not covered by tests

def decorator(func: F) -> F:
func._doctest_skip_reason = reason
Expand Down
6 changes: 4 additions & 2 deletions src/scanpy/_utils/compute/is_constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ def _check_axis_supported(wrapped: C) -> C:
def func(a, axis=None):
if axis is not None:
if not isinstance(axis, Integral):
raise TypeError("axis must be integer or None.")
msg = "axis must be integer or None."
raise TypeError(msg)

Check warning on line 28 in src/scanpy/_utils/compute/is_constant.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/compute/is_constant.py#L27-L28

Added lines #L27 - L28 were not covered by tests
if axis not in (0, 1):
raise NotImplementedError("We only support axis 0 and 1 at the moment")
msg = "We only support axis 0 and 1 at the moment"
raise NotImplementedError(msg)

Check warning on line 31 in src/scanpy/_utils/compute/is_constant.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/compute/is_constant.py#L30-L31

Added lines #L30 - L31 were not covered by tests
return wrapped(a, axis)

return func
Expand Down
17 changes: 10 additions & 7 deletions src/scanpy/experimental/pp/_highly_variable_genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ def _highly_variable_pearson_residuals(
if theta <= 0:
# TODO: would "underdispersion" with negative theta make sense?
# then only theta=0 were undefined..
raise ValueError("Pearson residuals require theta > 0")
msg = "Pearson residuals require theta > 0"
raise ValueError(msg)
# prepare clipping

if batch_key is None:
Expand All @@ -185,7 +186,8 @@ def _highly_variable_pearson_residuals(
n = X_batch.shape[0]
clip = np.sqrt(n)
if clip < 0:
raise ValueError("Pearson residuals require `clip>=0` or `clip=None`.")
msg = "Pearson residuals require `clip>=0` or `clip=None`."
raise ValueError(msg)

if sp_sparse.issparse(X_batch):
X_batch = X_batch.tocsc()
Expand Down Expand Up @@ -378,17 +380,19 @@ def highly_variable_genes(
logg.info("extracting highly variable genes")

if not isinstance(adata, AnnData):
raise ValueError(
msg = (

Check warning on line 383 in src/scanpy/experimental/pp/_highly_variable_genes.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_highly_variable_genes.py#L383

Added line #L383 was not covered by tests
"`pp.highly_variable_genes` expects an `AnnData` argument, "
"pass `inplace=False` if you want to return a `pd.DataFrame`."
)
raise ValueError(msg)

Check warning on line 387 in src/scanpy/experimental/pp/_highly_variable_genes.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_highly_variable_genes.py#L387

Added line #L387 was not covered by tests

if flavor == "pearson_residuals":
if n_top_genes is None:
raise ValueError(
msg = (

Check warning on line 391 in src/scanpy/experimental/pp/_highly_variable_genes.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_highly_variable_genes.py#L391

Added line #L391 was not covered by tests
"`pp.highly_variable_genes` requires the argument `n_top_genes`"
" for `flavor='pearson_residuals'`"
)
raise ValueError(msg)

Check warning on line 395 in src/scanpy/experimental/pp/_highly_variable_genes.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_highly_variable_genes.py#L395

Added line #L395 was not covered by tests
return _highly_variable_pearson_residuals(
adata,
layer=layer,
Expand All @@ -402,6 +406,5 @@ def highly_variable_genes(
inplace=inplace,
)
else:
raise ValueError(
"This is an experimental API and only `flavor=pearson_residuals` is available."
)
msg = "This is an experimental API and only `flavor=pearson_residuals` is available."
raise ValueError(msg)

Check warning on line 410 in src/scanpy/experimental/pp/_highly_variable_genes.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_highly_variable_genes.py#L409-L410

Added lines #L409 - L410 were not covered by tests
9 changes: 6 additions & 3 deletions src/scanpy/experimental/pp/_normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ def _pearson_residuals(X, theta, clip, check_values, *, copy: bool = False):
if theta <= 0:
# TODO: would "underdispersion" with negative theta make sense?
# then only theta=0 were undefined..
raise ValueError("Pearson residuals require theta > 0")
msg = "Pearson residuals require theta > 0"
raise ValueError(msg)
# prepare clipping
if clip is None:
n = X.shape[0]
clip = np.sqrt(n)
if clip < 0:
raise ValueError("Pearson residuals require `clip>=0` or `clip=None`.")
msg = "Pearson residuals require `clip>=0` or `clip=None`."
raise ValueError(msg)

if check_values and not check_nonnegative_integers(X):
warn(
Expand Down Expand Up @@ -128,7 +130,8 @@ def normalize_pearson_residuals(

if copy:
if not inplace:
raise ValueError("`copy=True` cannot be used with `inplace=False`.")
msg = "`copy=True` cannot be used with `inplace=False`."
raise ValueError(msg)

Check warning on line 134 in src/scanpy/experimental/pp/_normalization.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/experimental/pp/_normalization.py#L133-L134

Added lines #L133 - L134 were not covered by tests
adata = adata.copy()

view_to_actual(adata)
Expand Down
8 changes: 4 additions & 4 deletions src/scanpy/external/exporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ def spring_project(
neighbors_key = "neighbors"

if neighbors_key not in adata.uns:
raise ValueError("Run `sc.pp.neighbors` first.")
msg = "Run `sc.pp.neighbors` first."
raise ValueError(msg)

Check warning on line 90 in src/scanpy/external/exporting.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/external/exporting.py#L89-L90

Added lines #L89 - L90 were not covered by tests

# check that requested 2-D embedding has been generated
if embedding_method not in adata.obsm_keys():
Expand All @@ -101,9 +102,8 @@ def spring_project(
+ adata.uns[embedding_method]["params"]["layout"]
)
else:
raise ValueError(
f"Run the specified embedding method `{embedding_method}` first."
)
msg = f"Run the specified embedding method `{embedding_method}` first."
raise ValueError(msg)

Check warning on line 106 in src/scanpy/external/exporting.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/external/exporting.py#L105-L106

Added lines #L105 - L106 were not covered by tests

coords = adata.obsm[embedding_method]

Expand Down
5 changes: 2 additions & 3 deletions src/scanpy/external/pl.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,8 @@ def sam(
try:
dt = adata.obsm[projection]
except KeyError:
raise ValueError(
"Please create a projection first using run_umap or run_tsne"
)
msg = "Please create a projection first using run_umap or run_tsne"
raise ValueError(msg)

Check warning on line 202 in src/scanpy/external/pl.py

View check run for this annotation

Codecov / codecov/patch

src/scanpy/external/pl.py#L201-L202

Added lines #L201 - L202 were not covered by tests
else:
dt = projection

Expand Down
Loading

0 comments on commit 977ae5d

Please sign in to comment.