Skip to content

Commit

Permalink
Merge branch 'main' into session-info2
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep authored Dec 12, 2024
2 parents ee43945 + 391d87a commit 4bd4a63
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.4
rev: v0.8.2
hooks:
- id: ruff
types_or: [python, pyi, jupyter]
Expand Down
107 changes: 74 additions & 33 deletions ci/scripts/min-deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import sys
from collections import deque
from contextlib import ExitStack
from functools import cached_property
from pathlib import Path
from typing import TYPE_CHECKING

Expand All @@ -25,6 +26,8 @@

if TYPE_CHECKING:
from collections.abc import Generator, Iterable, Sequence
from collections.abc import Set as AbstractSet
from typing import Any, Self


def min_dep(req: Requirement) -> Requirement:
Expand Down Expand Up @@ -77,48 +80,86 @@ def extract_min_deps(


class Args(argparse.Namespace):
path: Path
"""\
Parse a pyproject.toml file and output a list of minimum dependencies.
Output is optimized for `[uv] pip install` (see `-o`/`--output` for details).
"""

_path: Path
output: Path | None
extras: list[str]
_extras: list[str]
_all_extras: bool

@classmethod
def parse(cls, argv: Sequence[str] | None = None) -> Self:
return cls.parser().parse_args(argv, cls())

@classmethod
def parser(cls) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="min-deps",
description=cls.__doc__,
usage="pip install `python min-deps.py pyproject.toml`",
)
parser.add_argument(
"_path",
metavar="pyproject.toml",
type=Path,
help="Path to pyproject.toml to parse minimum dependencies from",
)
parser.add_argument(
"--extras",
dest="_extras",
metavar="EXTRA",
type=str,
nargs="*",
default=(),
help="extras to install",
)
parser.add_argument(
"--all-extras",
dest="_all_extras",
action="store_true",
help="get all extras",
)
parser.add_argument(
*("--output", "-o"),
metavar="FILE",
type=Path,
default=None,
help=(
"output file (default: stdout). "
"Without this option, output is space-separated for direct passing to `pip install`. "
"With this option, output written to a file newline-separated file usable as `requirements.txt` or `constraints.txt`."
),
)
return parser

@cached_property
def pyproject(self) -> dict[str, Any]:
return tomllib.loads(self._path.read_text())

@cached_property
def extras(self) -> AbstractSet[str]:
if self._extras:
if self._all_extras:
sys.exit("Cannot specify both --extras and --all-extras")
return dict.fromkeys(self._extras).keys()
if not self._all_extras:
return set()
return self.pyproject["project"]["optional-dependencies"].keys()


def main(argv: Sequence[str] | None = None) -> None:
parser = argparse.ArgumentParser(
prog="min-deps",
description=(
"Parse a pyproject.toml file and output a list of minimum dependencies. "
"Output is optimized for `[uv] pip install` (see `-o`/`--output` for details)."
),
usage="pip install `python min-deps.py pyproject.toml`",
)
parser.add_argument(
"path", type=Path, help="pyproject.toml to parse minimum dependencies from"
)
parser.add_argument(
"--extras", type=str, nargs="*", default=(), help="extras to install"
)
parser.add_argument(
*("--output", "-o"),
type=Path,
default=None,
help=(
"output file (default: stdout). "
"Without this option, output is space-separated for direct passing to `pip install`. "
"With this option, output written to a file newline-separated file usable as `requirements.txt` or `constraints.txt`."
),
)

args = parser.parse_args(argv, Args())

pyproject = tomllib.loads(args.path.read_text())
args = Args.parse(argv)

project_name = pyproject["project"]["name"]
project_name = args.pyproject["project"]["name"]
deps = [
*map(Requirement, pyproject["project"]["dependencies"]),
*map(Requirement, args.pyproject["project"]["dependencies"]),
*(Requirement(f"{project_name}[{extra}]") for extra in args.extras),
]

min_deps = extract_min_deps(deps, pyproject=pyproject)
min_deps = extract_min_deps(deps, pyproject=args.pyproject)

