From 3dc82781cc1f95078708b692dac450109d70efa4 Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Wed, 6 Jul 2022 13:17:29 +0200 Subject: [PATCH] bootstrap template --- .bumpversion.cfg | 8 +++ .codecov.yaml | 17 +++++ .editorconfig | 12 ++++ .flake8 | 44 ++++++++++++ .github/workflows/build.yaml | 23 +++++++ .github/workflows/pre-commit.yaml | 14 ++++ .github/workflows/test.yaml | 62 +++++++++++++++++ .gitignore | 24 +++++++ .pre-commit-config.yaml | 75 ++++++++++++++++++++ .readthedocs.yaml | 15 ++++ CHANGELOG.md | 15 ++++ LICENSE | 29 ++++++++ README.md | 56 +++++++++++++++ docs/Makefile | 20 ++++++ docs/_static/.gitkeep | 0 docs/_templates/.gitkeep | 0 docs/api.md | 37 ++++++++++ docs/changelog.md | 3 + docs/conf.py | 110 ++++++++++++++++++++++++++++++ docs/developer_docs.md | 63 +++++++++++++++++ docs/extensions/.gitkeep | 0 docs/index.md | 15 ++++ docs/make.bat | 35 ++++++++++ docs/notebooks/example.ipynb | 79 +++++++++++++++++++++ docs/references.bib | 17 +++++ docs/references.md | 5 ++ pyproject.toml | 86 +++++++++++++++++++++++ src/infercnvpy/__init__.py | 7 ++ src/infercnvpy/pl/__init__.py | 1 + src/infercnvpy/pl/basic.py | 7 ++ src/infercnvpy/pp/__init__.py | 1 + src/infercnvpy/pp/basic.py | 7 ++ src/infercnvpy/tl/__init__.py | 1 + src/infercnvpy/tl/basic.py | 7 ++ tests/test_basic.py | 12 ++++ 35 files changed, 907 insertions(+) create mode 100644 .bumpversion.cfg create mode 100644 .codecov.yaml create mode 100644 .editorconfig create mode 100644 .flake8 create mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/pre-commit.yaml create mode 100644 .github/workflows/test.yaml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .readthedocs.yaml create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/Makefile create mode 100644 docs/_static/.gitkeep create mode 100644 docs/_templates/.gitkeep create mode 100644 docs/api.md create mode 100644 docs/changelog.md create mode 100644 docs/conf.py create mode 100644 docs/developer_docs.md create mode 100644 docs/extensions/.gitkeep create mode 100644 docs/index.md create mode 100644 docs/make.bat create mode 100644 docs/notebooks/example.ipynb create mode 100644 docs/references.bib create mode 100644 docs/references.md create mode 100644 pyproject.toml create mode 100644 src/infercnvpy/__init__.py create mode 100644 src/infercnvpy/pl/__init__.py create mode 100644 src/infercnvpy/pl/basic.py create mode 100644 src/infercnvpy/pp/__init__.py create mode 100644 src/infercnvpy/pp/basic.py create mode 100644 src/infercnvpy/tl/__init__.py create mode 100644 src/infercnvpy/tl/basic.py create mode 100644 tests/test_basic.py diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..3b4848d --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,8 @@ +[bumpversion] +current_version = 0.0.1 +tag = True +commit = False + +[bumpversion:file:./pyproject.toml] +search = version = "{current_version}" +replace = version = "{new_version}" diff --git a/.codecov.yaml b/.codecov.yaml new file mode 100644 index 0000000..829e56c --- /dev/null +++ b/.codecov.yaml @@ -0,0 +1,17 @@ +# Based on pydata/xarray +codecov: + require_ci_to_pass: no + +coverage: + 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 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2fe0ce0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[Makefile] +indent_style = tab diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..6244ca2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,44 @@ +# 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 + # 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 + # E266 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, i, j, k, l is reasonable indexing notation + E741 + # Missing docstring in public package + D104 + # ... imported but unused + F401 + # Missing docstring in public module + D100 + # Missing docstring in __init__ + D107 + # Do not perform function calls in argument defaults. + B008 + # line break before binary operator + W503 + # Missing docstring in magic method + D105 + # whitespace before ':' + E203 + # format string does contain unindexed parameters + P101 +exclude = .git,__pycache__,build,docs/_build,dist +per-file-ignores = + tests/*: D + */__init__.py: F401 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..0242943 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,23 @@ +name: Check Build + +on: + push: + branches: [main] + pull_request: + branches: [main] + +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 diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 0000000..7b49f62 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,14 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: pre-commit/action@v2.0.0 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..2f0ffd7 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,62 @@ +name: Test + +on: + push: + branches: [main] + pull_request: + branches: [main] + +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] + + 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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bb0bd5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Temp files +.DS_Store +*~ + +# Compiled files +__pycache__/ + +# Distribution / packaging +/build/ +/dist/ +/*.egg-info/ + +# Tests and coverage +/.pytest_cache/ +/.cache/ +/data/ + +# docs +/docs/generated/ +/docs/_build/ + +# IDEs +/.idea/ +/.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4627755 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,75 @@ +fail_fast: false +default_language_version: + python: python3 +default_stages: + - commit + - push +minimum_pre_commit_version: 2.16.0 +repos: + - repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v2.7.1 + hooks: + - id: prettier + - repo: https://github.com/asottile/blacken-docs + rev: v1.12.1 + hooks: + - id: blacken-docs + - repo: https://github.com/pre-commit/mirrors-autopep8 + rev: v1.6.0 + hooks: + - id: autopep8 + args: [-i] + - repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: + - id: isort + - repo: https://github.com/asottile/yesqa + rev: v1.3.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.3.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: v1.4 + hooks: + - id: autoflake + args: + - --in-place + - --remove-all-unused-imports + - --remove-unused-variable + - --ignore-init-module-imports + - repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 + 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: v2.34.0 + hooks: + - id: pyupgrade + args: [--py3-plus, --py38-plus, --keep-runtime-typing] diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..170325e --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,15 @@ +# https://docs.readthedocs.io/en/stable/config-file/v2.html +version: 2 +build: + os: ubuntu-20.04 + tools: + python: "3.10" +sphinx: + configuration: docs/conf.py + fail_on_warning: true +python: + install: + - method: pip + path: . + extra_requirements: + - doc diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e7b7808 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog][], +and this project adheres to [Semantic Versioning][]. + +[keep a changelog]: https://keepachangelog.com/en/1.0.0/ +[semantic versioning]: https://semver.org/spec/v2.0.0.html + +## [Unreleased] + +### Added + +- Basic tool, preprocessing and plotting functions diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e473d76 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, Gregor Sturm +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b2ebb16 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# infercnvpy + +[![Tests][badge-tests]][link-tests] +[![Documentation][badge-docs]][link-docs] + +[badge-tests]: https://img.shields.io/github/workflow/status/icbi-lab/infercnvpy/Test/main +[link-tests]: https://github.com/icbi-lab/infercnvpy/actions/workflows/test.yml +[badge-docs]: https://img.shields.io/readthedocs/infercnvpy + +Infercnv is a scalable python library to infer copy number variation (CNV) events from single cell transcriptomics data. It is heavliy inspired by InferCNV, but plays nicely with scanpy and is much more scalable. + +## Getting started + +Please refer to the [documentation][link-docs]. In particular, the + +- [API documentation][link-api]. + +## Installation + +You need to have Python 3.8 or newer installed on your system. If you don't have +Python installed, we recommend installing [Miniconda](https://docs.conda.io/en/latest/miniconda.html). + +There are several alternative options to install infercnvpy: + + + +1. Install the latest development version: + +```bash +pip install git+https://github.com/icbi-lab/infercnvpy.git@main +``` + +## Release notes + +See the [changelog][changelog]. + +## Contact + +For questions and help requests, you can reach out in the [scverse discourse][scverse-discourse]. +If you found a bug, please use the [issue tracker][issue-tracker]. + +## Citation + +> t.b.a + +[scverse-discourse]: https://discourse.scverse.org/ +[issue-tracker]: https://github.com/icbi-lab/infercnvpy/issues +[changelog]: https://infercnvpy.readthedocs.io/latest/changelog.html +[link-docs]: https://infercnvpy.readthedocs.io +[link-api]: https://infercnvpy.readthedocs.io/latest/api.html diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/_templates/.gitkeep b/docs/_templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..524314e --- /dev/null +++ b/docs/api.md @@ -0,0 +1,37 @@ +# API + +## Preprocessing + +```{eval-rst} +.. module:: infercnvpy.pp +.. currentmodule:: infercnvpy + +.. autosummary:: + :toctree: generated + + pp.basic_preproc +``` + +## Tools + +```{eval-rst} +.. module:: infercnvpy.tl +.. currentmodule:: infercnvpy + +.. autosummary:: + :toctree: generated + + tl.basic_tool +``` + +## Plotting + +```{eval-rst} +.. module:: infercnvpy.pl +.. currentmodule:: infercnvpy + +.. autosummary:: + :toctree: generated + + pl.basic_plot +``` diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..d9e79ba --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,3 @@ +```{include} ../CHANGELOG.md + +``` diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..89a44cc --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,110 @@ +# 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 + +# -- Path setup -------------------------------------------------------------- +import sys +from datetime import datetime +from importlib.metadata import metadata +from pathlib import Path + +HERE = Path(__file__).parent +sys.path.insert(0, str(HERE / "extensions")) + + +# -- Project information ----------------------------------------------------- + +info = metadata("infercnvpy") +project = info["Name"] +author = info["Author"] +copyright = f"{datetime.now():%Y}, {author}." +version = info["Version"] + +# The full version, including alpha/beta/rc tags +release = info["Version"] + +bibtex_bibfiles = ["references.bib"] +templates_path = ["_templates"] +nitpicky = True # Warn about broken links +needs_sphinx = "4.0" + +html_context = { + "display_github": True, # Integrate GitHub + "github_user": "icbi-lab", # Username + "github_repo": project, # Repo name + "github_version": "main", # Version + "conf_py_path": "/docs/", # Path in the checkout to the docs root +} + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. +# They can be extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinxcontrib.bibtex", + "sphinx_autodoc_typehints", + "scanpydoc.definition_list_typed_field", + "nbsphinx", + "sphinx.ext.mathjax", + *[p.stem for p in (HERE / "extensions").glob("*.py")], +] + +autosummary_generate = True +autodoc_member_order = "groupwise" +default_role = "literal" +napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_include_init_with_doc = False +napoleon_use_rtype = True # having a separate entry generally helps readability +napoleon_use_param = True + +intersphinx_mapping = { + "anndata": ("https://anndata.readthedocs.io/en/stable/", None), + "numpy": ("https://numpy.org/doc/stable/", None), +} + +nbsphinx_execute = "never" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**.ipynb_checkpoints"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "furo" +html_static_path = ["_static"] + +pygments_style = "sphinx" + +nitpick_ignore = [ + # If building the documentation fails because of a missing link that is outside your control, + # 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/developer_docs.md b/docs/developer_docs.md new file mode 100644 index 0000000..8813b6f --- /dev/null +++ b/docs/developer_docs.md @@ -0,0 +1,63 @@ +# Developer documentation + +Please refer to the [scanpy developer guide][]. + +[scanpy developer guide]: https://scanpy.readthedocs.io/en/latest/dev/index.html + +## Pre-commit documentation + +[Pre-commit](https://pre-commit.com/) checks are fast programs that +check code for errors, inconsistencies and code styles, before the code +is committed. This is a brief documentation of pre-commits checks +pre-sets in the scverse-template. + +The following pre-commit checks for code style and format. + +- [black](https://black.readthedocs.io/en/stable/): standard code + formatter in Python. +- [autopep8](https://github.com/hhatto/autopep8): code formatter to + conform to [PEP8](https://peps.python.org/pep-0008/) style guide. +- [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 for errors, inconsistencies and typing. + +- [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. + +### Notes on pre-commit checks + +- **flake8**: to ignore errors, 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 [flake8 guide](https://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html) for reference. +- 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 pre-commit + specific config files, such as `.prettierrc.yml` for **prettier** and `.flake8` for **flake8**. diff --git a/docs/extensions/.gitkeep b/docs/extensions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..23a1e19 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,15 @@ +```{include} ../README.md + +``` + +```{toctree} +:hidden: true +:maxdepth: 1 + +api.md +changelog.md +developer_docs.md +references.md + +notebooks/example +``` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..954237b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@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/notebooks/example.ipynb b/docs/notebooks/example.ipynb new file mode 100644 index 0000000..fddecf3 --- /dev/null +++ b/docs/notebooks/example.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from anndata import AnnData\n", + "import infercnvpy" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "adata = AnnData(np.random.normal(size=(20, 10)))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Implement a preprocessing function here." + ] + }, + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "infercnvpy.pp.basic_preproc(adata)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/references.bib b/docs/references.bib new file mode 100644 index 0000000..cd41386 --- /dev/null +++ b/docs/references.bib @@ -0,0 +1,17 @@ +@article{Wolf2018, + author = {Wolf, F. Alexander + and Angerer, Philipp + and Theis, Fabian J.}, + title = {SCANPY: large-scale single-cell gene expression data analysis}, + journal = {Genome Biology}, + year = {2018}, + month = {Feb}, + day = {06}, + volume = {19}, + number = {1}, + pages = {15}, + abstract = {Scanpy is a scalable toolkit for analyzing single-cell gene expression data. It includes methods for preprocessing, visualization, clustering, pseudotime and trajectory inference, differential expression testing, and simulation of gene regulatory networks. Its Python-based implementation efficiently deals with data sets of more than one million cells (https://github.com/theislab/Scanpy). Along with Scanpy, we present AnnData, a generic class for handling annotated data matrices (https://github.com/theislab/anndata).}, + issn = {1474-760X}, + doi = {10.1186/s13059-017-1382-0}, + url = {https://doi.org/10.1186/s13059-017-1382-0} +} diff --git a/docs/references.md b/docs/references.md new file mode 100644 index 0000000..00ad6a6 --- /dev/null +++ b/docs/references.md @@ -0,0 +1,5 @@ +# References + +```{bibliography} +:cited: +``` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4ee98ca --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,86 @@ +[build-system] +build-backend = "hatchling.build" +requires = ["hatchling"] + + +[project] +name = "infercnvpy" +version = "0.0.1" +description = "Infercnv is a scalable python library to infer copy number variation (CNV) events from single cell transcriptomics data. It is heavliy inspired by InferCNV, but plays nicely with scanpy and is much more scalable." +readme = "README.md" +requires-python = ">=3.8" +license = {file = "LICENSE"} +authors = [ + {name = "Gregor Sturm", email = "gregor.sturm@i-med.ac.at"}, +] +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"] + +[project.optional-dependencies] +dev = [ + # CLI for managing the python project + "hatch", +] +doc = [ + "sphinx>=4", + "furo", + "myst-parser", + "sphinxcontrib-bibtex>=1.0.0", + "scanpydoc[typehints]>=0.7.4", + # For notebooks + "nbsphinx", + "ipython>=8.3.0" +] +test = [ + "pytest", + "pytest-cov", +] + +[tool.coverage.run] +source = ["infercnvpy"] +omit = [ + "**/test_*.py", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +xfail_strict = true +addopts = [ + "-Werror", # if 3rd party libs raise DeprecationWarnings, just use filterwarnings below + "--import-mode=importlib", # allow using test files with same name +] +filterwarnings = [ + # "ignore:.*U.*mode is deprecated:DeprecationWarning", +] + +[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" diff --git a/src/infercnvpy/__init__.py b/src/infercnvpy/__init__.py new file mode 100644 index 0000000..20c8f07 --- /dev/null +++ b/src/infercnvpy/__init__.py @@ -0,0 +1,7 @@ +from importlib.metadata import version + +from . import pl, pp, tl + +__all__ = ["pl", "pp", "tl"] + +__version__ = version("infercnvpy") diff --git a/src/infercnvpy/pl/__init__.py b/src/infercnvpy/pl/__init__.py new file mode 100644 index 0000000..a9cd20a --- /dev/null +++ b/src/infercnvpy/pl/__init__.py @@ -0,0 +1 @@ +from .basic import basic_plot diff --git a/src/infercnvpy/pl/basic.py b/src/infercnvpy/pl/basic.py new file mode 100644 index 0000000..71b3627 --- /dev/null +++ b/src/infercnvpy/pl/basic.py @@ -0,0 +1,7 @@ +from anndata import AnnData + + +def basic_plot(adata: AnnData) -> int: + """Generate a basic plot for an AnnData object.""" + print("Import matplotlib and implement a plotting function here.") + return 0 diff --git a/src/infercnvpy/pp/__init__.py b/src/infercnvpy/pp/__init__.py new file mode 100644 index 0000000..5e7e293 --- /dev/null +++ b/src/infercnvpy/pp/__init__.py @@ -0,0 +1 @@ +from .basic import basic_preproc diff --git a/src/infercnvpy/pp/basic.py b/src/infercnvpy/pp/basic.py new file mode 100644 index 0000000..936f119 --- /dev/null +++ b/src/infercnvpy/pp/basic.py @@ -0,0 +1,7 @@ +from anndata import AnnData + + +def basic_preproc(adata: AnnData) -> int: + """Run a basic preprocessing on the AnnData object.""" + print("Implement a preprocessing function here.") + return 0 diff --git a/src/infercnvpy/tl/__init__.py b/src/infercnvpy/tl/__init__.py new file mode 100644 index 0000000..95a32cd --- /dev/null +++ b/src/infercnvpy/tl/__init__.py @@ -0,0 +1 @@ +from .basic import basic_tool diff --git a/src/infercnvpy/tl/basic.py b/src/infercnvpy/tl/basic.py new file mode 100644 index 0000000..4e3387c --- /dev/null +++ b/src/infercnvpy/tl/basic.py @@ -0,0 +1,7 @@ +from anndata import AnnData + + +def basic_tool(adata: AnnData) -> int: + """Run a tool on the AnnData object.""" + print("Implement a tool to run on the AnnData object.") + return 0 diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100644 index 0000000..47aa08f --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,12 @@ +import pytest + +import infercnvpy + + +def test_package_has_version(): + infercnvpy.__version__ + + +@pytest.mark.skip(reason="This decorator should be removed when test passes.") +def test_example(): + assert 1 == 0 # This test is designed to fail.