diff --git a/.bumpversion.cfg b/.bumpversion.cfg
deleted file mode 100644
index fdba9e4..0000000
--- 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 829e56c..d0c0e29 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 34b6f48..367a8e0 100644
--- a/.cruft.json
+++ b/.cruft.json
@@ -1,23 +1,31 @@
{
- "template": "https://github.com/scverse/cookiecutter-scverse",
- "commit": "7cc5403b05e299d7a4bb169c2bd8c27a2a7676f3",
- "context": {
- "cookiecutter": {
- "project_name": "infercnvpy",
- "package_name": "infercnvpy",
- "project_description": "Infer copy number variation (CNV) from scRNA-seq data. Plays nicely with Scanpy. ",
- "author_full_name": "Gregor Sturm",
- "author_email": "mail@gregor-sturm.de",
- "github_user": "grst",
- "project_repo": "https://github.com/icbi-lab/infercnvpy",
- "license": "BSD 3-Clause License",
- "_copy_without_render": [
- ".github/workflows/**.yaml",
- "docs/_templates/autosummary/**.rst"
- ],
- "_template": "https://github.com/scverse/cookiecutter-scverse"
- }
- },
- "directory": null,
- "checkout": "v0.1.3"
+ "template": "https://github.com/scverse/cookiecutter-scverse",
+ "commit": "497afeaf179fe5c1144c4503046efa494586cc3d",
+ "context": {
+ "cookiecutter": {
+ "project_name": "infercnvpy",
+ "package_name": "infercnvpy",
+ "project_description": "Infer copy number variation (CNV) from scRNA-seq data. Plays nicely with Scanpy. ",
+ "author_full_name": "Gregor Sturm",
+ "author_email": "mail@gregor-sturm.de",
+ "github_user": "grst",
+ "github_repo": "infercnvpy",
+ "license": "BSD 3-Clause License",
+ "ide_integration": true,
+ "_copy_without_render": [
+ ".github/workflows/build.yaml",
+ ".github/workflows/test.yaml",
+ "docs/_templates/autosummary/**.rst"
+ ],
+ "_render_devdocs": false,
+ "_jinja2_env_vars": {
+ "lstrip_blocks": true,
+ "trim_blocks": true
+ },
+ "_template": "https://github.com/scverse/cookiecutter-scverse",
+ "_commit": "497afeaf179fe5c1144c4503046efa494586cc3d"
+ }
+ },
+ "directory": null,
+ "checkout": "test4"
}
diff --git a/.editorconfig b/.editorconfig
index 2fe0ce0..66678e3 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/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 9dfd4ac..3ca1ccb 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 5cad625..5b62547 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 26123f3..473785f 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 infercnvpy
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 0242943..e822177 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -1,23 +1,32 @@
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:
+ shell: bash -e {0} # -e to fail on error
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 0000000..885c3b0
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,33 @@
+name: Release
+
+on:
+ release:
+ types: [published]
+
+defaults:
+ run:
+ shell: bash -e {0} # -e to fail on error
+
+# 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/infercnvpy
+ 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/sync.yaml b/.github/workflows/sync.yaml
deleted file mode 100644
index 5219499..0000000
--- a/.github/workflows/sync.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-name: Sync Template
-
-on:
- workflow_dispatch:
- schedule:
- - cron: "0 2 * * *" # every night at 2:00 UTC
-
-jobs:
- sync:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Set up Python 3.10
- uses: actions/setup-python@v4
- with:
- python-version: "3.10"
- - name: Install dependencies
- # for now, pin cookiecutter version, due to https://github.com/cruft/cruft/issues/166
- run: python -m pip install --upgrade cruft "cookiecutter<2" pre-commit toml
- - name: Find Latest Tag
- uses: oprypin/find-latest-tag@v1.1.0
- id: get-latest-tag
- with:
- repository: scverse/cookiecutter-scverse
- releases-only: false
- sort-tags: true
- regex: '^v\d+\.\d+\.\d+$' # vX.X.X
- - name: Sync
- run: |
- cruft update --checkout ${{ steps.get-latest-tag.outputs.tag }} --skip-apply-ask --project-dir .
- - name: Create Pull Request
- uses: peter-evans/create-pull-request@v4
- with:
- commit-message: Automated template update from cookiecutter-scverse
- branch: template-update
- title: Automated template update from cookiecutter-scverse
- body: |
- A new version of the [scverse cookiecutter template](https://github.com/scverse/cookiecutter-scverse/releases)
- got released. This PR adds all new changes to your repository and helps to to stay in sync with
- the latest best-practice template maintained by the scverse team.
-
- **If a merge conflict arised, a `.rej` file with the rejected patch is generated. You'll need to
- manually merge these changes.**
-
- For more information about the template sync, please refer to the
- [template documentation](https://cookiecutter-scverse-instance.readthedocs.io/en/latest/developer_docs.html#automated-template-sync).
diff --git a/.github/workflows/test.yaml.rej b/.github/workflows/test.yaml.rej
new file mode 100644
index 0000000..a1d93b3
--- /dev/null
+++ b/.github/workflows/test.yaml.rej
@@ -0,0 +1,115 @@
+diff a/.github/workflows/test.yaml b/.github/workflows/test.yaml (rejected hunks)
+@@ -1,62 +1,58 @@
+ 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:
++ shell: bash -e {0} # -e to fail on error
+
+ 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 7bb0bd5..31e10b3 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.rej b/.pre-commit-config.yaml.rej
new file mode 100644
index 0000000..88a5d7d
--- /dev/null
+++ b/.pre-commit-config.yaml.rej
@@ -0,0 +1,123 @@
+diff a/.pre-commit-config.yaml b/.pre-commit-config.yaml (rejected hunks)
+@@ -1,79 +1,47 @@
+ fail_fast: false
+ default_language_version:
+- python: python3
++ python: python3
+ default_stages:
+- - pre-commit
+- - pre-push
++ - pre-commit
++ - pre-push
+ minimum_pre_commit_version: 2.16.0
+ repos:
+- - repo: https://github.com/psf/black
+- rev: 25.1.0
+- hooks:
+- - id: black
+- - repo: https://github.com/pre-commit/mirrors-prettier
+- rev: v4.0.0-alpha.8
+- hooks:
+- - id: prettier
+- - repo: https://github.com/asottile/blacken-docs
+- rev: 1.19.1
+- hooks:
+- - id: blacken-docs
+- - repo: https://github.com/PyCQA/isort
+- rev: 6.0.1
+- hooks:
+- - id: isort
+- - repo: https://github.com/asottile/yesqa
+- rev: v1.5.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: 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
+- - repo: https://github.com/myint/autoflake
+- rev: v2.3.1
+- hooks:
+- - id: autoflake
+- args:
+- - --in-place
+- - --remove-all-unused-imports
+- - --remove-unused-variable
+- - --ignore-init-module-imports
+- - repo: https://github.com/PyCQA/flake8
+- rev: 7.2.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.19.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 9e5d5fa..69897c3 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 0000000..caaeb4f
--- /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 0000000..36d1874
--- /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/CHANGELOG.md.rej b/CHANGELOG.md.rej
new file mode 100644
index 0000000..512112b
--- /dev/null
+++ b/CHANGELOG.md.rej
@@ -0,0 +1,7 @@
+diff a/CHANGELOG.md b/CHANGELOG.md (rejected hunks)
+@@ -12,4 +12,4 @@ and this project adheres to [Semantic Versioning][].
+
+ ### Added
+
+-- Basic tool, preprocessing and plotting functions
++- Basic tool, preprocessing and plotting functions
diff --git a/README.md.rej b/README.md.rej
new file mode 100644
index 0000000..9b39424
--- /dev/null
+++ b/README.md.rej
@@ -0,0 +1,69 @@
+diff a/README.md b/README.md (rejected hunks)
+@@ -1,29 +1,27 @@
+ # infercnvpy
+
+-[![Tests][badge-tests]][link-tests]
+-[![Documentation][badge-docs]][link-docs]
++[![Tests][badge-tests]][tests]
++[![Documentation][badge-docs]][documentation]
+
+ [badge-tests]: https://img.shields.io/github/actions/workflow/status/grst/infercnvpy/test.yaml?branch=main
+-[link-tests]: https://github.com/icbi-lab/infercnvpy/actions/workflows/test.yml
+ [badge-docs]: https://img.shields.io/readthedocs/infercnvpy
+
+ Infer copy number variation (CNV) from scRNA-seq data. Plays nicely with Scanpy.
+
+ ## Getting started
+
+-Please refer to the [documentation][link-docs]. In particular, the
+-
+-- [API documentation][link-api].
++Please refer to the [documentation][],
++in particular, the [API documentation][].
+
+ ## Installation
+
+-You need to have Python 3.8 or newer installed on your system. If you don't have
+-Python installed, we recommend installing [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge).
++You need to have Python 3.10 or newer installed on your system.
++If you don't have Python installed, we recommend installing [uv][].
+
+ There are several alternative options to install infercnvpy:
+
+
-
-[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 9447813..0fbffef 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/index.md.rej b/docs/index.md.rej
new file mode 100644
index 0000000..14a8d31
--- /dev/null
+++ b/docs/index.md.rej
@@ -0,0 +1,9 @@
+diff a/docs/index.md b/docs/index.md (rejected hunks)
+@@ -8,7 +8,6 @@
+
+ api.md
+ changelog.md
+-template_usage.md
+ contributing.md
+ references.md
+
diff --git a/docs/make.bat b/docs/make.bat
deleted file mode 100644
index 954237b..0000000
--- 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 25c5601..0000000
--- 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 infercnvpy
-```
-
-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: `infercnvpy`.
-:::
-
-Now that your new project repository has been created on github at `https://github.com/grst/infercnvpy` 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/infercnvpy`. 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/grst/infercnvpy.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/grst/infercnvpy`. 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/grst/infercnvpy`. 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 = "infercnvpy"
--version = "0.3.1dev"
-+dynamic = ["version"]
-
-@@ -60,6 +60,9 @@
-+[tool.hatch.version]
-+source = "vcs"
-+
- [tool.coverage.run]
- source = ["infercnvpy"]
- 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.rej b/pyproject.toml.rej
new file mode 100644
index 0000000..a13e303
--- /dev/null
+++ b/pyproject.toml.rej
@@ -0,0 +1,213 @@
+diff a/pyproject.toml b/pyproject.toml (rejected hunks)
+@@ -1,104 +1,135 @@
+ [build-system]
+ build-backend = "hatchling.build"
+-requires = ["hatchling"]
+-
++requires = [ "hatchling" ]
+
+ [project]
+ name = "infercnvpy"
+ version = "0.0.1"
+ description = "Infer copy number variation (CNV) from scRNA-seq data. Plays nicely with Scanpy. "
+ readme = "README.md"
+-requires-python = ">=3.8"
+-license = {file = "LICENSE"}
++license = { file = "LICENSE" }
++maintainers = [
++ { name = "Gregor Sturm", email = "mail@gregor-sturm.de" },
++]
+ authors = [
+- {name = "Gregor Sturm"},
++ { name = "Gregor Sturm" },
+ ]
+-maintainers = [
+- {name = "Gregor Sturm", email = "mail@gregor-sturm.de"},
++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://infercnvpy.readthedocs.io/"
+-urls.Source = "https://github.com/icbi-lab/infercnvpy"
+-urls.Home-page = "https://github.com/icbi-lab/infercnvpy"
+ 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://infercnvpy.readthedocs.io/"
++urls.Homepage = "https://github.com/grst/infercnvpy"
++urls.Source = "https://github.com/grst/infercnvpy"
+
+-[tool.coverage.run]
+-source = ["infercnvpy"]
+-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 = [ "infercnvpy" ]
++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",
+ ]