From 46d77ade20c68afb5213490de85f33b81b00dbf9 Mon Sep 17 00:00:00 2001 From: "Philipp A." Date: Thu, 6 Aug 2026 14:29:29 +0200 Subject: [PATCH 1/3] Backport PR #4276 on branch 1.12.x (ci: run prek in GH actions) --- .github/dependabot.yml | 24 +++++++- .github/workflows/benchmark.yml | 10 ++-- .github/workflows/check-pr.yml | 18 +++--- .github/workflows/ci.yml | 64 ++++++++++++++-------- .github/workflows/publish.yml | 12 ++-- .pre-commit-config.yaml | 97 ++++++++++++++++++--------------- .vscode/settings.json | 5 +- hatch.toml | 10 ++++ 8 files changed, 151 insertions(+), 89 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index abd2e5876f..18fa22a4ca 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,10 +1,30 @@ version: 2 updates: - - package-ecosystem: github-actions + - package-ecosystem: pre-commit directory: / schedule: interval: weekly - - package-ecosystem: pip + labels: + - no milestone + commit-message: + prefix: test + cooldown: + default-days: 7 + groups: + pre-commit: + patterns: + - "*" + - package-ecosystem: github-actions directory: / schedule: interval: weekly + labels: + - no milestone + commit-message: + prefix: ci + cooldown: + default-days: 7 + groups: + actions-deps: + patterns: + - "*" diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 51a2ff5d30..ef28f89140 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -9,6 +9,8 @@ on: env: FORCE_COLOR: "1" +permissions: {} + jobs: benchmark: runs-on: ${{ matrix.os }} @@ -25,21 +27,21 @@ jobs: ASV_DIR: "./benchmarks" steps: - - uses: actions/checkout@v6 - with: { fetch-depth: 0 } # no blob:none so ASV can compare commits + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: { fetch-depth: 0, persist-credentials: false } # no blob:none so ASV can compare commits - name: Fetch main branch for `asv run`’s hash run: git fetch origin main:main if: ${{ github.ref_name != 'main' }} - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v6 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python }} cache: 'pip' - name: Cache datasets - uses: actions/cache@v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cache diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml index 4643cd3678..8498f8f7d5 100644 --- a/.github/workflows/check-pr.yml +++ b/.github/workflows/check-pr.yml @@ -20,19 +20,23 @@ on: # code change (e.g. this workflow) - synchronize +permissions: {} + jobs: # This job verifies that the milestone is present or not necessary # and determines if “check-relnotes” needs to be run. check-milestone: name: Check title, milestone, and labels runs-on: ubuntu-latest + permissions: + pull-requests: read # for amannn/action-semantic-pull-request steps: - name: Check if milestone or “no milestone” label is present - uses: flying-sheep/check@v1 + uses: flying-sheep/check@e10bb11109d1434ab16729bd988d78d65d47e163 # v1.0.5 with: success: ${{ github.event.pull_request.user.login == 'pre-commit-ci[bot]' || github.event.pull_request.milestone != null || contains(github.event.pull_request.labels.*.name, 'no milestone') }} - name: Check if the “Release notes” checkbox is checked and filled - uses: kaisugi/action-regex-match@v1.0.2 + uses: kaisugi/action-regex-match@d67cd689755dc47c5362609e0a6e2e1c93fa721b # v1.0.2 id: checked-relnotes with: text: ${{ github.event.pull_request.body }} @@ -40,7 +44,7 @@ jobs: flags: m - name: Check PR title id: check-title - uses: amannn/action-semantic-pull-request@v6 + uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 env: # Needs repo options: “Squash and merge” with commit message set to “PR title” GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} outputs: @@ -53,15 +57,15 @@ jobs: needs: check-milestone if: github.event.pull_request.user.login != 'pre-commit-ci[bot]' && needs.check-milestone.outputs.no-relnotes-reason == '' && !contains(fromJSON('["style","refactor","test","build","docs","ci"]'), needs.check-milestone.outputs.type) steps: - - uses: actions/checkout@v6 - with: { filter: 'blob:none', fetch-depth: 0 } + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: { filter: 'blob:none', fetch-depth: 0, persist-credentials: false } - name: Find out if a relevant release fragment is added - uses: dorny/paths-filter@v3 + uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2 id: changes with: filters: | # this is intentionally a string relnotes: 'docs/release-notes/${{ github.event.pull_request.number }}.${{ (contains(github.event.pull_request.title, '!') && 'breaking') || needs.check-milestone.outputs.type }}.md' - name: Check if a relevant release fragment is added - uses: flying-sheep/check@v1 + uses: flying-sheep/check@e10bb11109d1434ab16729bd988d78d65d47e163 # v1.0.5 with: success: ${{ steps.changes.outputs.relnotes }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2524cca620..3c3c249a88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,16 +15,25 @@ env: # so because leidenalg 0.10.0 has them, we pre-compile things: https://github.com/vtraag/leidenalg/issues/173 UV_COMPILE_BYTECODE: "1" +permissions: + contents: read + jobs: get-environments: runs-on: ubuntu-latest outputs: envs: ${{ steps.get-envs.outputs.envs }} steps: - - uses: actions/checkout@v6 - with: { filter: 'blob:none', fetch-depth: 0 } - - uses: astral-sh/setup-uv@v7 - with: { enable-cache: false } + - &clone + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + filter: blob:none + persist-credentials: false + - &setup-uv + uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + with: + enable-cache: true - id: get-envs run: | ENVS_JSON=$(NO_COLOR=1 uvx hatch env show --json | jq -c 'to_entries @@ -46,16 +55,13 @@ jobs: env: ${{ fromJSON(needs.get-environments.outputs.envs) }} permissions: id-token: write # for codecov OIDC + env: + UV_PYTHON: ${{ matrix.env.python }} steps: - - uses: actions/checkout@v6 - with: { filter: 'blob:none', fetch-depth: 0 } - - - uses: astral-sh/setup-uv@v7 - with: - python-version: ${{ matrix.env.python }} - + - *clone + - *setup-uv - name: Cache downloaded data - uses: actions/cache@v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: .pytest_cache/d/scanpy-data key: pytest @@ -83,7 +89,7 @@ jobs: - name: Upload coverage data if: ${{ !cancelled() && matrix.env.test-type == 'coverage' }} - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: flags: ${{ matrix.env.name }} files: test-data/coverage.xml @@ -92,7 +98,7 @@ jobs: - name: Upload test results if: ${{ !cancelled() }} - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: report_type: test_results flags: ${{ matrix.env.name }} @@ -102,7 +108,7 @@ jobs: - name: Publish debug artifacts if: ${{ !cancelled() }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: debug-data-${{ matrix.env.name }} path: .pytest_cache/d/debug @@ -110,25 +116,35 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - with: { filter: 'blob:none', fetch-depth: 0 } - - uses: actions/setup-python@v6 - with: - python-version: "3.x" - - uses: astral-sh/setup-uv@v7 - with: - enable-cache: true + - *clone + - *setup-uv - run: uvx --from build pyproject-build --sdist --wheel . - run: uvx twine check dist/* + lint: + name: Pre-commit checks + runs-on: ubuntu-latest + permissions: {} + steps: + - *clone + - *setup-uv + - run: uv tool install hatch + - name: Run pre-commit hooks + run: uvx prek run --all-files --show-diff-on-failure --color=always + env: + SKIP: no-commit-to-branch + - uses: autofix-ci/action@c5b2d67aa2274e7b5a18224e8171550871fc7e4a # v1.3.4 + if: ${{ !cancelled() }} + check: if: always() needs: - get-environments - test - build + - lint runs-on: ubuntu-latest steps: - - uses: re-actors/alls-green@release/v1 + - uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 54d9359219..2b6a46b4a6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,12 +14,14 @@ jobs: permissions: id-token: write # to authenticate as Trusted Publisher to pypi.org steps: - - uses: actions/checkout@v6 - with: { filter: 'blob:none', fetch-depth: 0 } - - uses: actions/setup-python@v6 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: { filter: 'blob:none', fetch-depth: 0, persist-credentials: false } + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.x" - - uses: astral-sh/setup-uv@v7 + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + with: + enable-cache: false - run: uvx --from build pyproject-build --sdist --wheel . - run: uvx twine check dist/* - - uses: pypa/gh-action-pypi-publish@release/v1 + - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bd3b7f026e..8ffe492d9d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,44 +1,55 @@ -ci: - autoupdate_commit_msg: "ci: pre-commit autoupdate" - repos: -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.0 - hooks: - - id: ruff-check - args: ["--fix"] - - id: ruff-format - # The following can be removed once PLR0917 is out of preview - - name: ruff preview rules - id: ruff-check - args: ["--preview", "--select=PLR0917"] -- repo: https://github.com/flying-sheep/bibfmt - rev: v4.3.0 - hooks: - - id: bibfmt - args: - - --sort-by-bibkey - - --drop=abstract -- repo: https://github.com/biomejs/pre-commit - rev: v2.3.14 - hooks: - - id: biome-format -- repo: https://github.com/tox-dev/pyproject-fmt - rev: v2.15.1 - hooks: - - id: pyproject-fmt -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 - hooks: - - id: trailing-whitespace - exclude: tests/_data - - id: end-of-file-fixer - exclude: tests/_data - - id: check-added-large-files - - id: check-case-conflict - - id: check-toml - - id: check-yaml - - id: check-merge-conflict - - id: detect-private-key - - id: no-commit-to-branch - args: ["--branch=main"] +- repo: https://github.com/flying-sheep/bibfmt + rev: v4.3.0 + hooks: + - id: bibfmt + args: + - --sort-by-bibkey + - --drop=abstract + groups: [format] +- repo: https://github.com/biomejs/pre-commit + rev: v2.5.6 + hooks: + - id: biome-format + groups: [format] + exclude: ^\.cruft\.json$ # inconsistent indentation with cruft - file never to be modified manually. +- repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.27.0 + hooks: + - id: pyproject-fmt + groups: [format] +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.16.1 + hooks: + - id: ruff-check + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + groups: [format] +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: detect-private-key + - id: check-ast + - id: check-added-large-files + - id: check-toml + - id: check-yaml + - id: end-of-file-fixer + groups: [format] + exclude: tests/_data + - id: mixed-line-ending + groups: [format] + args: [--fix=lf] + - id: trailing-whitespace + groups: [format] + exclude: tests/_data + - id: check-case-conflict + # Check that there are no merge conflicts (could be generated by template sync) + - id: check-merge-conflict + args: [--assume-in-merge] + - id: no-commit-to-branch + args: [--branch=main] +- repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.29.0 + hooks: + - id: zizmor + args: [--no-progress, --fix] diff --git a/.vscode/settings.json b/.vscode/settings.json index fc4da964e2..b0648f1990 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "[python][toml][json][jsonc]": { + "[python][json][jsonc]": { "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.organizeImports": "explicit", @@ -9,9 +9,6 @@ "[python]": { "editor.defaultFormatter": "charliermarsh.ruff", }, - "[toml]": { - "editor.defaultFormatter": "tamasfe.even-better-toml", - }, "[json][jsonc]": { "editor.defaultFormatter": "biomejs.biome", }, diff --git a/hatch.toml b/hatch.toml index 27a00a1677..30abcd0eed 100644 --- a/hatch.toml +++ b/hatch.toml @@ -14,6 +14,16 @@ scripts.create = "towncrier create {args}" scripts.build = "python3 ci/scripts/towncrier_automation.py {args}" scripts.clean = "git restore --source=HEAD --staged --worktree -- docs/release-notes" +[envs.hatch-check-fmt] +dependencies = [ "prek" ] +scripts.format-check = "echo 'try `hatch check fmt --fix`'; false" +scripts.format-fix = "prek run -a --group=format" + +[envs.hatch-check-code] +dependencies = [ "prek" ] +lint-check = "echo 'try `hatch check code --fix`'; false" +scripts.lint-fix = "prek run -a --no-group=format" + [envs.hatch-test] python = "3.14" default-args = [ ] From 797fe9a0036fac9bd36d0ef3dc32da3ae84a6fab Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 13:00:05 +0000 Subject: [PATCH 2/3] [autofix.ci] apply automated fixes --- docs/extensions/myst_ignore_mime_types.py | 2 +- pyproject.toml | 32 ++++++++++---------- src/scanpy/_utils/__init__.py | 3 +- src/scanpy/experimental/pp/_normalization.py | 2 +- src/scanpy/plotting/_baseplot_class.py | 2 +- src/scanpy/plotting/_dotplot.py | 10 +++--- src/scanpy/plotting/_matrixplot.py | 6 ++-- src/scanpy/plotting/_stacked_violin.py | 10 +++--- src/scanpy/plotting/_tools/scatterplots.py | 8 ++--- src/scanpy/preprocessing/_pca/__init__.py | 2 +- src/scanpy/preprocessing/_simple.py | 2 +- src/scanpy/readwrite.py | 6 ++-- 12 files changed, 42 insertions(+), 43 deletions(-) diff --git a/docs/extensions/myst_ignore_mime_types.py b/docs/extensions/myst_ignore_mime_types.py index 762b9e31c4..d90c47db07 100644 --- a/docs/extensions/myst_ignore_mime_types.py +++ b/docs/extensions/myst_ignore_mime_types.py @@ -31,7 +31,7 @@ class _Ignore(MimeRenderPlugin): @staticmethod def handle_mime( renderer: NbElementRenderer, data: MimeData, inline: bool - ) -> None | list[nodes.Element]: + ) -> list[nodes.Element] | None: if data.mime_type in ignore: return [] # returning a list instead of `None` means “we handled it” return None diff --git a/pyproject.toml b/pyproject.toml index cfd52e1908..5201c2f766 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -148,9 +148,9 @@ test-min = [ ] [tool.hatch] -build.targets.wheel.packages = [ "src/testing", "src/scanpy" ] version.source = "vcs" version.raw-options.version_scheme = "release-branch-semver" +build.targets.wheel.packages = [ "src/scanpy", "src/testing" ] [tool.ruff] src = [ "src" ] @@ -241,7 +241,6 @@ expand_tables = [ ] [tool.pytest] -strict = true addopts = [ "--import-mode=importlib", "--strict-markers", @@ -249,14 +248,6 @@ addopts = [ "-ptesting.scanpy._pytest", "--pyargs", ] -testpaths = [ "./tests", "./ci", "scanpy" ] -norecursedirs = [ "tests/_images" ] -junit_family = "xunit1" -markers = [ - "internet: tests which rely on internet resources (enable with `--internet-tests`)", - "gpu: tests that use a GPU (unused, required by anndata.tests.helpers)", - "array_api: tests that use array_api (unused, required by anndata.tests.helpers)", -] filterwarnings = [ "error", # Umap warns when tensorflow isn’t installed. @@ -284,6 +275,15 @@ filterwarnings = [ # everybody uses this zarr 3 feature, including us, XArray, lots of data out there … "ignore:Consolidated metadata is currently not part:UserWarning", ] +junit_family = "xunit1" +markers = [ + "internet: tests which rely on internet resources (enable with `--internet-tests`)", + "gpu: tests that use a GPU (unused, required by anndata.tests.helpers)", + "array_api: tests that use array_api (unused, required by anndata.tests.helpers)", +] +norecursedirs = [ "tests/_images" ] +strict = true +testpaths = [ "./tests", "./ci", "scanpy" ] [tool.coverage] run.concurrency = [ "multiprocessing" ] @@ -304,19 +304,19 @@ xml.output = "test-data/coverage.xml" [tool.towncrier] name = "scanpy" package = "scanpy" +package_dir = "src" directory = "docs/release-notes" filename = "docs/release-notes/{version}.md" -single_file = false -package_dir = "src" -issue_format = "{{pr}}`{issue}`" title_format = "(v{version})=\n### {version} {{small}}`{project_date}`" +issue_format = "{{pr}}`{issue}`" +single_file = false +fragment.breaking.name = "Breaking changes" # add `!` to commit type (e.g. “feature!:”) +fragment.chore.name = "Miscellaneous changes" +fragment.docs.name = "Documentation" # Valid fragments should be a subset of conventional commit types (except for `breaking`): # https://github.com/commitizen/conventional-commit-types/blob/master/index.json # style, refactor, test, build, ci: should not go into changelog fragment.feat.name = "Features" fragment.fix.name = "Bug fixes" -fragment.docs.name = "Documentation" fragment.perf.name = "Performance" -fragment.chore.name = "Miscellaneous changes" fragment.revert.name = "Revert" -fragment.breaking.name = "Breaking changes" # add `!` to commit type (e.g. “feature!:”) diff --git a/src/scanpy/_utils/__init__.py b/src/scanpy/_utils/__init__.py index 9a0380b1f3..ab0398c9ac 100644 --- a/src/scanpy/_utils/__init__.py +++ b/src/scanpy/_utils/__init__.py @@ -78,7 +78,6 @@ "get_literal_vals", "indent", "is_backed_type", - "is_backed_type", "raise_not_implemented_error_if_backed_type", "renamed_arg", "sanitize_anndata", @@ -268,7 +267,7 @@ def check_array_function_arguments(**kwargs): def check_use_raw( adata: AnnData, - use_raw: None | bool, # noqa: FBT001 + use_raw: bool | None, # noqa: FBT001 *, layer: str | None = None, ) -> bool: diff --git a/src/scanpy/experimental/pp/_normalization.py b/src/scanpy/experimental/pp/_normalization.py index cb34b9902b..eac0f28d7b 100644 --- a/src/scanpy/experimental/pp/_normalization.py +++ b/src/scanpy/experimental/pp/_normalization.py @@ -168,7 +168,7 @@ def normalize_pearson_residuals_pca( n_comps: int | None = 50, random_state: float = 0, kwargs_pca: Mapping[str, Any] = MappingProxyType({}), - mask_var: np.ndarray | str | None | Empty = _empty, + mask_var: np.ndarray | str | Empty | None = _empty, use_highly_variable: bool | None = None, check_values: bool = True, inplace: bool = True, diff --git a/src/scanpy/plotting/_baseplot_class.py b/src/scanpy/plotting/_baseplot_class.py index 20ecb30809..f8236d8a04 100644 --- a/src/scanpy/plotting/_baseplot_class.py +++ b/src/scanpy/plotting/_baseplot_class.py @@ -410,7 +410,7 @@ def add_totals( return self @old_positionals("cmap") - def style(self, *, cmap: Colormap | str | None | Empty = _empty) -> Self: + def style(self, *, cmap: Colormap | str | Empty | None = _empty) -> Self: r"""Set visual style parameters. Parameters diff --git a/src/scanpy/plotting/_dotplot.py b/src/scanpy/plotting/_dotplot.py index b903e781f3..6ea356f4ae 100644 --- a/src/scanpy/plotting/_dotplot.py +++ b/src/scanpy/plotting/_dotplot.py @@ -350,14 +350,14 @@ def _prepare_dot_data( def style( # noqa: PLR0913 self, *, - cmap: Colormap | str | None | Empty = _empty, + cmap: Colormap | str | Empty | None = _empty, color_on: Literal["dot", "square"] | Empty = _empty, - dot_max: float | None | Empty = _empty, - dot_min: float | None | Empty = _empty, + dot_max: float | Empty | None = _empty, + dot_min: float | Empty | None = _empty, smallest_dot: float | Empty = _empty, largest_dot: float | Empty = _empty, - dot_edge_color: ColorLike | None | Empty = _empty, - dot_edge_lw: float | None | Empty = _empty, + dot_edge_color: ColorLike | Empty | None = _empty, + dot_edge_lw: float | Empty | None = _empty, size_exponent: float | Empty = _empty, grid: bool | Empty = _empty, x_padding: float | Empty = _empty, diff --git a/src/scanpy/plotting/_matrixplot.py b/src/scanpy/plotting/_matrixplot.py index e803bdc1eb..9146124787 100644 --- a/src/scanpy/plotting/_matrixplot.py +++ b/src/scanpy/plotting/_matrixplot.py @@ -198,9 +198,9 @@ def __init__( # noqa: PLR0913 def style( self, - cmap: Colormap | str | None | Empty = _empty, - edge_color: ColorLike | None | Empty = _empty, - edge_lw: float | None | Empty = _empty, + cmap: Colormap | str | Empty | None = _empty, + edge_color: ColorLike | Empty | None = _empty, + edge_lw: float | Empty | None = _empty, ) -> Self: r"""Modify plot visual parameters. diff --git a/src/scanpy/plotting/_stacked_violin.py b/src/scanpy/plotting/_stacked_violin.py index 19d6aa7a97..9899afa0d9 100644 --- a/src/scanpy/plotting/_stacked_violin.py +++ b/src/scanpy/plotting/_stacked_violin.py @@ -273,15 +273,15 @@ def __init__( # noqa: PLR0913 def style( # noqa: PLR0913 self, *, - cmap: Colormap | str | None | Empty = _empty, + cmap: Colormap | str | Empty | None = _empty, stripplot: bool | Empty = _empty, jitter: float | bool | Empty = _empty, jitter_size: float | Empty = _empty, - linewidth: float | None | Empty = _empty, - row_palette: str | None | Empty = _empty, + linewidth: float | Empty | None = _empty, + row_palette: str | Empty | None = _empty, density_norm: DensityNorm | Empty = _empty, yticklabels: bool | Empty = _empty, - ylim: tuple[float, float] | None | Empty = _empty, + ylim: tuple[float, float] | Empty | None = _empty, x_padding: float | Empty = _empty, y_padding: float | Empty = _empty, # deprecated @@ -700,7 +700,7 @@ def stacked_violin( # noqa: PLR0913 density_norm: DensityNorm | Empty = _empty, yticklabels: bool = StackedViolin.DEFAULT_PLOT_YTICKLABELS, # deprecated - order: Sequence[str] | None | Empty = _empty, + order: Sequence[str] | Empty | None = _empty, scale: DensityNorm | Empty = _empty, save: bool | str | None = None, **kwds, diff --git a/src/scanpy/plotting/_tools/scatterplots.py b/src/scanpy/plotting/_tools/scatterplots.py index 46cb969f5e..0679fd69c3 100644 --- a/src/scanpy/plotting/_tools/scatterplots.py +++ b/src/scanpy/plotting/_tools/scatterplots.py @@ -978,8 +978,8 @@ def spatial( # noqa: PLR0913 *, basis: str = "spatial", img: np.ndarray | None = None, - img_key: str | None | Empty = _empty, - library_id: str | None | Empty = _empty, + img_key: str | Empty | None = _empty, + library_id: str | Empty | None = _empty, crop_coord: tuple[int, int, int, int] | None = None, alpha_img: float = 1.0, bw: bool | None = False, @@ -1366,7 +1366,7 @@ def _check_scale_factor( def _check_spatial_data( - uns: Mapping, library_id: str | None | Empty + uns: Mapping, library_id: str | Empty | None ) -> tuple[str | None, Mapping | None]: """Given a mapping, try and extract a library id/ mapping with spatial data. @@ -1391,7 +1391,7 @@ def _check_spatial_data( def _check_img( spatial_data: Mapping | None, img: np.ndarray | None, - img_key: None | str | Empty, + img_key: str | Empty | None, *, bw: bool = False, ) -> tuple[np.ndarray | None, str | None]: diff --git a/src/scanpy/preprocessing/_pca/__init__.py b/src/scanpy/preprocessing/_pca/__init__.py index f12229d842..67e2f448e2 100644 --- a/src/scanpy/preprocessing/_pca/__init__.py +++ b/src/scanpy/preprocessing/_pca/__init__.py @@ -66,7 +66,7 @@ def pca( # noqa: PLR0912, PLR0913, PLR0915 chunk_size: int | None = None, random_state: _LegacyRandom = 0, return_info: bool = False, - mask_var: NDArray[np.bool] | str | None | Empty = _empty, + mask_var: NDArray[np.bool] | str | Empty | None = _empty, use_highly_variable: bool | None = None, dtype: DTypeLike = "float32", key_added: str | None = None, diff --git a/src/scanpy/preprocessing/_simple.py b/src/scanpy/preprocessing/_simple.py index 379562847e..30b5e69113 100644 --- a/src/scanpy/preprocessing/_simple.py +++ b/src/scanpy/preprocessing/_simple.py @@ -896,7 +896,7 @@ def sample( # noqa: PLR0912 replace: bool = False, axis: Literal["obs", 0, "var", 1] = "obs", p: str | NDArray[np.bool] | NDArray[np.floating] | None = None, -) -> AnnData | None | tuple[np.ndarray | CSBase | DaskArray, NDArray[np.int64]]: +) -> AnnData | tuple[np.ndarray | CSBase | DaskArray, NDArray[np.int64]] | None: r"""Sample observations or variables with or without replacement. .. array-support:: pp.sample diff --git a/src/scanpy/readwrite.py b/src/scanpy/readwrite.py index 4f1d6b2b0e..c935cc6e2f 100644 --- a/src/scanpy/readwrite.py +++ b/src/scanpy/readwrite.py @@ -99,7 +99,7 @@ def read( first_column_names: bool = False, backup_url: str | None = None, cache: bool = False, - cache_compression: Literal["gzip", "lzf"] | None | Empty = _empty, + cache_compression: Literal["gzip", "lzf"] | Empty | None = _empty, **kwargs, ) -> AnnData: """Read file and return :class:`~anndata.AnnData` object. @@ -538,7 +538,7 @@ def read_10x_mtx( var_names: Literal["gene_symbols", "gene_ids"] = "gene_symbols", make_unique: bool = True, cache: bool = False, - cache_compression: Literal["gzip", "lzf"] | None | Empty = _empty, + cache_compression: Literal["gzip", "lzf"] | Empty | None = _empty, gex_only: bool = True, prefix: str | None = None, compressed: bool = True, @@ -607,7 +607,7 @@ def _read_10x_mtx( var_names: Literal["gene_symbols", "gene_ids"] = "gene_symbols", make_unique: bool = True, cache: bool = False, - cache_compression: Literal["gzip", "lzf"] | None | Empty = _empty, + cache_compression: Literal["gzip", "lzf"] | Empty | None = _empty, prefix: str = "", is_legacy: bool, compressed: bool = True, From 2e3ffdc95db52775461a43bbb7293026dd072f23 Mon Sep 17 00:00:00 2001 From: Phil Schaf Date: Thu, 6 Aug 2026 15:33:38 +0200 Subject: [PATCH 3/3] fix broken ref --- tests/plotting/legacy/test_plotting_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plotting/legacy/test_plotting_utils.py b/tests/plotting/legacy/test_plotting_utils.py index 8ea20bbda2..5ac5a58d9d 100644 --- a/tests/plotting/legacy/test_plotting_utils.py +++ b/tests/plotting/legacy/test_plotting_utils.py @@ -9,8 +9,8 @@ from matplotlib import colormaps from scanpy.plotting._anndata import _check_if_annotations +from scanpy.plotting._tools.scatterplots import _get_palette from scanpy.plotting._utils import validate_palette -from scanpy.plotting.legacy._tools.scatterplots import _get_palette if TYPE_CHECKING: from typing import Any, Literal