From 61e7ba76ce394626e21690625815ac7699a1a35d Mon Sep 17 00:00:00 2001 From: scverse-bot <108668866+scverse-bot@users.noreply.github.com> Date: Wed, 2 Apr 2025 18:27:23 +0000 Subject: [PATCH] Automated template update to v0.5.0 --- .bumpversion.cfg | 8 - .codecov.yaml | 22 +- .cruft.json | 62 ++-- .editorconfig | 3 + .flake8 | 57 ---- .github/ISSUE_TEMPLATE/bug_report.yml | 169 +++++------ .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/ISSUE_TEMPLATE/feature_request.yml | 14 +- .github/workflows/build.yaml | 46 +-- .github/workflows/release.yaml | 34 +++ .github/workflows/test.yaml | 107 ++++--- .gitignore | 12 +- .pre-commit-config.yaml | 116 +++----- .readthedocs.yaml | 22 +- .vscode/extensions.json | 18 ++ .vscode/launch.json | 33 +++ .vscode/settings.json | 18 ++ biome.jsonc | 16 + docs/_static/css/custom.css | 4 + docs/_templates/autosummary/class.rst | 14 +- docs/conf.py | 40 ++- docs/contributing.md | 247 ++++++++-------- docs/extensions/typed_returns.py | 19 +- docs/make.bat | 35 --- docs/template_usage.md | 322 --------------------- pyproject.toml | 183 +++++++----- 26 files changed, 684 insertions(+), 943 deletions(-) delete mode 100644 .bumpversion.cfg delete mode 100644 .flake8 create mode 100644 .github/workflows/release.yaml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 biome.jsonc create mode 100644 docs/_static/css/custom.css delete mode 100644 docs/make.bat delete mode 100644 docs/template_usage.md diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index fdba9e4f..00000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[bumpversion] -current_version = 0.0.1 -tag = True -commit = True - -[bumpversion:file:./pyproject.toml] -search = version = "{current_version}" -replace = version = "{new_version}" diff --git a/.codecov.yaml b/.codecov.yaml index 829e56c0..d0c0e291 100644 --- a/.codecov.yaml +++ b/.codecov.yaml @@ -1,17 +1,17 @@ # Based on pydata/xarray codecov: - require_ci_to_pass: no + require_ci_to_pass: no coverage: - status: - project: - default: - # Require 1% coverage, i.e., always succeed - target: 1 - patch: false - changes: false + status: + project: + default: + # Require 1% coverage, i.e., always succeed + target: 1 + patch: false + changes: false comment: - layout: diff, flags, files - behavior: once - require_base: no + layout: diff, flags, files + behavior: once + require_base: no diff --git a/.cruft.json b/.cruft.json index 02453102..02781f21 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,23 +1,43 @@ { - "template": "/Users/tim.treis/Documents/GitHub/cookiecutter-scverse", - "commit": "7cc5403b05e299d7a4bb169c2bd8c27a2a7676f3", - "checkout": null, - "context": { - "cookiecutter": { - "project_name": "spatialdata-plot", - "package_name": "spatialdata_plot", - "project_description": "A very interesting piece of code", - "author_full_name": "scverse", - "author_email": "scverse", - "github_user": "scverse", - "project_repo": "https://github.com/scverse/spatialdata-plot", - "license": "BSD 3-Clause License", - "_copy_without_render": [ - ".github/workflows/**.yaml", - "docs/_templates/autosummary/**.rst" - ], - "_template": "/Users/tim.treis/Documents/GitHub/cookiecutter-scverse" - } - }, - "directory": null + "template": "https://github.com/scverse/cookiecutter-scverse", + "commit": "94ef9fb6f9ad8cfe65a3d9575679c03c80c49cd1", + "checkout": "v0.5.0", + "context": { + "cookiecutter": { + "project_name": "spatialdata-plot", + "package_name": "spatialdata_plot", + "project_description": "A very interesting piece of code", + "author_full_name": "scverse", + "author_email": "scverse", + "github_user": "scverse", + "github_repo": "spatialdata-plot", + "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": "94ef9fb6f9ad8cfe65a3d9575679c03c80c49cd1" + } + }, + "directory": null } diff --git a/.editorconfig b/.editorconfig index 2fe0ce08..66678e37 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,5 +8,8 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +[{*.{yml,yaml,toml},.cruft.json}] +indent_size = 2 + [Makefile] indent_style = tab diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 10cfc5a3..00000000 --- a/.flake8 +++ /dev/null @@ -1,57 +0,0 @@ -# Can't yet be moved to the pyproject.toml due to https://github.com/PyCQA/flake8/issues/234 -[flake8] -max-line-length = 120 -ignore = - # line break before a binary operator -> black does not adhere to PEP8 - W503 - # line break occured after a binary operator -> black does not adhere to PEP8 - W504 - # line too long -> we accept long comment lines; black gets rid of long code lines - E501 - # whitespace before : -> black does not adhere to PEP8 - E203 - # line break before binary operator -> black does not adhere to PEP8 - W503 - # missing whitespace after ,', ';', or ':' -> black does not adhere to PEP8 - E231 - # continuation line over-indented for hanging indent -> black does not adhere to PEP8 - E126 - # too many leading '#' for block comment -> this is fine for indicating sections - E262 - # Do not assign a lambda expression, use a def -> lambda expression assignments are convenient - E731 - # allow I, O, l as variable names -> I is the identity matrix - E741 - # Missing docstring in public package - D104 - # Missing docstring in public module - D100 - # Missing docstring in __init__ - D107 - # Errors from function calls in argument defaults. These are fine when the result is immutable. - B008 - # Missing docstring in magic method - D105 - # format string does contain unindexed parameters - P101 - # first line should end with a period [Bug: doesn't work with single-line docstrings] - D400 - # First line should be in imperative mood; try rephrasing - D401 -exclude = .git,__pycache__,build,docs/_build,dist -per-file-ignores = - tests/*: D - */__init__.py: F401 -rst-roles = - class, - func, - ref, - cite:p, - cite:t, -rst-directives = - envvar, - exception, -rst-substitutions = - version, -extend-ignore = - RST307, diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9dfd4acb..3ca1ccbd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -2,88 +2,93 @@ name: Bug report description: Report something that is broken or incorrect labels: bug body: - - type: markdown - attributes: - value: | - **Note**: Please read [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) - 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 procecure. - * 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. + - type: markdown + attributes: + value: | + **Note**: Please read [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) + 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. - - type: textarea - id: report - attributes: - label: Report - description: A clear and concise description of what the bug is. - validations: - required: true + - type: textarea + id: report + attributes: + label: Report + description: A clear and concise description of what the bug is. + validations: + required: true - - type: textarea - id: versions - attributes: - label: Version information - description: | - Please paste below the output of + - type: textarea + id: versions + attributes: + label: Versions + description: | + Which version of packages. - ```python - import session_info - session_info.show(html=False, dependencies=True) - ``` - placeholder: | - ----- - anndata 0.8.0rc2.dev27+ge524389 - session_info 1.0.0 - ----- - asttokens NA - awkward 1.8.0 - backcall 0.2.0 - cython_runtime NA - dateutil 2.8.2 - debugpy 1.6.0 - decorator 5.1.1 - entrypoints 0.4 - executing 0.8.3 - h5py 3.7.0 - ipykernel 6.15.0 - jedi 0.18.1 - mpl_toolkits NA - natsort 8.1.0 - numpy 1.22.4 - packaging 21.3 - pandas 1.4.2 - parso 0.8.3 - pexpect 4.8.0 - pickleshare 0.7.5 - pkg_resources NA - prompt_toolkit 3.0.29 - psutil 5.9.1 - ptyprocess 0.7.0 - pure_eval 0.2.2 - pydev_ipython NA - pydevconsole NA - pydevd 2.8.0 - pydevd_file_utils NA - pydevd_plugins NA - pydevd_tracing NA - pygments 2.12.0 - pytz 2022.1 - scipy 1.8.1 - setuptools 62.5.0 - setuptools_scm NA - six 1.16.0 - stack_data 0.3.0 - tornado 6.1 - traitlets 5.3.0 - wcwidth 0.2.5 - zmq 23.1.0 - ----- - IPython 8.4.0 - jupyter_client 7.3.4 - jupyter_core 4.10.0 - ----- - Python 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:58:50) [GCC 10.3.0] - Linux-5.18.6-arch1-1-x86_64-with-glibc2.35 - ----- - Session information updated at 2022-07-07 17:55 + Please install `session-info2`, run the following command in a notebook, + click the “Copy as Markdown” button, then paste the results into the text box below. + + ```python + In[1]: import session_info2; session_info2.session_info(dependencies=True) + ``` + + Alternatively, run this in a console: + + ```python + >>> import session_info2; print(session_info2.session_info(dependencies=True)._repr_mimebundle_()["text/markdown"]) + ``` + render: python + placeholder: | + anndata 0.11.3 + ---- ---- + charset-normalizer 3.4.1 + coverage 7.7.0 + psutil 7.0.0 + dask 2024.7.1 + jaraco.context 5.3.0 + numcodecs 0.15.1 + jaraco.functools 4.0.1 + Jinja2 3.1.6 + sphinxcontrib-jsmath 1.0.1 + sphinxcontrib-htmlhelp 2.1.0 + toolz 1.0.0 + session-info2 0.1.2 + PyYAML 6.0.2 + llvmlite 0.44.0 + scipy 1.15.2 + pandas 2.2.3 + sphinxcontrib-devhelp 2.0.0 + h5py 3.13.0 + tblib 3.0.0 + setuptools-scm 8.2.0 + more-itertools 10.3.0 + msgpack 1.1.0 + sparse 0.15.5 + wrapt 1.17.2 + jaraco.collections 5.1.0 + numba 0.61.0 + pyarrow 19.0.1 + pytz 2025.1 + MarkupSafe 3.0.2 + crc32c 2.7.1 + sphinxcontrib-qthelp 2.0.0 + sphinxcontrib-serializinghtml 2.0.0 + zarr 2.18.4 + asciitree 0.3.3 + six 1.17.0 + sphinxcontrib-applehelp 2.0.0 + numpy 2.1.3 + cloudpickle 3.1.1 + sphinxcontrib-bibtex 2.6.3 + natsort 8.4.0 + jaraco.text 3.12.1 + setuptools 76.1.0 + Deprecated 1.2.18 + packaging 24.2 + python-dateutil 2.9.0.post0 + ---- ---- + Python 3.13.2 | packaged by conda-forge | (main, Feb 17 2025, 14:10:22) [GCC 13.3.0] + OS Linux-6.11.0-109019-tuxedo-x86_64-with-glibc2.39 + Updated 2025-03-18 15:47 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5cad625d..5b62547f 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Scverse Community Forum - url: https://discourse.scverse.org/ - about: If you have questions about “How to do X”, please ask them here. + - name: Scverse Community Forum + url: https://discourse.scverse.org/ + about: If you have questions about “How to do X”, please ask them here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 90fe6251..ae9ca05b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -2,10 +2,10 @@ name: Feature request description: Propose a new feature for spatialdata-plot labels: enhancement body: - - type: textarea - id: description - attributes: - label: Description of feature - description: Please describe your suggestion for a new feature. It might help to describe a problem or use case, plus any alternatives that you have considered. - validations: - required: true + - type: textarea + id: description + attributes: + label: Description of feature + description: Please describe your suggestion for a new feature. It might help to describe a problem or use case, plus any alternatives that you have considered. + validations: + required: true diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 02429433..83e01a1e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,23 +1,33 @@ name: Check Build on: - push: - branches: [main] - pull_request: - branches: [main] + push: + branches: [main] + pull_request: + branches: [main] + +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@v2 - - name: Set up Python 3.10 - uses: actions/setup-python@v2 - with: - python-version: "3.10" - - name: Install build dependencies - run: python -m pip install --upgrade pip wheel twine build - - name: Build package - run: python -m build - - name: Check package - run: twine check --strict dist/*.whl + package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + filter: blob:none + fetch-depth: 0 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + cache-dependency-glob: pyproject.toml + - name: Build package + run: uv build + - name: Check package + run: uvx twine check --strict dist/*.whl diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..6c23760f --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,34 @@ +name: Release + +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: + name: Upload release to PyPI + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/spatialdata_plot + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + steps: + - uses: actions/checkout@v4 + with: + filter: blob:none + fetch-depth: 0 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + cache-dependency-glob: pyproject.toml + - name: Build package + run: uv build + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2f0ffd7a..d5cfb2a9 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,62 +1,59 @@ name: Test on: - push: - branches: [main] - pull_request: - branches: [main] + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 5 1,15 * *" + +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: - test: - runs-on: ${{ matrix.os }} - defaults: - run: - shell: bash -e {0} # -e to fail on error - - strategy: - fail-fast: false - matrix: - python: ["3.8", "3.10"] - os: [ubuntu-latest] + test: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + python: "3.10" + - os: ubuntu-latest + python: "3.12" + - os: ubuntu-latest + python: "3.12" + pip-flags: "--pre" + name: PRE-RELEASE DEPENDENCIES + + name: ${{ matrix.name }} Python ${{ matrix.python }} + + env: + OS: ${{ matrix.os }} + PYTHON: ${{ matrix.python }} + steps: + - uses: actions/checkout@v4 + with: + filter: blob:none + fetch-depth: 0 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + cache-dependency-glob: pyproject.toml + - name: run tests using hatch env: - OS: ${{ matrix.os }} - PYTHON: ${{ matrix.python }} - - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python }} - - - name: Get pip cache dir - id: pip-cache-dir - run: | - echo "::set-output name=dir::$(pip cache dir)" - - name: Restore pip cache - uses: actions/cache@v2 - with: - path: ${{ steps.pip-cache-dir.outputs.dir }} - key: pip-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('**/pyproject.toml') }} - restore-keys: | - pip-${{ runner.os }}-${{ env.pythonLocation }}- - - name: Install test dependencies - run: | - python -m pip install --upgrade pip wheel - pip install codecov - - name: Install dependencies - run: | - pip install ".[dev,test]" - - name: Test - env: - MPLBACKEND: agg - PLATFORM: ${{ matrix.os }} - DISPLAY: :42 - run: | - pytest -v --cov --color=yes - - name: Upload coverage - env: - CODECOV_NAME: ${{ matrix.python }}-${{ matrix.os }} - run: | - codecov --required --flags=unittests + MPLBACKEND: agg + PLATFORM: ${{ matrix.os }} + DISPLAY: :42 + run: uvx hatch test --cover --python ${{ matrix.python }} + - name: Upload coverage + uses: codecov/codecov-action@v4 diff --git a/.gitignore b/.gitignore index 7bb0bd5e..31e10b3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,20 @@ # Temp files .DS_Store *~ +buck-out/ # Compiled files +.venv/ __pycache__/ +.*cache/ # Distribution / packaging -/build/ /dist/ -/*.egg-info/ # Tests and coverage -/.pytest_cache/ -/.cache/ /data/ +/node_modules/ # docs /docs/generated/ /docs/_build/ - -# IDEs -/.idea/ -/.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 500ca49a..0fcce11e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,79 +1,47 @@ fail_fast: false default_language_version: - python: python3 + python: python3 default_stages: - - commit - - push + - pre-commit + - pre-push minimum_pre_commit_version: 2.16.0 repos: - - repo: https://github.com/psf/black - rev: 22.12.0 - hooks: - - id: black - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0-alpha.4 - hooks: - - id: prettier - - repo: https://github.com/asottile/blacken-docs - rev: v1.12.1 - hooks: - - id: blacken-docs - - repo: https://github.com/PyCQA/isort - rev: 5.11.4 - hooks: - - id: isort - - repo: https://github.com/asottile/yesqa - rev: v1.4.0 - hooks: - - id: yesqa - additional_dependencies: - - flake8-tidy-imports - - flake8-docstrings - - flake8-rst-docstrings - - flake8-comprehensions - - flake8-bugbear - - flake8-blind-except - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 - hooks: - - id: detect-private-key - - id: check-ast - - id: end-of-file-fixer - - id: mixed-line-ending - args: [--fix=lf] - - id: trailing-whitespace - - id: check-case-conflict - - repo: https://github.com/myint/autoflake - rev: v2.0.0 - hooks: - - id: autoflake - args: - - --in-place - - --remove-all-unused-imports - - --remove-unused-variable - - --ignore-init-module-imports - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 - hooks: - - id: flake8 - additional_dependencies: - - flake8-tidy-imports - - flake8-docstrings - - flake8-rst-docstrings - - flake8-comprehensions - - flake8-bugbear - - flake8-blind-except - - repo: https://github.com/asottile/pyupgrade - rev: v3.3.1 - hooks: - - id: pyupgrade - args: [--py3-plus, --py38-plus, --keep-runtime-typing] - - repo: local - hooks: - - id: forbid-to-commit - name: Don't commit rej files - entry: | - Cannot commit .rej files. These indicate merge conflicts that arise during automated template updates. - Fix the merge conflicts manually and remove the .rej files. - language: fail - files: '.*\.rej$' + - repo: https://github.com/biomejs/pre-commit + rev: v1.9.4 + hooks: + - id: biome-format + exclude: ^\.cruft\.json$ # inconsistent indentation with cruft - file never to be modified manually. + - repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.5.1 + hooks: + - id: pyproject-fmt + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.2 + hooks: + - id: ruff + types_or: [python, pyi, jupyter] + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format + types_or: [python, pyi, jupyter] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: detect-private-key + - id: check-ast + - id: end-of-file-fixer + - id: mixed-line-ending + args: [--fix=lf] + - id: trailing-whitespace + - 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] + - repo: local + hooks: + - id: forbid-to-commit + name: Don't commit rej files + entry: | + Cannot commit .rej files. These indicate merge conflicts that arise during automated template updates. + Fix the merge conflicts manually and remove the .rej files. + language: fail + files: '.*\.rej$' diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 9e5d5fa2..69897c3b 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,16 +1,16 @@ # https://docs.readthedocs.io/en/stable/config-file/v2.html version: 2 build: - os: ubuntu-20.04 - tools: - python: "3.10" + os: ubuntu-20.04 + tools: + python: "3.10" sphinx: - configuration: docs/conf.py - # disable this for more lenient docs builds - fail_on_warning: true + configuration: docs/conf.py + # disable this for more lenient docs builds + fail_on_warning: true python: - install: - - method: pip - path: . - extra_requirements: - - doc + install: + - method: pip + path: . + extra_requirements: + - doc diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..caaeb4f7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,18 @@ +{ + "recommendations": [ + // GitHub integration + "github.vscode-github-actions", + "github.vscode-pull-request-github", + // Language support + "ms-python.python", + "ms-python.vscode-pylance", + "ms-toolsai.jupyter", + "tamasfe.even-better-toml", + // Dependency management + "ninoseki.vscode-mogami", + // Linting and formatting + "editorconfig.editorconfig", + "charliermarsh.ruff", + "biomejs.biome", + ], +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..36d18746 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Build Documentation", + "type": "debugpy", + "request": "launch", + "module": "sphinx", + "args": ["-M", "html", ".", "_build"], + "cwd": "${workspaceFolder}/docs", + "console": "internalConsole", + "justMyCode": false, + }, + { + "name": "Python: Debug Test", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "purpose": ["debug-test"], + "console": "internalConsole", + "justMyCode": false, + "env": { + "PYTEST_ADDOPTS": "--color=yes", + }, + "presentation": { + "hidden": true, + }, + }, + ], +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..e034b91f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "[python][json][jsonc]": { + "editor.formatOnSave": true, + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.codeActionsOnSave": { + "source.fixAll": "always", + "source.organizeImports": "always", + }, + }, + "[json][jsonc]": { + "editor.defaultFormatter": "biomejs.biome", + }, + "python.analysis.typeCheckingMode": "basic", + "python.testing.pytestEnabled": true, + "python.testing.pytestArgs": ["-vv", "--color=yes"], +} diff --git a/biome.jsonc b/biome.jsonc new file mode 100644 index 00000000..2175c16e --- /dev/null +++ b/biome.jsonc @@ -0,0 +1,16 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "formatter": { "useEditorconfig": true }, + "overrides": [ + { + "include": ["./.vscode/*.json", "**/*.jsonc"], + "json": { + "formatter": { "trailingCommas": "all" }, + "parser": { + "allowComments": true, + "allowTrailingCommas": true, + }, + }, + }, + ], +} diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 00000000..b8c8d47f --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,4 @@ +/* Reduce the font size in data frames - See https://github.com/scverse/cookiecutter-scverse/issues/193 */ +div.cell_output table.dataframe { + font-size: 0.8em; +} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst index 17dc123c..7b4a0cf8 100644 --- a/docs/_templates/autosummary/class.rst +++ b/docs/_templates/autosummary/class.rst @@ -9,11 +9,11 @@ {% block attributes %} {% if attributes %} Attributes table -~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~ .. autosummary:: {% for item in attributes %} - ~{{ fullname }}.{{ item }} + ~{{ name }}.{{ item }} {%- endfor %} {% endif %} {% endblock %} @@ -26,7 +26,7 @@ Methods table .. autosummary:: {% for item in methods %} {%- if item != '__init__' %} - ~{{ fullname }}.{{ item }} + ~{{ name }}.{{ item }} {%- endif -%} {%- endfor %} {% endif %} @@ -35,13 +35,10 @@ Methods table {% block attributes_documentation %} {% if attributes %} Attributes -~~~~~~~~~~~ +~~~~~~~~~~ {% for item in attributes %} -{{ item }} -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. autoattribute:: {{ [objname, item] | join(".") }} {%- endfor %} @@ -56,9 +53,6 @@ Methods {% for item in methods %} {%- if item != '__init__' %} -{{ item }} -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. automethod:: {{ [objname, item] | join(".") }} {%- endif -%} {%- endfor %} diff --git a/docs/conf.py b/docs/conf.py index 02831db2..50bc4955 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,5 @@ # Configuration file for the Sphinx documentation builder. -# + # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html @@ -16,12 +16,15 @@ # -- Project information ----------------------------------------------------- +# 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("spatialdata-plot") project_name = info["Name"] author = info["Author"] copyright = f"{datetime.now():%Y}, {author}." version = info["Version"] -repository_url = f"https://github.com/scverse/{project_name}" +urls = dict(pu.split(", ") for pu in info.get_all("Project-URL")) +repository_url = urls["Source"] # The full version, including alpha/beta/rc tags release = info["Version"] @@ -33,10 +36,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_name, + "github_version": "main", + "conf_py_path": "/docs/", } # -- General configuration --------------------------------------------------- @@ -52,8 +55,10 @@ "sphinx.ext.napoleon", "sphinxcontrib.bibtex", "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")], ] @@ -65,7 +70,7 @@ napoleon_include_init_with_doc = False napoleon_use_rtype = True # having a separate entry generally helps readability napoleon_use_param = True -myst_heading_anchors = 3 # create anchors for h1-h3 +myst_heading_anchors = 6 # create anchors for h1-h6 myst_enable_extensions = [ "amsmath", "colon_fence", @@ -87,7 +92,9 @@ } intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), "anndata": ("https://anndata.readthedocs.io/en/stable/", None), + "scanpy": ("https://scanpy.readthedocs.io/en/stable/", None), "numpy": ("https://numpy.org/doc/stable/", None), } @@ -104,11 +111,15 @@ # html_theme = "sphinx_book_theme" html_static_path = ["_static"] +html_css_files = ["css/custom.css"] + html_title = project_name html_theme_options = { "repository_url": repository_url, "use_repository_button": True, + "path_to_docs": "docs/", + "navigation_with_keys": False, } pygments_style = "default" @@ -118,18 +129,3 @@ # you can add an exception to this list. # ("py:class", "igraph.Graph"), ] - - -def setup(app): - """App setup hook.""" - app.add_config_value( - "recommonmark_config", - { - "auto_toc_tree_section": "Contents", - "enable_auto_toc_tree": True, - "enable_math": True, - "enable_inline_math": False, - "enable_eval_rst": True, - }, - True, - ) diff --git a/docs/contributing.md b/docs/contributing.md index be9ddee5..330a7d13 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,27 +1,49 @@ # Contributing guide -Scanpy provides extensive [developer documentation][scanpy developer guide], most of which applies to this repo, too. -This document will not reproduce the entire content from there. Instead, it aims at summarizing the most important -information to get you started on contributing. +Scanpy provides extensive [developer documentation][scanpy developer guide], most of which applies to this project, too. +This document will not reproduce the entire content from there. +Instead, it aims at summarizing the most important information to get you started on contributing. -We assume that you are already familiar with git and with making pull requests on GitHub. If not, please refer -to the [scanpy developer guide][]. +We assume that you are already familiar with git and with making pull requests on GitHub. +If not, please refer to the [scanpy developer guide][]. + +[scanpy developer guide]: https://scanpy.readthedocs.io/en/latest/dev/index.html ## Installing dev dependencies -In addition to the packages needed to _use_ this package, you need additional python packages to _run tests_ and _build -the documentation_. It's easy to install them using `pip`: +In addition to the packages needed to _use_ this package, +you need additional python packages to [run tests](#writing-tests) and [build the documentation](#docs-building). + +:::::{tabs} +::::{group-tab} Hatch +The easiest way is to get familiar with [hatch environments][], with which these tasks are simply: + +```bash +hatch test # defined in the table [tool.hatch.envs.hatch-test] in pyproject.toml +hatch run docs:build # defined in the table [tool.hatch.envs.docs] +``` + +:::: + +::::{group-tab} Pip +If you prefer managing environments manually, you can use `pip`: ```bash cd spatialdata-plot +python3 -m venv .venv +source .venv/bin/activate pip install -e ".[dev,test,doc]" ``` +:::: +::::: + +[hatch environments]: https://hatch.pypa.io/latest/tutorials/environment/basic-usage/ + ## Code-style -This template uses [pre-commit][] to enforce consistent code-styles. On every commit, pre-commit checks will either -automatically fix issues with the code, or raise an error message. See [pre-commit checks](template_usage.md#pre-commit-checks) for -a full list of checks enabled for this repository. +This package uses [pre-commit][] to enforce consistent code-styles. +On every commit, pre-commit checks will either automatically fix issues with the code, or raise an error message. To enable pre-commit locally, simply run @@ -29,10 +51,11 @@ To enable pre-commit locally, simply run pre-commit install ``` -in the root of the repository. Pre-commit will automatically download all dependencies when it is run for the first time. +in the root of the repository. +Pre-commit will automatically download all dependencies when it is run for the first time. -Alternatively, you can rely on the [pre-commit.ci][] service enabled on GitHub. If you didn't run `pre-commit` before -pushing changes to GitHub it will automatically commit fixes to your pull request, or show an error message. +Alternatively, you can rely on the [pre-commit.ci][] service enabled on GitHub. +If you didn't run `pre-commit` before pushing changes to GitHub it will automatically commit fixes to your pull request, or show an error message. If pre-commit.ci added a commit on a branch you still have been working on locally, simply use @@ -43,155 +66,149 @@ git pull --rebase to integrate the changes into yours. While the [pre-commit.ci][] is useful, we strongly encourage installing and running pre-commit locally first to understand its usage. -Finally, most editors have an _autoformat on save_ feature. Consider enabling this option for [black][black-editors] -and [prettier][prettier-editors]. +Finally, most editors have an _autoformat on save_ feature. +Consider enabling this option for [ruff][ruff-editors] and [biome][biome-editors]. -[black-editors]: https://black.readthedocs.io/en/stable/integrations/editors.html -[prettier-editors]: https://prettier.io/docs/en/editors.html +[pre-commit]: https://pre-commit.com/ +[pre-commit.ci]: https://pre-commit.ci/ +[ruff-editors]: https://docs.astral.sh/ruff/integrations/ +[biome-editors]: https://biomejs.dev/guides/integrate-in-editor/ -## Writing tests +(writing-tests)= -```{note} -Remember to first install the package with `pip install '-e[dev,test]'` -``` +## Writing tests -This package uses the [pytest][] for automated testing. Please [write tests][scanpy-test-docs] for every function added -to the package. +This package uses [pytest][] for automated testing. +Please write {doc}`scanpy:dev/testing` for every function added to the package. -Most IDEs integrate with pytest and provide a GUI to run tests. Alternatively, you can run all tests from the -command line by executing +Most IDEs integrate with pytest and provide a GUI to run tests. +Just point yours to one of the environments returned by ```bash -pytest +hatch env create hatch-test # create test environments for all supported versions +hatch env find hatch-test # list all possible test environment paths ``` -in the root of the repository. Continuous integration will automatically run the tests on all pull requests. - -[scanpy-test-docs]: https://scanpy.readthedocs.io/en/latest/dev/testing.html#writing-tests +Alternatively, you can run all tests from the command line by executing -## Publishing a release - -### Updating the version number - -Before making a release, you need to update the version number. Please adhere to [Semantic Versioning][semver], in brief - -> Given a version number MAJOR.MINOR.PATCH, increment the: -> -> 1. MAJOR version when you make incompatible API changes, -> 2. MINOR version when you add functionality in a backwards compatible manner, and -> 3. PATCH version when you make backwards compatible bug fixes. -> -> Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. - -We use [bump2version][] to automatically update the version number in all places and automatically create a git tag. -Run one of the following commands in the root of the repository +:::::{tabs} +::::{group-tab} Hatch ```bash -bump2version patch -bump2version minor -bump2version major +hatch test # test with the highest supported Python version +# or +hatch test --all # test with all supported Python versions ``` -Once you are done, run - -``` -git push --tags -``` +:::: -to publish the created tag on GitHub. +::::{group-tab} Pip -[bump2version]: https://github.com/c4urself/bump2version +```bash +source .venv/bin/activate +pytest +``` -### Building and publishing the package on PyPI +:::: +::::: -Python packages are not distributed as source code, but as _distributions_. The most common distribution format is the so-called _wheel_. To build a _wheel_, run +in the root of the repository. -```bash -python -m build -``` +[pytest]: https://docs.pytest.org/ -This command creates a _source archive_ and a _wheel_, which are required for publishing your package to [PyPI][]. These files are created directly in the root of the repository. +### Continuous integration -Before uploading them to [PyPI][] you can check that your _distribution_ is valid by running: +Continuous integration will automatically run the tests on all pull requests and test +against the minimum and maximum supported Python version. -```bash -twine check dist/* -``` +Additionally, there's a CI job that tests against pre-releases of all dependencies (if there are any). +The purpose of this check is to detect incompatibilities of new package versions early on and +gives you time to fix the issue or reach out to the developers of the dependency before the package is released to a wider audience. -and finally publishing it with: +## Publishing a release -```bash -twine upload dist/* -``` +### Updating the version number -Provide your username and password when requested and then go check out your package on [PyPI][]! +Before making a release, you need to update the version number in the `pyproject.toml` file. +Please adhere to [Semantic Versioning][semver], in brief -For more information, follow the [Python packaging tutorial][]. +> Given a version number MAJOR.MINOR.PATCH, increment the: +> +> 1. MAJOR version when you make incompatible API changes, +> 2. MINOR version when you add functionality in a backwards compatible manner, and +> 3. PATCH version when you make backwards compatible bug fixes. +> +> Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. -It is possible to automate this with GitHub actions, see also [this feature request][pypi-feature-request] -in the cookiecutter-scverse template. +Once you are done, commit and push your changes and navigate to the "Releases" page of this project on GitHub. +Specify `vX.X.X` as a tag name and create a release. +For more information, see [managing GitHub releases][]. +This will automatically create a git tag and trigger a Github workflow that creates a release on [PyPI][]. -[python packaging tutorial]: https://packaging.python.org/en/latest/tutorials/packaging-projects/#generating-distribution-archives -[pypi-feature-request]: https://github.com/scverse/cookiecutter-scverse/issues/88 +[semver]: https://semver.org/ +[managing GitHub releases]: https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository +[pypi]: https://pypi.org/ ## Writing documentation -Please write documentation for new or changed features and use-cases. This project uses [sphinx][] with the following features: +Please write documentation for new or changed features and use-cases. +This project uses [sphinx][] with the following features: -- the [myst][] extension allows to write documentation in markdown/Markedly Structured Text -- [Numpy-style docstrings][numpydoc] (through the [napoloen][numpydoc-napoleon] extension). -- Jupyter notebooks as tutorials through [myst-nb][] (See [Tutorials with myst-nb](#tutorials-with-myst-nb-and-jupyter-notebooks)) -- [Sphinx autodoc typehints][], to automatically reference annotated input and output types +- The [myst][] extension allows to write documentation in markdown/Markedly Structured Text +- [Numpy-style docstrings][numpydoc] (through the [napoloen][numpydoc-napoleon] extension). +- Jupyter notebooks as tutorials through [myst-nb][] (See [Tutorials with myst-nb](#tutorials-with-myst-nb-and-jupyter-notebooks)) +- [sphinx-autodoc-typehints][], to automatically reference annotated input and output types +- Citations (like {cite:p}`Virshup_2023`) can be included with [sphinxcontrib-bibtex](https://sphinxcontrib-bibtex.readthedocs.io/) -See the [scanpy developer docs](https://scanpy.readthedocs.io/en/latest/dev/documentation.html) for more information -on how to write documentation. +See scanpy’s {doc}`scanpy:dev/documentation` for more information on how to write your own. + +[sphinx]: https://www.sphinx-doc.org/en/master/ +[myst]: https://myst-parser.readthedocs.io/en/latest/intro.html +[myst-nb]: https://myst-nb.readthedocs.io/en/latest/ +[numpydoc-napoleon]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html +[numpydoc]: https://numpydoc.readthedocs.io/en/latest/format.html +[sphinx-autodoc-typehints]: https://github.com/tox-dev/sphinx-autodoc-typehints ### Tutorials with myst-nb and jupyter notebooks The documentation is set-up to render jupyter notebooks stored in the `docs/notebooks` directory using [myst-nb][]. Currently, only notebooks in `.ipynb` format are supported that will be included with both their input and output cells. -It is your reponsibility to update and re-run the notebook whenever necessary. +It is your responsibility to update and re-run the notebook whenever necessary. -If you are interested in automatically running notebooks as part of the continuous integration, please check -out [this feature request](https://github.com/scverse/cookiecutter-scverse/issues/40) in the `cookiecutter-scverse` -repository. +If you are interested in automatically running notebooks as part of the continuous integration, +please check out [this feature request][issue-render-notebooks] in the `cookiecutter-scverse` repository. + +[issue-render-notebooks]: https://github.com/scverse/cookiecutter-scverse/issues/40 #### Hints -- If you refer to objects from other packages, please add an entry to `intersphinx_mapping` in `docs/conf.py`. Only - if you do so can sphinx automatically create a link to the external documentation. -- If building the documentation fails because of a missing link that is outside your control, you can add an entry to - the `nitpick_ignore` list in `docs/conf.py` +- If you refer to objects from other packages, please add an entry to `intersphinx_mapping` in `docs/conf.py`. + Only if you do so can sphinx automatically create a link to the external documentation. +- If building the documentation fails because of a missing link that is outside your control, + you can add an entry to the `nitpick_ignore` list in `docs/conf.py` + +(docs-building)= #### Building the docs locally +:::::{tabs} +::::{group-tab} Hatch + ```bash +hatch run docs:build +hatch run docs:open +``` + +:::: + +::::{group-tab} Pip + +```bash +source .venv/bin/activate cd docs make html -open _build/html/index.html +(xdg-)open _build/html/index.html ``` - - -[scanpy developer guide]: https://scanpy.readthedocs.io/en/latest/dev/index.html -[cookiecutter-scverse-instance]: https://cookiecutter-scverse-instance.readthedocs.io/en/latest/template_usage.html -[github quickstart guide]: https://docs.github.com/en/get-started/quickstart/create-a-repo?tool=webui -[codecov]: https://about.codecov.io/sign-up/ -[codecov docs]: https://docs.codecov.com/docs -[codecov bot]: https://docs.codecov.com/docs/team-bot -[codecov app]: https://github.com/apps/codecov -[pre-commit.ci]: https://pre-commit.ci/ -[readthedocs.org]: https://readthedocs.org/ -[myst-nb]: https://myst-nb.readthedocs.io/en/latest/ -[jupytext]: https://jupytext.readthedocs.io/en/latest/ -[pre-commit]: https://pre-commit.com/ -[anndata]: https://github.com/scverse/anndata -[mudata]: https://github.com/scverse/mudata -[pytest]: https://docs.pytest.org/ -[semver]: https://semver.org/ -[sphinx]: https://www.sphinx-doc.org/en/master/ -[myst]: https://myst-parser.readthedocs.io/en/latest/intro.html -[numpydoc-napoleon]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html -[numpydoc]: https://numpydoc.readthedocs.io/en/latest/format.html -[sphinx autodoc typehints]: https://github.com/tox-dev/sphinx-autodoc-typehints -[pypi]: https://pypi.org/ +:::: +::::: diff --git a/docs/extensions/typed_returns.py b/docs/extensions/typed_returns.py index 94478130..0fbffefe 100644 --- a/docs/extensions/typed_returns.py +++ b/docs/extensions/typed_returns.py @@ -1,24 +1,27 @@ # code from https://github.com/theislab/scanpy/blob/master/docs/extensions/typed_returns.py # with some minor adjustment +from __future__ import annotations + import re +from collections.abc import Generator, Iterable from sphinx.application import Sphinx from sphinx.ext.napoleon import NumpyDocstring -def _process_return(lines): +def _process_return(lines: Iterable[str]) -> Generator[str, None, None]: for line in lines: - m = re.fullmatch(r"(?P\w+)\s+:\s+(?P[\w.]+)", line) - if m: - # Once this is in scanpydoc, we can use the fancy hover stuff - yield f'-{m["param"]} (:class:`~{m["type"]}`)' + if m := re.fullmatch(r"(?P\w+)\s+:\s+(?P[\w.]+)", line): + yield f"-{m['param']} (:class:`~{m['type']}`)" else: yield line -def _parse_returns_section(self, section): - lines_raw = list(_process_return(self._dedent(self._consume_to_next_section()))) - lines = self._format_block(":returns: ", lines_raw) +def _parse_returns_section(self: NumpyDocstring, section: str) -> list[str]: + lines_raw = self._dedent(self._consume_to_next_section()) + if lines_raw[0] == ":": + del lines_raw[0] + lines = self._format_block(":returns: ", list(_process_return(lines_raw))) if lines and lines[-1]: lines.append("") return lines diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 954237b9..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/template_usage.md b/docs/template_usage.md deleted file mode 100644 index 6b39e178..00000000 --- a/docs/template_usage.md +++ /dev/null @@ -1,322 +0,0 @@ -# Using this template - -Welcome to the developer guidelines! This document is split into two parts: - -1. The [repository setup](#setting-up-the-repository). This section is relevant primarily for the repository maintainer and shows how to connect - continuous integration services and documents initial set-up of the repository. -2. The [contributor guide](contributing.md#contributing-guide). It contains information relevant to all developers who want to make a contribution. - -## Setting up the repository - -### First commit - -If you are reading this, you should have just completed the repository creation with : - -```bash -cruft create https://github.com/scverse/cookiecutter-scverse -``` - -and you should have - -``` -cd spatialdata-plot -``` - -into the new project directory. Now that you have created a new repository locally, the first step is to push it to github. To do this, you'd have to create a **new repository** on github. -You can follow the instructions directly on [github quickstart guide][]. -Since `cruft` already populated the local repository of your project with all the necessary files, we suggest to _NOT_ initialize the repository with a `README.md` file or `.gitignore`, because you might encounter git conflicts on your first push. -If you are familiar with git and knows how to handle git conflicts, you can go ahead with your preferred choice. - -:::{note} -If you are looking at this document in the [cookiecutter-scverse-instance][] repository documentation, throughout this document the name of the project is `cookiecutter-scverse-instance`. Otherwise it should be replaced by your new project name: `spatialdata-plot`. -::: - -Now that your new project repository has been created on github at `https://github.com/scverse/spatialdata-plot` you can push your first commit to github. -To do this, simply follow the instructions on your github repository page or a more verbose walkthrough here: - -Assuming you are in `/your/path/to/spatialdata-plot`. Add all files and commit. - -```bash -# stage all files of your new repo -git add --all -# commit -git commit -m "first commit" -``` - -You'll notice that the command `git commit` installed a bunch of packages and triggered their execution: those are pre-commit! To read more about what they are and what they do, you can go to the related section [Pre-commit checks](#pre-commit-checks) in this document. - -:::{note} -There is a chance that `git commit -m "first commit"` fails due to the `prettier` pre-commit formatting the file `.cruft.json`. No problem, you have just experienced what pre-commit checks do in action. Just go ahead and re-add the modified file and try to commit again: - -```bash - git add -u # update all tracked file - git commit -m "first commit" -``` - -::: - -Now that all the files of the newly created project have been committed, go ahead with the remaining steps: - -```bash -# update the `origin` of your local repo with the remote github link -git remote add origin https://github.com/scverse/spatialdata-plot.git -# rename the default branch to main -git branch -M main -# push all your files to remote -git push -u origin main -``` - -Your project should be now available at `https://github.com/scverse/spatialdata-plot`. While the repository at this point can be directly used, there are few remaining steps that needs to be done in order to achieve full functionality. - -### Coverage tests with _Codecov_ - -Coverage tells what fraction of the code is "covered" by unit tests, thereby encouraging contributors to -[write tests](contributing.md#writing-tests). -To enable coverage checks, head over to [codecov][] and sign in with your GitHub account. -You'll find more information in "getting started" section of the [codecov docs][]. - -In the `Actions` tab of your projects' github repository, you can see that the workflows are failing due to the **Upload coverage** step. The error message in the workflow should display something like: - -``` -... - Retrying 5/5 in 2s.. - {'detail': ErrorDetail(string='Could not find a repository, try using repo upload token', code='not_found')} -Error: 404 Client Error: Not Found for url: -... -``` - -While [codecov docs][] has a very extensive documentation on how to get started, _if_ you are using the default settings of this template we can assume that you are using [codecov][] in a github action workflow and hence you can make use of the [codecov bot][]. - -To set it up, simply go to the [codecov app][] page and follow the instructions to activate it for your repository. -Once the activation is completed, go back to the `Actions` tab and re-run the failing workflows. - -The workflows should now succeed and you will be able to find the code coverage at this link: `https://app.codecov.io/gh/scverse/spatialdata-plot`. You might have to wait couple of minutes and the coverage of this repository should be ~60%. - -If your repository is private, you will have to specify an additional token in the repository secrets. In brief, you need to: - -1. Generate a Codecov Token by clicking _setup repo_ in the codecov dashboard. - - If you have already set up codecov in the repository by following the previous steps, you can directly go to the codecov repo webpage. -2. Go to _Settings_ and copy **only** the token `_______-____-...`. -3. Go to _Settings_ of your newly created repository on GitHub. -4. Go to _Security > Secrets > Actions_. -5. Create new repository secret with name `CODECOV_TOKEN` and paste the token generated by codecov. -6. Past these additional lines in `/.github/workflows.test.yaml` under the **Upload coverage** step: - ```bash - - name: Upload coverage - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - ``` -7. Go back to github `Actions` page an re-run previously failed jobs. - -### Documentation on _readthedocs_ - -We recommend using [readthedocs.org][] (RTD) to build and host the documentation for your project. -To enable readthedocs, head over to [their website][readthedocs.org] and sign in with your GitHub account. -On the RTD dashboard choose "Import a Project" and follow the instructions to add your repository. - -- Make sure to choose the correct name of the default branch. On GitHub, the name of the default branch should be `main` (it has - recently changed from `master` to `main`). -- We recommend to enable documentation builds for pull requests (PRs). This ensures that a PR doesn't introduce changes - that break the documentation. To do so, got to `Admin -> Advanced Settings`, check the - `Build pull requests for this projects` option, and click `Save`. For more information, please refer to - the [official RTD documentation](https://docs.readthedocs.io/en/stable/pull-requests.html). -- If you find the RTD builds are failing, you can disable the `fail_on_warning` option in `.readthedocs.yaml`. - -If your project is private, there are ways to enable docs rendering on [readthedocs.org][] but it is more cumbersome and requires a different subscription for read the docs. See a guide [here](https://docs.readthedocs.io/en/stable/guides/importing-private-repositories.html). - -### Pre-commit checks - -[Pre-commit][] checks are fast programs that -check code for errors, inconsistencies and code styles, before the code -is committed. - -We recommend setting up [pre-commit.ci][] to enforce consistency checks on every commit -and pull-request. - -To do so, head over to [pre-commit.ci][] and click "Sign In With GitHub". Follow -the instructions to enable pre-commit.ci for your account or your organization. You -may choose to enable the service for an entire organization or on a per-repository basis. - -Once authorized, pre-commit.ci should automatically be activated. - -#### Overview of pre-commit hooks used by the template - -The following pre-commit checks are for code style and format: - -- [black](https://black.readthedocs.io/en/stable/): standard code - formatter in Python. -- [isort](https://pycqa.github.io/isort/): sort module imports into - sections and types. -- [prettier](https://prettier.io/docs/en/index.html): standard code - formatter for non-Python files (e.g. YAML). -- [blacken-docs](https://github.com/asottile/blacken-docs): black on - python code in docs. - -The following pre-commit checks are for errors and inconsistencies: - -- [flake8](https://flake8.pycqa.org/en/latest/): standard check for errors in Python files. - - [flake8-tidy-imports](https://github.com/adamchainz/flake8-tidy-imports): - tidy module imports. - - [flake8-docstrings](https://github.com/PyCQA/flake8-docstrings): - pydocstyle extension of flake8. - - [flake8-rst-docstrings](https://github.com/peterjc/e8-rst-docstrings): - extension of `flake8-docstrings` for `rst` docs. - - [flake8-comprehensions](https://github.com/adamchainz/e8-comprehensions): - write better list/set/dict comprehensions. - - [flake8-bugbear](https://github.com/PyCQA/flake8-bugbear): - find possible bugs and design issues in program. - - [flake8-blind-except](https://github.com/elijahandrews/flake8-blind-except): - checks for blind, catch-all `except` statements. -- [yesqa](https://github.com/asottile/yesqa): - remove unneccesary `# noqa` comments, follows additional dependencies listed above. -- [autoflake](https://github.com/PyCQA/autoflake): - remove unused imports and variables. -- [pre-commit-hooks](https://github.com/pre-commit/pre-commit-hooks): generic pre-commit hooks. - - **detect-private-key**: checks for the existence of private keys. - - **check-ast**: check whether files parse as valid python. - - **end-of-file-fixer**:check files end in a newline and only a newline. - - **mixed-line-ending**: checks mixed line ending. - - **trailing-whitespace**: trims trailing whitespace. - - **check-case-conflict**: check files that would conflict with case-insensitive file systems. -- [pyupgrade](https://github.com/asottile/pyupgrade): - upgrade syntax for newer versions of the language. -- **forbid-to-commit**: Make sure that `*.rej` files cannot be commited. These files are created by the - [automated template sync](#automated-template-sync) if there's a merge conflict and need to be addressed manually. - -### How to disable or add pre-commit checks - -- To ignore lint warnigs from **flake8**, see [Ignore certain lint warnings](#how-to-ignore-certain-lint-warnings). -- You can add or remove pre-commit checks by simply deleting relevant lines in the `.pre-commit-config.yaml` file. - Some pre-commit checks have additional options that can be specified either in the `pyproject.toml` or tool-specific - config files, such as `.prettierrc.yml` for **prettier** and `.flake8` for **flake8**. - -### How to ignore certain lint warnings - -The [pre-commit checks](#pre-commit-checks) include [flake8](https://flake8.pycqa.org/en/latest/) which checks -for errors in Python files, including stylistic errors. - -In some cases it might overshoot and you may have good reasons to ignore certain warnings. - -To ignore an specific error on a per-case basis, you can add a comment `# noqa` to the offending line. You can also -specify the error ID to ignore, with e.g. `# noqa: E731`. Check the [flake8 guide][] for reference. - -Alternatively, you can disable certain error messages for the entire project. To do so, edit the `.flake8` -file in the root of the repository. Add one line per linting code you wish to ignore and don't forget to add a comment. - -```toml -... -# line break before a binary operator -> black does not adhere to PEP8 -W503 -# line break occured after a binary operator -> black does not adhere to PEP8 -W504 -... -``` - -[flake8 guide]: https://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html - -### API design - -Scverse ecosystem packages should operate on [AnnData][] and/or [MuData][] data structures and typically use an API -as originally [introduced by scanpy][scanpy-api] with the following submodules: - -- `pp` for preprocessing -- `tl` for tools (that, compared to `pp` generate interpretable output, often associated with a corresponding plotting - function) -- `pl` for plotting functions - -You may add additional submodules as appropriate. While we encourage to follow a scanpy-like API for ecosystem packages, -there may also be good reasons to choose a different approach, e.g. using an object-oriented API. - -[scanpy-api]: https://scanpy.readthedocs.io/en/stable/usage-principles.html - -### Using VCS-based versioning - -By default, the template uses hard-coded version numbers that are set in `pyproject.toml` and [managed with -bump2version](contributing.md#publishing-a-release). If you prefer to have your project automatically infer version numbers from git -tags, it is straightforward to switch to vcs-based versioning using [hatch-vcs][]. - -In `pyproject.toml` add the following changes, and you are good to go! - -```diff ---- a/pyproject.toml -+++ b/pyproject.toml -@@ -1,11 +1,11 @@ - [build-system] - build-backend = "hatchling.build" --requires = ["hatchling"] -+requires = ["hatchling", "hatch-vcs"] - - - [project] - name = "spatialdata-plot" --version = "0.3.1dev" -+dynamic = ["version"] - -@@ -60,6 +60,9 @@ -+[tool.hatch.version] -+source = "vcs" -+ - [tool.coverage.run] - source = ["spatialdata-plot"] - omit = [ -``` - -Don't forget to update the [Making a release section](contributing.md#publishing-a-release) in this document accordingly, after you are done! - -[hatch-vcs]: https://pypi.org/project/hatch-vcs/ - -### Automated template sync - -Automated template sync is enabled by default. This means that every night, a GitHub action runs [cruft][] to check -if a new version of the `scverse-cookiecutter` template got released. If there are any new changes, a pull request -proposing these changes is created automatically. This helps keeping the repository up-to-date with the latest -coding standards. - -It may happen that a template sync results in a merge conflict. If this is the case a `*.ref` file with the -diff is created. You need to manually address these changes and remove the `.rej` file when you are done. -The pull request can only be merged after all `*.rej` files have been removed. - -:::{tip} -The following hints may be useful to work with the template sync: - -- GitHub automatically disables scheduled actions if there has been not activity to the repository for 60 days. - You can re-enable or manually trigger the sync by navigating to `Actions` -> `Sync Template` in your GitHub repository. -- If you want to ignore certain files from the template update, you can add them to the `[tool.cruft]` section in the - `pyproject.toml` file in the root of your repository. More details are described in the - [cruft documentation][cruft-update-project]. -- To disable the sync entirely, simply remove the file `.github/workflows/sync.yaml`. - -::: - -[cruft]: https://cruft.github.io/cruft/ -[cruft-update-project]: https://cruft.github.io/cruft/#updating-a-project - -## Moving forward - -You have reached the end of this document. Congratulations! You have successfully set up your project and are ready to start. -For everything else related to documentation, code style, testing and publishing your project ot pypi, please refer to the [contributing docs](contributing.md#contributing-guide). - - - -[scanpy developer guide]: https://scanpy.readthedocs.io/en/latest/dev/index.html -[cookiecutter-scverse-instance]: https://cookiecutter-scverse-instance.readthedocs.io/en/latest/template_usage.html -[github quickstart guide]: https://docs.github.com/en/get-started/quickstart/create-a-repo?tool=webui -[codecov]: https://about.codecov.io/sign-up/ -[codecov docs]: https://docs.codecov.com/docs -[codecov bot]: https://docs.codecov.com/docs/team-bot -[codecov app]: https://github.com/apps/codecov -[pre-commit.ci]: https://pre-commit.ci/ -[readthedocs.org]: https://readthedocs.org/ -[myst-nb]: https://myst-nb.readthedocs.io/en/latest/ -[jupytext]: https://jupytext.readthedocs.io/en/latest/ -[pre-commit]: https://pre-commit.com/ -[anndata]: https://github.com/scverse/anndata -[mudata]: https://github.com/scverse/mudata -[pytest]: https://docs.pytest.org/ -[semver]: https://semver.org/ -[sphinx]: https://www.sphinx-doc.org/en/master/ -[myst]: https://myst-parser.readthedocs.io/en/latest/intro.html -[numpydoc-napoleon]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html -[numpydoc]: https://numpydoc.readthedocs.io/en/latest/format.html -[sphinx autodoc typehints]: https://github.com/tox-dev/sphinx-autodoc-typehints diff --git a/pyproject.toml b/pyproject.toml index fe0c998f..3fe37d08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,104 +1,135 @@ [build-system] build-backend = "hatchling.build" -requires = ["hatchling"] - +requires = [ "hatchling" ] [project] name = "spatialdata-plot" version = "0.0.1" description = "A very interesting piece of code" readme = "README.md" -requires-python = ">=3.8" -license = {file = "LICENSE"} +license = { file = "LICENSE" } +maintainers = [ + { name = "scverse", email = "scverse" }, +] authors = [ - {name = "scverse"}, + { name = "scverse" }, ] -maintainers = [ - {name = "scverse", email = "scverse"}, +requires-python = ">=3.10" +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", ] -urls.Documentation = "https://spatialdata-plot.readthedocs.io/" -urls.Source = "https://github.com/scverse/spatialdata-plot" -urls.Home-page = "https://github.com/scverse/spatialdata-plot" dependencies = [ - "anndata", - # for debug logging (referenced from the issue template) - "session-info" + "anndata", + # for debug logging (referenced from the issue template) + "session-info2", ] - -[project.optional-dependencies] -dev = [ - # CLI for bumping the version number - "bump2version", - "pre-commit", - "twine>=4.0.2" +optional-dependencies.dev = [ + "pre-commit", + "twine>=4.0.2", ] -doc = [ - "sphinx>=4", - "sphinx-book-theme>=0.3.3", - "myst-nb", - "sphinxcontrib-bibtex>=1.0.0", - "sphinx-autodoc-typehints", - # For notebooks - "ipykernel", - "ipython", - "sphinx-copybutton", +optional-dependencies.doc = [ + "docutils>=0.8,!=0.18.*,!=0.19.*", + "ipykernel", + "ipython", + "myst-nb>=1.1", + "pandas", + # Until pybtex >0.24.0 releases: https://bitbucket.org/pybtex-devs/pybtex/issues/169/ + "setuptools", + "sphinx>=4", + "sphinx-autodoc-typehints", + "sphinx-book-theme>=1", + "sphinx-copybutton", + "sphinx-tabs", + "sphinxcontrib-bibtex>=1", + "sphinxext-opengraph", ] -test = [ - "pytest", - "pytest-cov", +optional-dependencies.test = [ + "coverage", + "pytest", ] +# https://docs.pypi.org/project_metadata/#project-urls +urls.Documentation = "https://spatialdata-plot.readthedocs.io/" +urls.Homepage = "https://github.com/scverse/spatialdata-plot" +urls.Source = "https://github.com/scverse/spatialdata-plot" -[tool.coverage.run] -source = ["spatialdata_plot"] -omit = [ - "**/test_*.py", +[tool.hatch.envs.default] +installer = "uv" +features = [ "dev" ] + +[tool.hatch.envs.docs] +features = [ "doc" ] +scripts.build = "sphinx-build -M html docs docs/_build {args}" +scripts.open = "python -m webbrowser -t docs/_build/html/index.html" +scripts.clean = "git clean -fdX -- {args:docs}" + +[tool.hatch.envs.hatch-test] +features = [ "test" ] + +[tool.ruff] +line-length = 120 +src = [ "src" ] +extend-include = [ "*.ipynb" ] + +format.docstring-code-format = true + +lint.select = [ + "B", # flake8-bugbear + "BLE", # flake8-blind-except + "C4", # flake8-comprehensions + "D", # pydocstyle + "E", # Error detected by Pycodestyle + "F", # Errors detected by Pyflakes + "I", # isort + "RUF100", # Report unused noqa directives + "TID", # flake8-tidy-imports + "UP", # pyupgrade + "W", # Warning detected by Pycodestyle +] +lint.ignore = [ + "B008", # Errors from function calls in argument defaults. These are fine when the result is immutable. + "D100", # Missing docstring in public module + "D104", # Missing docstring in public package + "D105", # __magic__ methods are often self-explanatory, allow missing docstrings + "D107", # Missing docstring in __init__ + # Disable one in each pair of mutually incompatible rules + "D203", # We don’t want a blank line before a class docstring + "D213", # <> We want docstrings to start immediately after the opening triple quote + "D400", # first line should end with a period [Bug: doesn’t work with single-line docstrings] + "D401", # First line should be in imperative mood; try rephrasing + "E501", # line too long -> we accept long comment lines; formatter gets rid of long code lines + "E731", # Do not assign a lambda expression, use a def -> lambda expression assignments are convenient + "E741", # allow I, O, l as variable names -> I is the identity matrix ] +lint.per-file-ignores."*/__init__.py" = [ "F401" ] +lint.per-file-ignores."docs/*" = [ "I" ] +lint.per-file-ignores."tests/*" = [ "D" ] +lint.pydocstyle.convention = "numpy" [tool.pytest.ini_options] -testpaths = ["tests"] +testpaths = [ "tests" ] xfail_strict = true addopts = [ - "--import-mode=importlib", # allow using test files with same name + "--import-mode=importlib", # allow using test files with same name ] -[tool.isort] -include_trailing_comma = true -multi_line_output = 3 -profile = "black" -skip_glob = ["docs/*"] - -[tool.black] -line-length = 120 -target-version = ['py38'] -include = '\.pyi?$' -exclude = ''' -( - /( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - )/ -) -''' - -[tool.jupytext] -formats = "ipynb,md" +[tool.coverage.run] +source = [ "spatialdata_plot" ] +omit = [ + "**/test_*.py", +] [tool.cruft] skip = [ - "tests", - "src/**/__init__.py", - "src/**/basic.py", - "docs/api.md", - "docs/changelog.md", - "docs/references.bib", - "docs/references.md", - "docs/notebooks/example.ipynb" + "tests", + "src/**/__init__.py", + "src/**/basic.py", + "docs/api.md", + "docs/changelog.md", + "docs/references.bib", + "docs/references.md", + "docs/notebooks/example.ipynb", ]