sep = "\n" if args.output else " "
with ExitStack() as stack:
Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/3393.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Upper-bound {mod}`sklearn` `<1.6.0` due to {issue}`dask/dask-ml#1002` {smaller}`Ilan Gold`
2 changes: 1 addition & 1 deletion hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ overrides.matrix.deps.env-vars = [
{ if = ["min"], key = "UV_CONSTRAINT", value = "ci/scanpy-min-deps.txt" },
]
overrides.matrix.deps.pre-install-commands = [
{ if = ["min"], value = "uv run ci/scripts/min-deps.py pyproject.toml -o ci/scanpy-min-deps.txt" },
{ if = ["min"], value = "uv run ci/scripts/min-deps.py pyproject.toml --all-extras -o ci/scanpy-min-deps.txt" },
]
overrides.matrix.deps.python = [
{ if = ["min"], value = "3.10" },
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ dependencies = [
"seaborn>=0.13",
"h5py>=3.7",
"tqdm",
"scikit-learn>=1.1",
"scikit-learn>=1.1,<1.6.0",
"statsmodels>=0.13",
"patsy!=1.0.0", # https://github.com/pydata/patsy/issues/215
"networkx>=2.7",
Expand Down
4 changes: 1 addition & 3 deletions src/scanpy/_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ def _type_check(var: Any, varname: str, types: type | tuple[type, ...]):
possible_types_str = types.__name__
else:
type_names = [t.__name__ for t in types]
possible_types_str = "{} or {}".format(
", ".join(type_names[:-1]), type_names[-1]
)
possible_types_str = f"{', '.join(type_names[:-1])} or {type_names[-1]}"
raise TypeError(f"{varname} must be of type {possible_types_str}")


Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/external/exporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,8 @@ def _write_color_tracks(ctracks, fname):


def _frac_to_hex(frac):
rgb = tuple(np.array(np.array(plt.cm.jet(frac)[:3]) * 255, dtype=int))
return "#{:02x}{:02x}{:02x}".format(*rgb)
r, g, b = tuple(np.array(np.array(plt.cm.jet(frac)[:3]) * 255, dtype=int))
return f"#{r:02x}{g:02x}{b:02x}"


def _get_color_stats_genes(color_stats, E, gene_list):
Expand Down
4 changes: 2 additions & 2 deletions src/scanpy/external/tl/_phenograph.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ def phenograph(
comm_key = (
f"pheno_{clustering_algo}" if clustering_algo in ["louvain", "leiden"] else ""
)
ig_key = "pheno_{}_ig".format("jaccard" if jaccard else "gaussian")
q_key = "pheno_{}_q".format("jaccard" if jaccard else "gaussian")
ig_key = f"pheno_{'jaccard' if jaccard else 'gaussian'}_ig"
q_key = f"pheno_{'jaccard' if jaccard else 'gaussian'}_q"

communities, graph, Q = phenograph.cluster(
data=data,
Expand Down
8 changes: 4 additions & 4 deletions src/scanpy/plotting/_tools/paga.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,11 +702,11 @@ def _paga_graph(
and isinstance(node_labels, str)
and node_labels != adata.uns["paga"]["groups"]
):
raise ValueError(
"Provide a list of group labels for the PAGA groups {}, not {}.".format(
adata.uns["paga"]["groups"], node_labels
)
msg = (
"Provide a list of group labels for the PAGA groups "
f"{adata.uns['paga']['groups']}, not {node_labels}."
)
raise ValueError(msg)
groups_key = adata.uns["paga"]["groups"]
if node_labels is None:
node_labels = adata.obs[groups_key].cat.categories
Expand Down
21 changes: 8 additions & 13 deletions src/scanpy/preprocessing/_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,26 +194,21 @@ def describe_var(
if issparse(X):
X.eliminate_zeros()
var_metrics = pd.DataFrame(index=adata.var_names)
var_metrics["n_cells_by_{expr_type}"], var_metrics["mean_{expr_type}"] = (
var_metrics[f"n_cells_by_{expr_type}"], var_metrics[f"mean_{expr_type}"] = (
materialize_as_ndarray((axis_nnz(X, axis=0), _get_mean_var(X, axis=0)[0]))
)
if log1p:
var_metrics["log1p_mean_{expr_type}"] = np.log1p(
var_metrics["mean_{expr_type}"]
var_metrics[f"log1p_mean_{expr_type}"] = np.log1p(
var_metrics[f"mean_{expr_type}"]
)
var_metrics["pct_dropout_by_{expr_type}"] = (
1 - var_metrics["n_cells_by_{expr_type}"] / X.shape[0]
var_metrics[f"pct_dropout_by_{expr_type}"] = (
1 - var_metrics[f"n_cells_by_{expr_type}"] / X.shape[0]
) * 100
var_metrics["total_{expr_type}"] = np.ravel(axis_sum(X, axis=0))
var_metrics[f"total_{expr_type}"] = np.ravel(axis_sum(X, axis=0))
if log1p:
var_metrics["log1p_total_{expr_type}"] = np.log1p(
var_metrics["total_{expr_type}"]
var_metrics[f"log1p_total_{expr_type}"] = np.log1p(
var_metrics[f"total_{expr_type}"]
)
# Relabel
new_colnames = []
for col in var_metrics.columns:
new_colnames.append(col.format(**locals()))
var_metrics.columns = new_colnames
if inplace:
adata.var[var_metrics.columns] = var_metrics
return None
Expand Down
7 changes: 4 additions & 3 deletions src/scanpy/tools/_rank_genes_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ def __init__(
)

if len(invalid_groups_selected) > 0:
raise ValueError(
"Could not calculate statistics for groups {} since they only "
"contain one sample.".format(", ".join(invalid_groups_selected))
msg = (
f"Could not calculate statistics for groups {', '.join(invalid_groups_selected)} "
"since they only contain one sample."
)
raise ValueError(msg)

adata_comp = adata
if layer is not None:
Expand Down
2 changes: 1 addition & 1 deletion tests/notebooks/test_paga_paul15_subsampled.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,6 @@ def test_paga_paul15_subsampled(image_comparer, plt):
show=False,
)
# add a test for this at some point
# data.to_csv('./write/paga_path_{}.csv'.format(descr))
# data.to_csv(f"./write/paga_path_{descr}.csv")

save_and_compare_images("paga_path")

0 comments on commit 4bd4a63

Please sign in to comment.