diff --git a/.conda/meta.yaml b/.conda/meta.yaml index 2f433a28e..30fc67306 100644 --- a/.conda/meta.yaml +++ b/.conda/meta.yaml @@ -16,12 +16,12 @@ build: requirements: host: - - python >=3.10 + - python >=3.11 - hatchling - hatch-vcs run: - - python >=3.10 + - python >=3.11 - anndata >=0.9 - awkward >=2.1.0 - mudata >=0.2.3 diff --git a/.cruft.json b/.cruft.json index dfb7cf65f..d73a98cd2 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,43 +1,43 @@ { - "template": "https://github.com/scverse/cookiecutter-scverse", - "commit": "d383d94fadff9e4e6fdb59d77c68cb900d7cedec", - "checkout": "v0.6.0", - "context": { - "cookiecutter": { - "project_name": "scirpy", - "package_name": "scirpy", - "project_description": "A very interesting piece of code", - "author_full_name": "Gregor Sturm", - "author_email": "mail@gregor-sturm.de", - "github_user": "grst", - "github_repo": "scirpy", - "license": "BSD 3-Clause License", - "ide_integration": true, - "_copy_without_render": [ - ".github/workflows/build.yaml", - ".github/workflows/test.yaml", - "docs/_templates/autosummary/**.rst" - ], - "_exclude_on_template_update": [ - "CHANGELOG.md", - "LICENSE", - "README.md", - "docs/api.md", - "docs/index.md", - "docs/notebooks/example.ipynb", - "docs/references.bib", - "docs/references.md", - "src/**", - "tests/**" - ], - "_render_devdocs": false, - "_jinja2_env_vars": { - "lstrip_blocks": true, - "trim_blocks": true - }, - "_template": "https://github.com/scverse/cookiecutter-scverse", - "_commit": "d383d94fadff9e4e6fdb59d77c68cb900d7cedec" - } - }, - "directory": null + "template": "https://github.com/scverse/cookiecutter-scverse", + "commit": "6ff5b92b5d44ea6d8a88e47538475718d467db95", + "checkout": "v0.7.0", + "context": { + "cookiecutter": { + "project_name": "scirpy", + "package_name": "scirpy", + "project_description": "A very interesting piece of code", + "author_full_name": "Gregor Sturm", + "author_email": "mail@gregor-sturm.de", + "github_user": "grst", + "github_repo": "scirpy", + "license": "BSD 3-Clause License", + "ide_integration": true, + "_copy_without_render": [ + ".github/workflows/build.yaml", + ".github/workflows/test.yaml", + "docs/_templates/autosummary/**.rst" + ], + "_exclude_on_template_update": [ + "CHANGELOG.md", + "LICENSE", + "README.md", + "docs/api.md", + "docs/index.md", + "docs/notebooks/example.ipynb", + "docs/references.bib", + "docs/references.md", + "src/**", + "tests/**" + ], + "_render_devdocs": false, + "_jinja2_env_vars": { + "lstrip_blocks": true, + "trim_blocks": true + }, + "_template": "https://github.com/scverse/cookiecutter-scverse", + "_commit": "6ff5b92b5d44ea6d8a88e47538475718d467db95" + } + }, + "directory": null } diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3ca1ccbde..6104b9e6f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report description: Report something that is broken or incorrect -labels: bug +type: Bug body: - type: markdown attributes: @@ -9,8 +9,7 @@ body: detailing how to provide the necessary information for us to reproduce your bug. In brief: * Please provide exact steps how to reproduce the bug in a clean Python environment. * In case it's not clear what's causing this bug, please provide the data or the data generation procedure. - * Sometimes it is not possible to share the data, but usually it is possible to replicate problems on publicly - available datasets or to share a subset of your data. + * Replicate problems on public datasets or share data subsets when full sharing isn't possible. - type: textarea id: report diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 585af6936..a1f032979 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature request description: Propose a new feature for scirpy -labels: enhancement +type: Enhancement body: - type: textarea id: description diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 83e01a1ee..c6ecc2f25 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -10,23 +10,16 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - # to fail on error in multiline statements (-e), in pipes (-o pipefail), and on unset variables (-u). - shell: bash -euo pipefail {0} - jobs: package: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: filter: blob:none fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v5 - with: - cache-dependency-glob: pyproject.toml + uses: astral-sh/setup-uv@v7 - name: Build package run: uv build - name: Check package diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d4f2594aa..b23933593 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,11 +4,6 @@ on: release: types: [published] -defaults: - run: - # to fail on error in multiline statements (-e), in pipes (-o pipefail), and on unset variables (-u). - shell: bash -euo pipefail {0} - # Use "trusted publishing", see https://docs.pypi.org/trusted-publishers/ jobs: release: @@ -20,14 +15,12 @@ jobs: permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: filter: blob:none fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v5 - with: - cache-dependency-glob: pyproject.toml + uses: astral-sh/setup-uv@v7 - name: Build package run: uv build - name: Publish package distributions to PyPI diff --git a/.github/workflows/test-tutorials.yaml b/.github/workflows/test-tutorials.yaml index fa3848c3f..c2f9439bb 100644 --- a/.github/workflows/test-tutorials.yaml +++ b/.github/workflows/test-tutorials.yaml @@ -26,32 +26,23 @@ jobs: - tutorial_5k_bcr.ipynb os: - ubuntu-latest - python: - - "3.10" - - env: - OS: ${{ matrix.os }} - PYTHON: ${{ matrix.python }} steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 with: - python-version: ${{ matrix.python }} - cache: "pip" - cache-dependency-path: "**/pyproject.toml" - + filter: blob:none + fetch-depth: 0 - name: Install system dependencies run: | sudo apt-get update && sudo apt-get install -y libcairo2-dev pkg-config - - name: Install dependencies - run: | - pip install ".[doc]" + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + cache-dependency-glob: pyproject.toml - name: Test env: MPLBACKEND: agg PLATFORM: ${{ matrix.os }} DISPLAY: :42 run: | - jupytext -k python3 --execute docs/tutorials/${{ matrix.tutorial }} + uvx hatch run docs:run_tutorial docs/tutorials/${{ matrix.tutorial }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c4f9ad332..c0490c586 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -12,11 +12,6 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - # to fail on error in multiline statements (-e), in pipes (-o pipefail), and on unset variables (-u). - shell: bash -euo pipefail {0} - jobs: # Get the test environment from hatch as defined in pyproject.toml. # This ensures that the pyproject.toml is the single point of truth for test definitions and the same tests are @@ -28,12 +23,12 @@ jobs: outputs: envs: ${{ steps.get-envs.outputs.envs }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: filter: blob:none fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 - name: Get test environments id: get-envs run: | @@ -51,6 +46,8 @@ jobs: # Run tests through hatch. Spawns a separate runner for each environment defined in the hatch matrix obtained above. test: needs: get-environments + permissions: + id-token: write # for codecov OIDC strategy: fail-fast: false @@ -63,15 +60,14 @@ jobs: continue-on-error: ${{ contains(matrix.env.name, 'pre') }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: filter: blob:none fetch-depth: 0 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.env.python }} - cache-dependency-glob: pyproject.toml - name: create hatch environment run: uvx hatch env create ${{ matrix.env.name }} - name: run tests using hatch @@ -88,6 +84,9 @@ jobs: uvx hatch run ${{ matrix.env.name }}:coverage xml # create report for upload - name: Upload coverage uses: codecov/codecov-action@v5 + with: + fail_ci_if_error: true + use_oidc: true # Check that all tests defined above pass. This makes it easy to set a single "required" test in branch # protection instead of having to update it frequently. See https://github.com/re-actors/alls-green#why. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6b9fcd2a..27d8a954d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ default_stages: minimum_pre_commit_version: 2.16.0 repos: - repo: https://github.com/biomejs/pre-commit - rev: v2.3.8 + rev: v2.3.10 hooks: - id: biome-format exclude: ^\.cruft\.json$ # inconsistent indentation with cruft - file never to be modified manually. @@ -16,7 +16,7 @@ repos: hooks: - id: pyproject-fmt - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.9 + rev: v0.14.10 hooks: - id: ruff-check types_or: [python, pyi, jupyter] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c3f3f96fb..6c2847716 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,8 @@ version: 2 build: os: ubuntu-24.04 tools: - python: "3.12" + python: "3.13" + nodejs: latest jobs: create_environment: - asdf plugin add uv diff --git a/README.md b/README.md index a4d4c0704..a503c6901 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Please refer to the [documentation][link-docs]. In particular, the ## Installation -You need to have Python 3.10 or newer installed on your system. If you don't have +You need to have Python 3.11 or newer installed on your system. If you don't have Python installed, we recommend installing [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge). There are several alternative options to install scirpy: diff --git a/docs/conf.py b/docs/conf.py index fddf73a84..75efdb9cc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -5,11 +5,14 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- -import os +import shutil import sys from datetime import datetime from importlib.metadata import metadata from pathlib import Path +import os + +from sphinxcontrib import katex HERE = Path(__file__).parent sys.path.insert(0, str(HERE / "extensions")) @@ -19,7 +22,7 @@ # NOTE: If you installed your project in editable mode, this might be stale. # If this is the case, reinstall it to refresh the metadata info = metadata("scirpy") -project_name = info["Name"] +project = info["Name"] author = info["Author"] copyright = f"{datetime.now():%Y}, {author}." version = info["Version"] @@ -39,10 +42,10 @@ html_context = { "display_github": True, # Integrate GitHub - "github_user": "scverse", # Username - "github_repo": project_name, # Repo name - "github_version": "main", # Version - "conf_py_path": "/docs/", # Path in the checkout to the docs root + "github_user": "scverse", + "github_repo": project, + "github_version": "main", + "conf_py_path": "/docs/", } # Set canonical URL from the Read the Docs Domain @@ -63,9 +66,9 @@ "sphinx.ext.autosummary", "sphinx.ext.napoleon", "sphinxcontrib.bibtex", + "sphinxcontrib.katex", "sphinx_autodoc_typehints", "sphinx_tabs.tabs", - "sphinx.ext.mathjax", "IPython.sphinxext.ipython_console_highlighting", "sphinxext.opengraph", *[p.stem for p in (HERE / "extensions").glob("*.py")], @@ -139,9 +142,9 @@ # html_theme = "sphinx_book_theme" html_static_path = ["_static"] -html_title = project_name -html_logo = "img/scirpy_logo.png" html_css_files = ["css/custom.css"] +html_title = project +html_logo = "img/scirpy_logo.png" html_theme_options = { "repository_url": repository_url, @@ -151,6 +154,7 @@ } pygments_style = "default" +katex_prerender = shutil.which(katex.NODEJS_BINARY) is not None # -- nbsphinx Tutorials ---------------------------------------------------------------- diff --git a/docs/contributing.md b/docs/contributing.md index 699d94291..b172fd1d0 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -62,9 +62,9 @@ This will list “Standalone” environments and a table of “Matrix” environ +------------+---------+--------------------------+----------+---------------------------------+-------------+ | Name | Type | Envs | Features | Dependencies | Scripts | +------------+---------+--------------------------+----------+---------------------------------+-------------+ -| hatch-test | virtual | hatch-test.py3.10-stable | dev | coverage-enable-subprocess==1.0 | cov-combine | -| | | hatch-test.py3.13-stable | test | coverage[toml]~=7.4 | cov-report | -| | | hatch-test.py3.13-pre | | pytest-mock~=3.12 | run | +| hatch-test | virtual | hatch-test.py3.11-stable | dev | coverage-enable-subprocess==1.0 | cov-combine | +| | | hatch-test.py3.14-stable | test | coverage[toml]~=7.4 | cov-report | +| | | hatch-test.py3.14-pre | | pytest-mock~=3.12 | run | | | | | | pytest-randomly~=3.15 | run-cov | | | | | | pytest-rerunfailures~=14.0 | | | | | | | pytest-xdist[psutil]~=3.5 | | @@ -73,18 +73,18 @@ This will list “Standalone” environments and a table of “Matrix” environ ``` From the `Envs` column, select the environment name you want to use for development. -In this example, it would be `hatch-test.py3.13-stable`. +In this example, it would be `hatch-test.py3.14-stable`. Next, create the environment with ```bash -hatch env create hatch-test.py3.13-stable +hatch env create hatch-test.py3.14-stable ``` Then, obtain the path to the environment using ```bash -hatch env find hatch-test.py3.13-stable +hatch env find hatch-test.py3.14-stable ``` In case you are using VScode, now open the command palette (Ctrl+Shift+P) and search for `Python: Select Interpreter`. diff --git a/pyproject.toml b/pyproject.toml index f835f0c01..294e99773 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,10 +9,9 @@ readme = "README.md" license = { file = "LICENSE" } maintainers = [ { name = "Gregor Sturm", email = "mail@gregor-sturm.de" } ] authors = [ { name = "Gregor Sturm" }, { name = "Tamas Szabo" } ] -requires-python = ">=3.10" +requires-python = ">=3.11" classifiers = [ "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -30,7 +29,7 @@ dependencies = [ "logomaker!=0.8.5", "mudata>=0.2.3", "networkx>=2.5", - "numba>=0.57", + "numba>=0.60", "numpy>=1.17", "pandas>=1.5,!=2.1.2", "pooch>=1.7", @@ -42,12 +41,31 @@ dependencies = [ "squarify", "tqdm>=4.63", # https://github.com/tqdm/tqdm/issues/1082 ] - optional-dependencies.cupy = [ "cupy-cuda12x" ] optional-dependencies.dandelion = [ "sc-dandelion>=0.3.5" ] -optional-dependencies.dev = [ "pre-commit" ] optional-dependencies.diversity = [ "scikit-bio>=0.5.7" ] -optional-dependencies.doc = [ +optional-dependencies.parasail = [ + # parasail 1.2.1 fails to be installd on MacOS + "parasail!=1.2.1", +] +optional-dependencies.rpack = [ "rectangle-packer" ] +urls.Documentation = "https://scirpy.readthedocs.io/" +urls.Home-page = "https://github.com/scverse/scirpy" +urls.Source = "https://github.com/scverse/scirpy" + +[dependency-groups] +dev = [ "pre-commit" ] +test = [ + "anndata>=0.9", + "black", + "coverage", + "parasail!=1.2.1", + "pytest", + "rectangle-packer", + # "sc-dandelion>=0.3.5", + "scikit-bio>=0.5.7", +] +doc = [ "docutils>=0.8,!=0.18.*,!=0.19.*", # for tutorial "ipykernel", @@ -69,53 +87,39 @@ optional-dependencies.doc = [ "sphinx-copybutton", "sphinx-tabs", "sphinxcontrib-bibtex>=1", + "sphinxcontrib-katex", "sphinxext-opengraph", - # TODO needed for AnnData type hints - "zarr<3", -] -optional-dependencies.parasail = [ - # parasail 1.2.1 fails to be installd on MacOS - "parasail!=1.2.1", + "zarr", # required for anndata typehints ] -optional-dependencies.rpack = [ "rectangle-packer" ] -optional-dependencies.test = [ - "black", - "coverage", - "parasail!=1.2.1", - "pytest", - "rectangle-packer", - "sc-dandelion>=0.3.5", - "scikit-bio>=0.5.7", -] -urls.Documentation = "https://scirpy.readthedocs.io/" -urls.Home-page = "https://github.com/scverse/scirpy" -urls.Source = "https://github.com/scverse/scirpy" [tool.hatch.version] source = "vcs" [tool.hatch.envs.default] installer = "uv" -features = [ "dev" ] +dependency-groups = [ "dev" ] [tool.hatch.envs.docs] -features = [ "doc" ] +dependency-groups = [ "doc" ] scripts.build = "sphinx-build -M html docs docs/_build -W {args}" scripts.open = "python -m webbrowser -t docs/_build/html/index.html" scripts.clean = "git clean -fdX -- {args:docs}" +scripts.run_tutorial = "jupytext -k python3 --execute {args}" # Test the lowest and highest supported Python versions with normal deps [[tool.hatch.envs.hatch-test.matrix]] deps = [ "stable" ] -python = [ "3.10", "3.13" ] +python = [ "3.11", "3.14" ] # Test the newest supported Python version also with pre-release deps [[tool.hatch.envs.hatch-test.matrix]] deps = [ "pre" ] -python = [ "3.13" ] +python = [ "3.14" ] [tool.hatch.envs.hatch-test] -features = [ "dev", "test" ] +dependency-groups = [ "dev", "test" ] +default-args = [ +] # accounting for non-default tests path (specified via pytest.ini_options) [tool.hatch.envs.hatch-test.overrides] # If the matrix variable `deps` is set to "pre", @@ -192,10 +196,14 @@ lint.per-file-ignores."src/scirpy/datasets/_processing_scripts/*" = [ lint.per-file-ignores."tests/*" = [ "D" ] lint.pydocstyle.convention = "numpy" -[tool.pytest.ini_options] -testpaths = "src/scirpy/tests" +[tool.pytest] +strict = true xfail_strict = true -addopts = [ "-m not gpu" ] +addopts = [ + "--import-mode=importlib", # allow using test files with same name + "-m not gpu", +] +testpaths = [ "src/scirpy/tests" ] markers = [ "conda: marks a subset of tests to be ran on the Bioconda CI.", "extra: marks tests that require extra dependencies.",