Skip to content

Commit

Permalink
Merge branch 'main' into no-format
Browse files Browse the repository at this point in the history
  • Loading branch information
flying-sheep authored Dec 10, 2024
2 parents d5e994e + ef92866 commit ec19b29
Show file tree
Hide file tree
Showing 80 changed files with 891 additions and 405 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
# Python build files
__pycache__/
/src/scanpy/_version.py
/ci/scanpy-min-deps.txt
/dist/
/*-env/
/env-*/
Expand Down
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.0
rev: v0.8.2
hooks:
- id: ruff
types_or: [python, pyi, jupyter]
Expand Down
7 changes: 4 additions & 3 deletions benchmarks/benchmarks/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
import scanpy as sc

if TYPE_CHECKING:
from collections.abc import Callable, Sequence, Set
from collections.abc import Callable, Sequence
from collections.abc import Set as AbstractSet
from typing import Literal, Protocol, TypeVar

from anndata import AnnData

C = TypeVar("C", bound=Callable)

class ParamSkipper(Protocol):
def __call__(self, **skipped: Set) -> Callable[[C], C]: ...
def __call__(self, **skipped: AbstractSet) -> Callable[[C], C]: ...

Dataset = Literal["pbmc68k_reduced", "pbmc3k", "bmmc", "lung93k"]
KeyX = Literal[None, "off-axis"]
Expand Down Expand Up @@ -195,7 +196,7 @@ def param_skipper(
b 5
"""

def skip(**skipped: Set) -> Callable[[C], C]:
def skip(**skipped: AbstractSet) -> Callable[[C], C]:
skipped_combs = [
tuple(record.values())
for record in (
Expand Down
53 changes: 42 additions & 11 deletions ci/scripts/min-deps.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#!/usr/bin/env python3
# /// script
# dependencies = [
# "tomli; python_version < '3.11'",
# "packaging",
# ]
# ///

from __future__ import annotations

import argparse
import sys
from collections import deque
from contextlib import ExitStack
from pathlib import Path
from typing import TYPE_CHECKING

Expand All @@ -16,7 +24,7 @@
from packaging.version import Version

if TYPE_CHECKING:
from collections.abc import Generator, Iterable
from collections.abc import Generator, Iterable, Sequence


def min_dep(req: Requirement) -> Requirement:
Expand All @@ -27,18 +35,21 @@ def min_dep(req: Requirement) -> Requirement:
-------
>>> min_dep(Requirement("numpy>=1.0"))
"numpy==1.0"
<Requirement('numpy==1.0.*')>
"""
req_name = req.name
if req.extras:
req_name = f"{req_name}[{','.join(req.extras)}]"

if not req.specifier:
filter_specs = [
spec for spec in req.specifier if spec.operator in {"==", "~=", ">=", ">"}
]
if not filter_specs:
return Requirement(req_name)

min_version = Version("0.0.0.a1")
for spec in req.specifier:
if spec.operator in [">", ">=", "~="]:
for spec in filter_specs:
if spec.operator in {">", ">=", "~="}:
min_version = max(min_version, Version(spec.version))
elif spec.operator == "==":
min_version = Version(spec.version)
Expand All @@ -65,12 +76,19 @@ def extract_min_deps(
yield min_dep(req)


def main():
class Args(argparse.Namespace):
path: Path
output: Path | None
extras: list[str]


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 directly passable to `pip install`.""",
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(
Expand All @@ -79,8 +97,18 @@ def main():
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()
args = parser.parse_args(argv, Args())

pyproject = tomllib.loads(args.path.read_text())

Expand All @@ -92,7 +120,10 @@ def main():

min_deps = extract_min_deps(deps, pyproject=pyproject)

print(" ".join(map(str, min_deps)))
sep = "\n" if args.output else " "
with ExitStack() as stack:
f = stack.enter_context(args.output.open("w")) if args.output else sys.stdout
print(sep.join(map(str, min_deps)), file=f)


if __name__ == "__main__":
Expand Down
8 changes: 5 additions & 3 deletions ci/scripts/towncrier_automation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/usr/bin/env python3
# /// script
# dependencies = [ "towncrier", "packaging" ]
# ///

from __future__ import annotations

import argparse
Expand Down Expand Up @@ -62,9 +66,7 @@ def main(argv: Sequence[str] | None = None) -> None:
text=True,
check=True,
).stdout.strip()
pr_description = (
"" if base_branch == "main" else "@meeseeksmachine backport to main"
)
pr_description = "" if base_branch == "main" else "@meeseeksdev backport to main"
branch_name = f"release_notes_{args.version}"

# Create a new branch + commit
Expand Down
17 changes: 17 additions & 0 deletions docs/release-notes/1.10.4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(v1.10.4)=
### 1.10.4 {small}`2024-11-12`

### Breaking changes

- Remove Python 3.9 support {smaller}`P Angerer` ({pr}`3283`)

### Bug fixes

- Fix {meth}`scanpy.pl.DotPlot.style`, {meth}`scanpy.pl.MatrixPlot.style`, and {meth}`scanpy.pl.StackedViolin.style` resetting all non-specified parameters {smaller}`P Angerer` ({pr}`3206`)
- Accept `'group'` instead of `'obs'` for `standard_scale` parameter in {func}`~scanpy.pl.stacked_violin` {smaller}`P Angerer` ({pr}`3243`)
- Use `density_norm` instead of of `scale` (cont. from {pr}`2844`) in {func}`~scanpy.pl.violin` and {func}`~scanpy.pl.stacked_violin` {smaller}`P Angerer` ({pr}`3244`)
- Switched all compatibility adapters for positional parameters to {exc}`FutureWarning` {smaller}`P Angerer` ({pr}`3264`)
- Catch `PerfectSeparationWarning` during {func}`~scanpy.pp.regress_out` {smaller}`J Wagner` ({pr}`3275`)
- Fix {func}`scanpy.pp.highly_variable_genes` for batches of size 1 {smaller}`P Angerer` ({pr}`3286`)
- Fix {func}`scanpy.pl.scatter`’s `color` parameter to take collections as advertised {smaller}`P Angerer` ({pr}`3299`)
- Fix {func}`scanpy.pl.highest_expr_genes` when used with a categorical gene symbol column {smaller}`P Angerer` ({pr}`3302`)
1 change: 0 additions & 1 deletion docs/release-notes/3206.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3243.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3244.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3264.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3275.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3283.breaking.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/release-notes/3284.performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Speed up {func}`~scanpy.pp.regress_out` {smaller}`P Ashish, P Angerer & S Dicks`
1 change: 0 additions & 1 deletion docs/release-notes/3286.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3299.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/release-notes/3302.bugfix.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/release-notes/3307.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support {class}`dask.array.Array` to {func}`scanpy.pp.calculate_qc_metrics` {smaller}`I Gold`
1 change: 1 addition & 0 deletions docs/release-notes/3324.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support `layer` parameter in {func}`scanpy.pl.highest_expr_genes` {smaller}`P Angerer`
1 change: 1 addition & 0 deletions docs/release-notes/3335.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Run numba functions single-threaded when called from inside of a ThreadPool {smaller}`P Angerer`
1 change: 1 addition & 0 deletions docs/release-notes/3362.doc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve {func}`~scanpy.external.pp.harmony_integrate` docs {smaller}`D Kühl`
1 change: 1 addition & 0 deletions docs/release-notes/3380.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Raise {exc}`FutureWarning` when calling deprecated {mod}`scanpy.pp` functions {smaller}`P Angerer`
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`
9 changes: 6 additions & 3 deletions hatch.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ features = ["test", "dask-ml"]
extra-dependencies = ["ipykernel"]
overrides.matrix.deps.env-vars = [
{ if = ["pre"], key = "UV_PRERELEASE", value = "allow" },
{ if = ["min"], key = "UV_RESOLUTION", value = "lowest-direct" },
{ 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" },
]
overrides.matrix.deps.python = [
{ if = ["min"] , value = "3.10" },
{ if = ["min"], value = "3.10" },
{ if = ["stable", "full", "pre"], value = "3.12" },
]
overrides.matrix.deps.features = [
{ if = ["full"] , value = "test-full" },
{ if = ["full"], value = "test-full" },
]

[[envs.hatch-test.matrix]]
Expand Down
2 changes: 1 addition & 1 deletion notebooks
19 changes: 12 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ dependencies = [
"pandas >=1.5",
"scipy>=1.8",
"seaborn>=0.13",
"h5py>=3.6",
"h5py>=3.7",
"tqdm",
"scikit-learn>=1.1",
"scikit-learn>=1.1,<1.6.0",
"statsmodels>=0.13",
"patsy",
"patsy!=1.0.0", # https://github.com/pydata/patsy/issues/215
"networkx>=2.7",
"natsort",
"joblib",
Expand All @@ -66,7 +66,7 @@ dependencies = [
"packaging>=21.3",
"session-info",
"legacy-api-wrap>=1.4", # for positional API deprecations
"get-annotations; python_version < '3.10'",
"typing-extensions; python_version < '3.13'",
]
dynamic = ["version"]

Expand Down Expand Up @@ -124,7 +124,7 @@ doc = [
"ipython>=7.20", # for nbsphinx code highlighting
"matplotlib!=3.6.1",
"sphinxcontrib-bibtex",
"setuptools",
"setuptools", # undeclared dependency of sphinxcontrib-bibtex→pybtex
# TODO: remove necessity for being able to import doc-linked classes
"scanpy[paga,dask-ml]",
"sam-algorithm",
Expand Down Expand Up @@ -167,7 +167,7 @@ addopts = [
"-ptesting.scanpy._pytest",
"--pyargs",
]
testpaths = ["./tests", "scanpy"]
testpaths = ["./tests", "./ci", "scanpy"]
norecursedirs = ["tests/_images"]
xfail_strict = true
nunit_attach_on = "fail"
Expand Down Expand Up @@ -212,7 +212,7 @@ exclude_also = [
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
# https://github.com/numba/numba/issues/4268
"@numba.njit.*",
'@(numba\.|nb\.)njit.*',
]

[tool.ruff]
Expand All @@ -232,6 +232,7 @@ select = [
"TID251", # Banned imports
"ICN", # Follow import conventions
"PTH", # Pathlib instead of os.path
"PYI", # Typing
"PLR0917", # Ban APIs with too many positional parameters
"FBT", # No positional boolean parameters
"PT", # Pytest style
Expand All @@ -246,6 +247,8 @@ ignore = [
"E262",
# 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",
]
[tool.ruff.lint.per-file-ignores]
# Do not assign a lambda expression, use a def
Expand All @@ -259,6 +262,8 @@ required-imports = ["from __future__ import annotations"]
"pandas.value_counts".msg = "Use pd.Series(a).value_counts() instead"
"legacy_api_wrap.legacy_api".msg = "Use scanpy._compat.old_positionals instead"
"numpy.bool".msg = "Use `np.bool_` instead for numpy>=1.24<2 compatibility"
"numba.jit".msg = "Use `scanpy._compat.njit` instead"
"numba.njit".msg = "Use `scanpy._compat.njit` instead"
[tool.ruff.lint.flake8-type-checking]
exempt-modules = []
strict = true
Expand Down
Loading

0 comments on commit ec19b29

Please sign in to comment.