diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d4a2c44 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +charset = utf-8 +end_of_line = lf + +[*.bat] +indent_style = tab +end_of_line = crlf + +[LICENSE] +insert_final_newline = false + +[Makefile] +indent_style = tab diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..122db8d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,39 @@ +name: Release + +on: + push: + tags: + - "*.*.*" + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + # will use ref/SHA that triggered it + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: "3.9" + + - name: Install poetry + uses: abatilo/actions-poetry@v2.0.0 + with: + poetry-version: 1.4.2 + + - name: Build project for distribution + run: poetry build + + - name: Check Version + id: check-version + run: | + [[ "$(poetry version --short)" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] \ + || echo ::set-output name=prerelease::true + + - name: Publish to PyPI + env: + POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }} + run: poetry publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..18c666d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: regvelo + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + pip install pytest-cov + pip install .[dev] + - name: Test with pytest + run: | + pytest --cov-report=xml --cov=velovi + - name: After success + run: | + bash <(curl -s https://codecov.io/bash) + pip list diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2f7038 --- /dev/null +++ b/.gitignore @@ -0,0 +1,137 @@ +# DS_Store +.DS_Store + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# vscode +.vscode/settings.json +docs/api/reference/ +*.h5ad diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c9c14d3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +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: "23.1.0" + hooks: + - id: black + - repo: https://github.com/asottile/blacken-docs + rev: 1.13.0 + hooks: + - id: blacken-docs + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.0.0-alpha.6 + hooks: + - id: prettier + # Newer versions of node don't work on systems that have an older version of GLIBC + # (in particular Ubuntu 18.04 and Centos 7) + # EOL of Centos 7 is in 2024-06, we can probably get rid of this then. + # See https://github.com/scverse/cookiecutter-scverse/issues/143 and + # https://github.com/jupyterlab/jupyterlab/issues/12675 + language_version: "17.9.1" + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.254 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: detect-private-key + - id: check-ast + - id: end-of-file-fixer + - id: mixed-line-ending + args: [--fix=lf] + - id: trailing-whitespace + - id: check-case-conflict + - repo: 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/docs/conf.py b/docs/conf.py index fff083b..733d1c2 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,7 +21,7 @@ author = info["Weixu Wang"] copyright = f"{datetime.now():%Y}, {author}." version = info["Version"] -repository_url = "https://github.com/theislab/RegVelo_repo" +repository_url = "https://github.com/theislab/RegVelo" # The full version, including alpha/beta/rc tags release = info["Version"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1a717ff --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,161 @@ +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +authors = ["Weixu Wang "] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Natural Language :: English", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Topic :: Scientific/Engineering :: Bio-Informatics", +] +description = "Estimation of RNA velocity with variational inference." +documentation = "https://scvi-tools.org" +homepage = "https://github.com/theislab/RegVelo/" +license = "BSD-3-Clause" +name = "regvelo" +packages = [ + {include = "regvelo"}, +] +readme = "README.md" +version = "0.1.0" + +[tool.poetry.dependencies] +anndata = ">=0.7.5" +black = {version = ">=20.8b1", optional = true} +codecov = {version = ">=2.0.8", optional = true} +ruff = {version = "*", optional = true} +importlib-metadata = {version = "^1.0", python = "<3.8"} +ipython = {version = ">=7.1.1", optional = true} +jupyter = {version = ">=1.0", optional = true} +pre-commit = {version = ">=2.7.1", optional = true} +sphinx-book-theme = {version = ">=1.0.0", optional = true} +myst-nb = {version = "*", optional = true} +sphinx-copybutton = {version = "*", optional = true} +sphinxcontrib-bibtex = {version = "*", optional = true} +ipykernel = {version = "*", optional = true} +pytest = {version = ">=4.4", optional = true} +pytest-cov = {version = "*", optional = true} +python = ">=3.9,<4.0" +python-igraph = {version = "*", optional = true} +scanpy = {version = ">=1.6", optional = true} +scanpydoc = {version = ">=0.5", optional = true} +scvelo = ">=0.2.5" +scvi-tools = ">=1.0.0" +scikit-learn = ">=0.21.2" +torchode = ">=0.1.6" +cellrank = ">=2.0.0" +sphinx = {version = ">=4.1", optional = true} +sphinx-autodoc-typehints = {version = "*", optional = true} + + +[tool.poetry.extras] +dev = ["black", "pytest", "pytest-cov", "ruff", "codecov", "scanpy", "loompy", "jupyter", "pre-commit"] +docs = [ + "sphinx", + "scanpydoc", + "ipython", + "myst-nb", + "sphinx-book-theme", + "sphinx-copybutton", + "sphinxcontrib-bibtex", + "ipykernel", + "ipython", +] +tutorials = ["scanpy"] + +[tool.poetry.dev-dependencies] + + +[tool.coverage.run] +source = ["regvelo"] +omit = [ + "**/test_*.py", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +xfail_strict = true + + +[tool.black] +include = '\.pyi?$' +exclude = ''' +( + /( + \.eggs + | \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + )/ +) +''' + +[tool.ruff] +src = ["."] +line-length = 119 +target-version = "py38" +select = [ + "F", # Errors detected by Pyflakes + "E", # Error detected by Pycodestyle + "W", # Warning detected by Pycodestyle + "I", # isort + "D", # pydocstyle + "B", # flake8-bugbear + "TID", # flake8-tidy-imports + "C4", # flake8-comprehensions + "BLE", # flake8-blind-except + "UP", # pyupgrade + "RUF100", # Report unused noqa directives +] +ignore = [ + # line too long -> we accept long comment lines; black gets rid of long code lines + "E501", + # Do not assign a lambda expression, use a def -> lambda expression assignments are convenient + "E731", + # allow I, O, l as variable names -> I is the identity matrix + "E741", + # Missing docstring in public package + "D104", + # Missing docstring in public module + "D100", + # Missing docstring in __init__ + "D107", + # Errors from function calls in argument defaults. These are fine when the result is immutable. + "B008", + # __magic__ methods are are often self-explanatory, allow missing docstrings + "D105", + # first line should end with a period [Bug: doesn't work with single-line docstrings] + "D400", + # First line should be in imperative mood; try rephrasing + "D401", + ## Disable one in each pair of mutually incompatible rules + # We don’t want a blank line before a class docstring + "D203", + # We want docstrings to start immediately after the opening triple quote + "D213", + # Missing argument description in the docstring TODO: enable + "D417", +] + +[tool.ruff.per-file-ignores] +"docs/*" = ["I", "BLE001"] +"tests/*" = ["D"] +"*/__init__.py" = ["F401"] +"regvelo/__init__.py" = ["I"] + +[tool.jupytext] +formats = "ipynb,md" diff --git a/regvelovi/__init__.py b/regvelo/__init__.py similarity index 94% rename from regvelovi/__init__.py rename to regvelo/__init__.py index dd0a5fe..d33e1f1 100644 --- a/regvelovi/__init__.py +++ b/regvelo/__init__.py @@ -18,7 +18,7 @@ except ModuleNotFoundError: import importlib_metadata -package_name = "regvelovi" +package_name = "regvelo" __version__ = importlib_metadata.version(package_name) logger = logging.getLogger(__name__) @@ -30,7 +30,7 @@ if console.is_jupyter is True: console.is_jupyter = False ch = RichHandler(show_path=False, console=console, show_time=False) -formatter = logging.Formatter("regvelovi: %(message)s") +formatter = logging.Formatter("regvelo: %(message)s") ch.setFormatter(formatter) logger.addHandler(ch) diff --git a/regvelovi/_constants.py b/regvelo/_constants.py similarity index 100% rename from regvelovi/_constants.py rename to regvelo/_constants.py diff --git a/regvelovi/_model.py b/regvelo/_model.py similarity index 100% rename from regvelovi/_model.py rename to regvelo/_model.py diff --git a/regvelovi/_module.py b/regvelo/_module.py similarity index 100% rename from regvelovi/_module.py rename to regvelo/_module.py diff --git a/regvelovi/_perturbation.py b/regvelo/_perturbation.py similarity index 100% rename from regvelovi/_perturbation.py rename to regvelo/_perturbation.py diff --git a/regvelovi/_utils.py b/regvelo/_utils.py similarity index 100% rename from regvelovi/_utils.py rename to regvelo/_utils.py diff --git a/regvelovi/datasets/__init__.py b/regvelo/datasets/__init__.py similarity index 100% rename from regvelovi/datasets/__init__.py rename to regvelo/datasets/__init__.py diff --git a/regvelovi/datasets/_datasets.py b/regvelo/datasets/_datasets.py similarity index 100% rename from regvelovi/datasets/_datasets.py rename to regvelo/datasets/_datasets.py diff --git a/tests/test_regvelo.py b/tests/test_regvelo.py index 4c8a738..5c7cb5b 100644 --- a/tests/test_regvelo.py +++ b/tests/test_regvelo.py @@ -3,7 +3,7 @@ import numpy as np import pandas as pd from scvi.data import synthetic_iid -from regvelovi import REGVELOVI,TFscreening +from regvelovi import REGVELOVI import torch def test_regvelo():