Skip to content

Add Pylint lints #3577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmarks/benchmarks/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


def setup():
global adata
global adata # noqa: PLW0603
adata = pbmc68k_reduced()
assert "X_pca" in adata.obsm

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

HERE = Path(__file__).parent
sys.path[:0] = [str(HERE.parent), str(HERE / "extensions")]
import scanpy # noqa
import scanpy

if TYPE_CHECKING:
from sphinx.application import Sphinx
Expand Down
4 changes: 2 additions & 2 deletions docs/extensions/debug_docstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
_pd_orig = sphinx.ext.napoleon._process_docstring


def pd_new(app, what, name, obj, options, lines): # noqa: PLR0917
def pd_new(app, what, name, obj, options, lines) -> None: # noqa: PLR0917
"""Wrap ``sphinx.ext.napoleon._process_docstring``."""
_pd_orig(app, what, name, obj, options, lines)
print(*lines, sep="\n")


def setup(app: Sphinx):
def setup(app: Sphinx) -> None:
"""App setup hook."""
if os.environ.get("DEBUG") is not None:
sphinx.ext.napoleon._process_docstring = pd_new
4 changes: 2 additions & 2 deletions docs/extensions/function_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

def insert_function_images( # noqa: PLR0917
app: Sphinx, what: str, name: str, obj: Any, options: Options, lines: list[str]
):
) -> None:
"""Insert images for plot functions."""
path = app.config.api_dir / f"{name}.png"
if what != "function" or not path.is_file():
Expand All @@ -27,7 +27,7 @@ def insert_function_images( # noqa: PLR0917
]


def setup(app: Sphinx):
def setup(app: Sphinx) -> None:
"""App setup hook."""
app.add_config_value("api_dir", Path(), "env")
app.connect("autodoc-process-docstring", insert_function_images)
64 changes: 36 additions & 28 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -226,55 +226,58 @@ docstring-code-format = true

[tool.ruff.lint]
select = [
"B", # Likely bugs and design issues
"D", # Documentation style
"E", # Error detected by Pycodestyle
"EM", # Traceback-friendly error messages
"F", # Errors detected by Pyflakes
"FBT", # No positional boolean parameters
"I", # Import sorting
"ICN", # Follow import conventions
"PIE", # Syntax simplifications
"PLR0917", # Ban APIs with too many positional parameters
"PT", # Pytest style
"PTH", # Pathlib instead of os.path
"PYI", # Typing
"SIM", # Simplify control flow
"TC", # Manage type checking blocks
"UP", # Update legacy syntax
"TID251", # Banned imports
"W", # Warning detected by Pycodestyle
"B", # Likely bugs and design issues
"D", # Documentation style
"E", # Error detected by Pycodestyle
"EM", # Traceback-friendly error messages
"F", # Errors detected by Pyflakes
"FBT", # No positional boolean parameters
"I", # Import sorting
"ICN", # Follow import conventions
"PIE", # Syntax simplifications
"PL", # Pylint
"PT", # Pytest style
"PTH", # Pathlib instead of os.path
"PYI", # Typing
"RUF100", # Unused noqa
"SIM", # Simplify control flow
"TC", # Manage type checking blocks
"UP", # Update legacy syntax
"TID251", # Banned imports
"W", # Warning detected by Pycodestyle
]
external = [ "PLR0917" ] # preview lint that we use
ignore = [
# line too long -> we accept long comment lines; black gets rid of long code lines
"E501",
# module level import not at top of file -> required to circumvent circular imports for Scanpys API
"E402",
# E266 too many leading '#' for block comment -> Scanpy allows them for comments into sections
"E262",
# module level import not at top of file -> required to circumvent circular imports for Scanpys API
"E402",
# line too long -> we accept long comment lines; black gets rid of long code lines
"E501",
# allow I, O, l as variable names -> I is the identity matrix, i, j, k, l is reasonable indexing notation
"E741",
# `Literal["..."] | str` is useful for autocompletion
"PYI051",
# We ban blank lines before docstrings instead of the opposite
"D203",
# We want multiline summaries to start on the first line, not the second
"D213",
# TODO: replace our current param docs reuse with this and remove it here:
"D417",
# Numbers like “2” aren’t that “magic”.
"PLR2004",
# `Literal["..."] | str` is useful for autocompletion
"PYI051",
]
[tool.ruff.lint.per-file-ignores]
# Do not assign a lambda expression, use a def
"src/scanpy/tools/_rank_genes_groups.py" = [ "E731" ]
# No need for docstrings for all benchmarks
"benchmarks/**/*.py" = [ "D102", "D103" ]
# No need for docstrings for all test modules and test functions
"tests/**/*.py" = [ "D100", "D101", "D103" ]
# D*: No need for docstrings for all test modules and test functions
# PLR0913: Test may use many fixtures
"tests/**/*.py" = [ "D100", "D101", "D103", "PLR0913" ]
[tool.ruff.lint.isort]
known-first-party = [ "scanpy", "testing.scanpy" ]
required-imports = [ "from __future__ import annotations" ]
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"pytest.importorskip".msg = "Use the “@needs” decorator/mark instead"
"pandas.api.types.is_categorical_dtype".msg = "Use isinstance(s.dtype, CategoricalDtype) instead"
Expand All @@ -290,6 +293,11 @@ convention = "numpy"
[tool.ruff.lint.flake8-type-checking]
exempt-modules = [ ]
strict = true
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.lint.pylint]
max-args = 10
max-positional-args = 5

