diff --git a/.cruft.json b/.cruft.json old mode 100755 new mode 100644 index abbb619..343ece1 --- a/.cruft.json +++ b/.cruft.json @@ -13,6 +13,7 @@ "github_repo": "pycea", "license": "BSD 3-Clause License", "ide_integration": true, + "issue_categorization": "", "_copy_without_render": [ ".github/workflows/build.yaml", ".github/workflows/test.yaml", diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..914ad69 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + cooldown: + default-days: 7 + groups: + actions-deps: + patterns: + - "*" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c6ecc2f..876c355 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -18,6 +18,7 @@ jobs: with: filter: blob:none fetch-depth: 0 + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@v7 - name: Build package diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9c79a02..de9101a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,6 +5,8 @@ on: types: [published] # Use "trusted publishing", see https://docs.pypi.org/trusted-publishers/ +permissions: {} + jobs: release: name: Upload release to PyPI @@ -13,15 +15,17 @@ jobs: name: pypi url: https://pypi.org/p/pycea-lineage permissions: + contents: read id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - uses: actions/checkout@v5 with: filter: blob:none fetch-depth: 0 + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@v7 - name: Build package run: uv build - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 327964b..cc64891 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -19,7 +19,7 @@ jobs: # Check [[tool.hatch.envs.hatch-test.matrix]] in pyproject.toml and https://hatch.pypa.io/latest/environment/ for # more details. get-environments: - runs-on: ubuntu-latest + runs-on: ubuntu-slim outputs: envs: ${{ steps.get-envs.outputs.envs }} steps: @@ -27,6 +27,7 @@ jobs: with: filter: blob:none fetch-depth: 0 + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@v7 - name: Get test environments @@ -58,7 +59,7 @@ jobs: name: ${{ matrix.env.label }} runs-on: ${{ matrix.os }} - + continue-on-error: ${{ matrix.env.allow_failure }} steps: @@ -66,12 +67,15 @@ jobs: with: filter: blob:none fetch-depth: 0 + persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.env.python }} - name: create hatch environment run: uvx hatch env create ${{ matrix.env.name }} + - name: list all all installed package versions + run: uvx hatch run ${{ matrix.env.name }}:uv pip list - name: run tests using hatch env: MPLBACKEND: agg @@ -80,7 +84,7 @@ jobs: run: uvx hatch run ${{ matrix.env.name }}:run-cov -v --color=yes -n auto - name: generate coverage report run: | - # See https://coverage.readthedocs.io/en/latest/config.html#run-patch + # See https://coverage.readthedocs.io/page/config.html#run-patch test -f .coverage || uvx hatch run ${{ matrix.env.name }}:cov-combine uvx hatch run ${{ matrix.env.name }}:cov-report # report visibly uvx hatch run ${{ matrix.env.name }}:coverage xml # create report for upload @@ -104,6 +108,6 @@ jobs: - test 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/.pre-commit-config.yaml b/.pre-commit-config.yaml index 27d8a95..1344b43 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,3 +36,9 @@ repos: # Check that there are no merge conflicts (could be generated by template sync) - id: check-merge-conflict args: [--assume-in-merge] + + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.24.1 + hooks: + - id: zizmor + args: [--no-progress, --fix] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 6c28477..24bfa3c 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,4 +1,4 @@ -# https://docs.readthedocs.io/en/stable/config-file/v2.html +# https://docs.readthedocs.io/page/config-file/v2.html version: 2 build: os: ubuntu-24.04 diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst deleted file mode 100644 index 7b4a0cf..0000000 --- a/docs/_templates/autosummary/class.rst +++ /dev/null @@ -1,61 +0,0 @@ -{{ fullname | escape | underline}} - -.. currentmodule:: {{ module }} - -.. add toctree option to make autodoc generate the pages - -.. autoclass:: {{ objname }} - -{% block attributes %} -{% if attributes %} -Attributes table -~~~~~~~~~~~~~~~~ - -.. autosummary:: -{% for item in attributes %} - ~{{ name }}.{{ item }} -{%- endfor %} -{% endif %} -{% endblock %} - -{% block methods %} -{% if methods %} -Methods table -~~~~~~~~~~~~~ - -.. autosummary:: -{% for item in methods %} - {%- if item != '__init__' %} - ~{{ name }}.{{ item }} - {%- endif -%} -{%- endfor %} -{% endif %} -{% endblock %} - -{% block attributes_documentation %} -{% if attributes %} -Attributes -~~~~~~~~~~ - -{% for item in attributes %} - -.. autoattribute:: {{ [objname, item] | join(".") }} -{%- endfor %} - -{% endif %} -{% endblock %} - -{% block methods_documentation %} -{% if methods %} -Methods -~~~~~~~ - -{% for item in methods %} -{%- if item != '__init__' %} - -.. automethod:: {{ [objname, item] | join(".") }} -{%- endif -%} -{%- endfor %} - -{% endif %} -{% endblock %} diff --git a/docs/conf.py b/docs/conf.py index fd25dc5..b3f2f23 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,7 @@ # 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 +# https://www.sphinx-doc.org/page/usage/configuration.html # -- Path setup -------------------------------------------------------------- import shutil @@ -62,6 +62,7 @@ "sphinx_design", "IPython.sphinxext.ipython_console_highlighting", "sphinxext.opengraph", + "scverse_misc.sphinx_ext", *[p.stem for p in (HERE / "extensions").glob("*.py")], ] @@ -87,6 +88,9 @@ nb_execution_mode = "off" nb_merge_streams = True typehints_defaults = "braces" +always_use_bars_union = ( + True # use `|` instead of `Union` in types even when building with Python ≤3.14 +) # Render @typing.overload'd functions as a single entry (the implementation). # Otherwise sphinx-autodoc-typehints emits every overload signature, which both # drops the short description from the API summary table and clutters each @@ -100,8 +104,6 @@ } intersphinx_mapping = { - # TODO: replace `3.13` with `3` once ReadTheDocs supports building with Python 3.14 - "python": ("https://docs.python.org/3.13", None), "anndata": ("https://anndata.readthedocs.io/en/stable/", None), "cycler": ("https://matplotlib.org/cycler/", None), "matplotlib": ("https://matplotlib.org/stable/", None), @@ -109,7 +111,7 @@ "networkx": ("https://networkx.org/documentation/stable/", None), "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), "python": ("https://docs.python.org/3", None), - "scanpy": ("https://scanpy.readthedocs.io/en/stable/", None), + "scanpy": ("https://scanpy.scverse.org/en/stable/", None), "scipy": ("https://docs.scipy.org/doc/scipy/reference/", None), "squidpy": ("https://squidpy.readthedocs.io/en/stable/", None), "treedata": ("https://treedata.readthedocs.io/en/stable/", None), diff --git a/docs/contributing.md b/docs/contributing.md index ab2538f..1699f06 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -9,7 +9,7 @@ the [scientific Python tutorials][], or the [scanpy developer guide][]. [pyopensci tutorials]: https://www.pyopensci.org/learn.html [scientific Python tutorials]: https://learn.scientific-python.org/development/tutorials/ -[scanpy developer guide]: https://scanpy.readthedocs.io/en/latest/dev/index.html +[scanpy developer guide]: https://scanpy.scverse.org/page/dev/ :::{tip} The *hatch* project manager @@ -45,11 +45,21 @@ hatch test # defined in the table [tool.hatch.envs.hatch-test] in pyproject.tom hatch run docs:build # defined in the table [tool.hatch.envs.docs] ``` -When using an IDE such as VS Code, -you’ll have to point the editor at the paths to the virtual environments manually. -The environment you typically want to use as your main development environment is the `hatch-test` -environment with the latest Python version. +### VS Code +If you are using VS code, install the [hatch-code][] extension. +Additionally, make sure that the `vscode-python-environments` extension is installed (should be by default) +and `"python.useEnvironmentsExtension": true` is activated in your `settings.json`. + +Next, open the "Python Environment Managers" sidebar. +You can do so by opening the command palette (Ctrl+Shift+P) and searching for `Python: Focus on Environment Managers View`. +It will show a collapsible list where you can expand "Hatch" +and activate an environment by clicking on the checkmark next to it. +As the main development environment, we recommend to use `hatch-test` with the latest supported Python version. + +### Other IDEs + +For other IDEs, you’ll have to point the editor at the paths to the virtual environments manually. To get a list of all environments for your projects, run ```bash @@ -87,10 +97,8 @@ Then, obtain the path to the environment using 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`. -Choose `Enter Interpreter Path` and paste the path to the virtual environment from above. +and manually point it to the python binary. -In this future, this may become easier through a hatch vscode extension. :::: @@ -103,7 +111,7 @@ This can have undesired side-effects, such as requiring to install a lower version of a library your project depends on, only because an outdated sphinx plugin pins an older version. -To initalize a virtual environment in the `.venv` directory of your project, simply run +To initialize a virtual environment in the `.venv` directory of your project, simply run ```bash uv sync --all-extras @@ -131,24 +139,26 @@ The `.venv` directory is typically automatically discovered by IDEs such as VS C ::::: [hatch environments]: https://hatch.pypa.io/latest/tutorials/environment/basic-usage/ +[hatch-code]: https://marketplace.visualstudio.com/items?itemName=PyPA.hatch [uv]: https://docs.astral.sh/uv/ ## Code-style -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. +This package uses [pre-commit][]-style hooks to enforce consistent code-styles. +We recommend running them with [prek][], a fast, drop-in replacement for `pre-commit` that reads the same `.pre-commit-config.yaml`. +On every commit, the checks will either automatically fix issues with the code, or raise an error message. -To enable pre-commit locally, simply run +To enable the checks locally, install [prek][] (e.g. with `uv tool install prek`) and run ```bash -pre-commit install +prek install ``` in the root of the repository. -Pre-commit will automatically download all dependencies when it is run for the first time. +prek 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. +If you didn’t run the checks 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 @@ -157,12 +167,13 @@ 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. +While the [pre-commit.ci][] is useful, we strongly encourage installing and running the checks locally first to understand their usage. Finally, most editors have an _autoformat on save_ feature. Consider enabling this option for [ruff][ruff-editors] and [biome][biome-editors]. [pre-commit]: https://pre-commit.com/ +[prek]: https://prek.j178.dev/ [pre-commit.ci]: https://pre-commit.ci/ [ruff-editors]: https://docs.astral.sh/ruff/integrations/ [biome-editors]: https://biomejs.dev/guides/integrate-in-editor/ @@ -175,12 +186,8 @@ 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. -Just point yours to one of the environments returned by - -```bash -hatch env create hatch-test # create test environments for all supported versions -hatch env find hatch-test # list all possible test environment paths -``` +If you set up your virtual environments as described in [installing dev dependencies](#installing-dev-dependencies), +test cases should be automatically discovered by your IDE. Alternatively, you can run all tests from the command line by executing @@ -268,11 +275,11 @@ This project uses [sphinx][] with the following features: 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]: https://www.sphinx-doc.org/ +[myst]: https://myst-parser.readthedocs.io/page/intro.html +[myst-nb]: https://myst-nb.readthedocs.io/ +[numpydoc-napoleon]: https://www.sphinx-doc.org/page/usage/extensions/napoleon.html +[numpydoc]: https://numpydoc.readthedocs.io/page/format.html [sphinx-autodoc-typehints]: https://github.com/tox-dev/sphinx-autodoc-typehints ### Tutorials with myst-nb and jupyter notebooks diff --git a/docs/extensions/typed_returns.py b/docs/extensions/typed_returns.py deleted file mode 100644 index 0fbffef..0000000 --- a/docs/extensions/typed_returns.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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: Iterable[str]) -> Generator[str, None, None]: - for line in lines: - 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: 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 - - -def setup(app: Sphinx): - """Set app.""" - NumpyDocstring._parse_returns_section = _parse_returns_section diff --git a/pyproject.toml b/pyproject.toml index 2aa26d7..f8ea107 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,8 +40,8 @@ dependencies = [ [project.urls] Documentation = "https://pycea.readthedocs.io/" -Homepage = "https://github.com/colganwi/pycea" -Source = "https://github.com/colganwi/pycea" +Homepage = "https://github.com/YosefLab/pycea" +Source = "https://github.com/YosefLab/pycea" [dependency-groups] dev = [ @@ -58,6 +58,7 @@ doc = [ "ipython", "myst-nb>=1.1", "pandas", + "scverse-misc[sphinx]>=0.1.2", # provides scverse_misc.sphinx_ext (0.1.2+ needed for pydocstring-rs 0.4 API) "sphinx>=8.1", "sphinx-autodoc-typehints", "sphinx-book-theme>=1", @@ -95,9 +96,10 @@ dependency-groups = [ "dev", "test" ] [tool.hatch.envs.hatch-test.overrides] # If the matrix variable `deps` is set to "pre", # set the environment variable `UV_PRERELEASE` to "allow". -matrix.deps.env-vars = [ - { key = "UV_PRERELEASE", value = "allow", if = [ "pre" ] }, +envs.hatch-test.overrides.matrix.deps.env-vars = [ + { value = "allow", key = "UV_PRERELEASE", if = [ "pre" ] }, ] +envs.hatch-test.dependency-groups = [ "dev", "test" ] [tool.hatch.build.targets.wheel] packages = [ "src/pycea" ] @@ -107,9 +109,7 @@ exclude = [ "**/.DS_Store", "**/._*" ] line-length = 120 src = [ "src" ] extend-include = [ "*.ipynb" ] - format.docstring-code-format = true - lint.select = [ "B", # flake8-bugbear "BLE", # flake8-blind-except @@ -154,15 +154,16 @@ markers = [ "internet: tests which rely on internet resources (enable with `--internet-tests`)", ] -[tool.coverage.run] -source = [ "pycea" ] -patch = [ "subprocess" ] -omit = [ +[tool.coverage] +run.omit = [ "**/test_*.py", ] +run.patch = [ "subprocess" ] +run.source = [ "pycea" ] [tool.cruft] skip = [ + ".git", "tests", "src/**/__init__.py", "src/**/basic.py",