[tool.towncrier]
name = "scanpy"
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class ScanpyConfig:
N_PCS: int
"""Default number of principal components to use."""

def __init__(
def __init__( # noqa: PLR0913
self,
*,
verbosity: Verbosity | int | str = Verbosity.warning,
Expand Down Expand Up @@ -406,7 +406,7 @@ def categories_to_ignore(self, categories_to_ignore: Iterable[str]):
"transparent",
"ipython_format",
)
def set_figure_params(
def set_figure_params( # noqa: PLR0913
self,
*,
scanpy: bool = True,
Expand Down
10 changes: 6 additions & 4 deletions src/scanpy/_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,10 @@
return decorator


def _import_name(name: str) -> Any:
def _import_name(full_name: str) -> Any:
from importlib import import_module

parts = name.split(".")
parts = full_name.split(".")
obj = import_module(parts[0])
for _i, name in enumerate(parts[1:]):
i = _i
Expand Down Expand Up @@ -387,7 +387,7 @@
asso_matrix: list[list[float]] = []
for ipred_group, pred_group in enumerate(adata.obs[prediction].cat.categories):
if "?" in pred_group:
pred_group = str(ipred_group)
pred_group = str(ipred_group) # noqa: PLW2901

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

View check run for this annotation

Codecov / codecov/patch

src/scanpy/_utils/__init__.py#L390

Added line #L390 was not covered by tests
# starting from numpy version 1.13, subtractions of boolean arrays are deprecated
mask_pred = adata.obs[prediction].values == pred_group
mask_pred_int = mask_pred.astype(np.int8)
Expand Down Expand Up @@ -927,7 +927,9 @@
return groups_order_subset, groups_masks_obs


def warn_with_traceback(message, category, filename, lineno, file=None, line=None): # noqa: PLR0917
def warn_with_traceback( # noqa: PLR0917
message, category, filename, lineno, file=None, line=None
) -> None:
"""Get full tracebacks when warning is raised by setting.

warnings.showwarning = warn_with_traceback
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/experimental/pp/_highly_variable_genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def clac_clipped_res_dense(gene: int, cell: int) -> np.float64:
return residuals


def _highly_variable_pearson_residuals(
def _highly_variable_pearson_residuals( # noqa: PLR0912, PLR0915
adata: AnnData,
*,
theta: float = 100,
Expand Down Expand Up @@ -308,7 +308,7 @@ def _highly_variable_pearson_residuals(
layer=doc_layer,
inplace=doc_inplace,
)
def highly_variable_genes(
def highly_variable_genes( # noqa: PLR0913
adata: AnnData,
*,
theta: float = 100,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/experimental/pp/_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
check_values=doc_check_values,
inplace=doc_inplace,
)
def recipe_pearson_residuals(
def recipe_pearson_residuals( # noqa: PLR0913
adata: AnnData,
*,
theta: float = 100,
Expand Down
25 changes: 11 additions & 14 deletions src/scanpy/external/exporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"neighbors_key",
"overwrite",
)
def spring_project(
def spring_project( # noqa: PLR0912, PLR0915
adata: AnnData,
project_dir: Path | str,
embedding_method: str,
Expand Down Expand Up @@ -90,17 +90,16 @@
if embedding_method not in adata.obsm_keys():
if "X_" + embedding_method in adata.obsm_keys():
embedding_method = "X_" + embedding_method
elif embedding_method in adata.uns:
embedding_method = (

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

View check run for this annotation

Codecov / codecov/patch

src/scanpy/external/exporting.py#L93-L94

Added lines #L93 - L94 were not covered by tests
"X_"
+ embedding_method
+ "_"
+ adata.uns[embedding_method]["params"]["layout"]
)
else:
if embedding_method in adata.uns:
embedding_method = (
"X_"
+ embedding_method
+ "_"
+ adata.uns[embedding_method]["params"]["layout"]
)
else:
msg = f"Run the specified embedding method `{embedding_method}` first."
raise ValueError(msg)
msg = f"Run the specified embedding method `{embedding_method}` first."
raise ValueError(msg)

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

View check run for this annotation

Codecov / codecov/patch

src/scanpy/external/exporting.py#L101-L102

Added lines #L101 - L102 were not covered by tests

coords = adata.obsm[embedding_method]

Expand Down Expand Up @@ -477,8 +476,6 @@

Path(outpath).write_text(json.dumps(PAGA_data, indent=4))

return None


@old_positionals(
"embedding_keys",
Expand All @@ -490,7 +487,7 @@
"port",
"do_debug",
)
def cellbrowser(
def cellbrowser( # noqa: PLR0913
adata: AnnData,
data_dir: Path | str,
data_name: str,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pl.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def sam(
"ax",
)
@_doc_params(show_save_ax=doc_show_save_ax)
def wishbone_marker_trajectory(
def wishbone_marker_trajectory( # noqa: PLR0913
adata: AnnData,
markers: Collection[str],
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pp/_bbknn.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

@old_positionals("batch_key", "use_rep", "approx", "use_annoy", "metric", "copy")
@doctest_needs("bbknn")
def bbknn(
def bbknn( # noqa: PLR0913
adata: AnnData,
*,
batch_key: str = "batch",
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pp/_dca.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"return_info",
"copy",
)
def dca(
def dca( # noqa: PLR0913
adata: AnnData,
mode: Literal["denoise", "latent"] = "denoise",
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pp/_hashsolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from numpy.typing import ArrayLike, NDArray


def _calculate_log_likelihoods(
def _calculate_log_likelihoods( # noqa: PLR0915
data: np.ndarray, number_of_noise_barcodes: int
) -> tuple[NDArray[np.float64], NDArray[np.float64], dict[int, str]]:
"""Calculate log likelihoods for each hypothesis, negative, singlet, doublet.
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pp/_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


@doctest_needs("magic")
def magic(
def magic( # noqa: PLR0913
adata: AnnData,
name_list: Literal["all_genes", "pca_only"] | Sequence[str] | None = None,
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/pp/_mnn_correct.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from anndata import AnnData


def mnn_correct(
def mnn_correct( # noqa: PLR0913
*datas: AnnData | np.ndarray,
var_index: Collection[str] | None = None,
var_subset: Collection[str] | None = None,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/tl/_phate.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"copy",
)
@doctest_needs("phate")
def phate(
def phate( # noqa: PLR0913
adata: AnnData,
n_components: int = 2,
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/tl/_phenograph.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"copy",
)
@doctest_needs("phenograph")
def phenograph(
def phenograph( # noqa: PLR0913
data: AnnData | np.ndarray | SpBase,
clustering_algo: Literal["louvain", "leiden"] | None = "louvain",
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/tl/_sam.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"verbose",
)
@doctest_needs("samalg")
def sam(
def sam( # noqa: PLR0913
adata: AnnData,
*,
max_iter: int = 10,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/external/tl/_trimap.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"copy",
)
@doctest_needs("trimap")
def trimap(
def trimap( # noqa: PLR0913
adata: AnnData,
n_components: int = 2,
*,
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/get/_aggregated.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ def _power(X: Array, power: float) -> Array:
return X**power if isinstance(X, np.ndarray) else X.power(power)


def aggregate(
def aggregate( # noqa: PLR0912
adata: AnnData,
by: str | Collection[str],
func: AggType | Iterable[AggType],
Expand Down
2 changes: 1 addition & 1 deletion src/scanpy/get/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@


# TODO: implement diffxpy method, make singledispatch
def rank_genes_groups_df(
def rank_genes_groups_df( # noqa: PLR0912
adata: AnnData,
group: str | Iterable[str] | None,
*,
Expand Down
Loading
Loading