From abbf7913ce84fbc7fc981a990cbd52a9a315458d Mon Sep 17 00:00:00 2001 From: Kori Kuzma Date: Tue, 25 Jun 2024 12:14:01 -0400 Subject: [PATCH] chore: add boilerplate files (#3) close #1 --- .github/ISSUE_TEMPLATE/bug-report.yaml | 85 ++++++++++++ .github/ISSUE_TEMPLATE/feature-request.yaml | 60 ++++++++ .github/workflows/python-cqa.yaml | 43 ++++++ .github/workflows/release.yaml | 63 +++++++++ .gitignore | 60 ++++++++ .pre-commit-config.yaml | 17 +++ Makefile | 103 ++++++++++++++ README.md | 84 +++++++++++ pyproject.toml | 146 ++++++++++++++++++++ src/ga4gh/cat_vrs/__init__.py | 1 + 10 files changed, 662 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yaml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yaml create mode 100644 .github/workflows/python-cqa.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 Makefile create mode 100644 pyproject.toml create mode 100644 src/ga4gh/cat_vrs/__init__.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml new file mode 100644 index 0000000..5b3f7c8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -0,0 +1,85 @@ +name: Bug Report +description: Report a bug. +labels: ["bug"] +body: + - type: textarea + attributes: + label: Describe the bug + description: Provide a clear and concise description of what the bug is. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce + description: Provide detailed steps to replicate the bug. + placeholder: | + 1. In this environment... + 2. With this config... + 3. Run '...' + 4. See error... + validations: + required: true + - type: textarea + attributes: + label: Expected behavior + description: What did you expect to happen? + validations: + required: true + - type: textarea + attributes: + label: Current behavior + description: | + What actually happened? + + Include full errors, stack traces, and/or relevant logs. + validations: + required: true + - type: textarea + attributes: + label: Possible reason(s) + description: Provide any insights into what might be causing the issue. + validations: + required: false + - type: textarea + attributes: + label: Suggested fix + description: Provide any suggestions on how to resolve the bug. + validations: + required: false + - type: textarea + attributes: + label: Branch, commit, and/or version + description: Provide the branch, commit, and/or version you're using. + placeholder: | + branch: issue-1 + commit: abc123d + validations: + required: true + - type: textarea + attributes: + label: Screenshots + description: If applicable, add screenshots with descriptions to help explain your problem. + validations: + required: false + - type: textarea + attributes: + label: Environment details + description: Provide environment details (OS name and version, etc). + validations: + required: true + - type: textarea + attributes: + label: Additional details + description: Provide any other additional details about the problem. + validations: + required: false + - type: dropdown + attributes: + label: Contribution + description: Can you contribute to the development of this feature? + options: + - "Yes, I can create a PR for this fix." + - "Yes, but I can only provide ideas and feedback." + - "No, I cannot contribute." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml new file mode 100644 index 0000000..2e1ae64 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yaml @@ -0,0 +1,60 @@ +name: Feature Request +description: Suggest an idea for this project. +labels: ["enhancement"] +body: + - type: textarea + attributes: + label: Feature description + description: Provide a clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + attributes: + label: Use case + description: | + Why do you need this feature? For example: "I'm always frustrated when..." + validations: + required: true + - type: textarea + attributes: + label: Proposed solution + description: Provide proposed solution. + validations: + required: false + - type: textarea + attributes: + label: Alternatives considered + description: Describe any alternative solutions you've considered. + validations: + required: false + - type: textarea + attributes: + label: Implementation details + description: Provide any technical details on how the feature might be implemented. + validations: + required: false + - type: textarea + attributes: + label: Potential Impact + description: | + Discuss any potential impacts of this feature on existing functionality or performance, if known. + Will this feature cause breaking changes? + What challenges might arise? + validations: + required: false + - type: textarea + attributes: + label: Additional context + description: Provide any other context or screenshots about the feature. + validations: + required: false + - type: dropdown + attributes: + label: Contribution + description: Can you contribute to the development of this feature? + options: + - "Yes, I can create a PR for this feature." + - "Yes, but I can only provide ideas and feedback." + - "No, I cannot contribute." + validations: + required: false diff --git a/.github/workflows/python-cqa.yaml b/.github/workflows/python-cqa.yaml new file mode 100644 index 0000000..9df1355 --- /dev/null +++ b/.github/workflows/python-cqa.yaml @@ -0,0 +1,43 @@ +name: Python CQA + +on: [push, pull_request] + +jobs: + test: + name: test py${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python3 -m pip install ".[tests]" + + - name: Run tests + run: python3 -m pytest + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.12 + + - name: Install dependencies + run: python3 -m pip install ".[dev]" + + - name: Check style + run: python3 -m ruff check && python3 -m ruff format --check diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..1d9aa38 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,63 @@ +name: Upload tagged commit to PyPI +on: + push: + tags: + - "*.*.**" +jobs: + get_branch: + runs-on: ubuntu-latest + outputs: + branch_name: ${{ steps.get_branch_name.outputs.name }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get branch name + id: get_branch_name + run: | + raw=$(git branch -r --contains ${{ github.ref }}) + branch=$(echo "$raw" | grep "origin/main" | sed "s|origin/||" | xargs) + echo "name=$branch" >> "$GITHUB_OUTPUT" + build: + name: Build distribution + runs-on: ubuntu-latest + needs: get_branch + if: needs.get_branch.outputs.branch_name == 'main' + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@v3 + with: + name: python-package-distributions + path: dist/ + publish-to-pypi: + name: >- + Publish Python distribution to PyPI + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ga4gh-cat-vrs + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + steps: + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c668b65 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..56efe9d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-added-large-files + - id: detect-private-key + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-merge-conflict + - id: detect-aws-credentials + args: [--allow-missing-credentials] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.9 # ruff version + hooks: + - id: ruff-format + - id: ruff + args: [ --fix, --exit-non-zero-on-fix ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4aeac88 --- /dev/null +++ b/Makefile @@ -0,0 +1,103 @@ +# Makefile for Python project + +.DELETE_ON_ERROR: +.PHONY: FORCE +.PRECIOUS: +.SUFFIXES: + +SHELL:=/bin/bash -e -o pipefail +SELF:=$(firstword $(MAKEFILE_LIST)) + +UNAME = $(shell uname) +ifeq (${UNAME},Darwin) + _XRM_R:= +else + _XRM_R:=r +endif +XRM=xargs -0${_XRM_R} rm + +PKG=ga4gh.cat_vrs +PKGD=$(subst .,/,${PKG}) +PYV:=3.12 +VEDIR=venv/${PYV} + + +############################################################################ +#= BASIC USAGE +default: help + +#=> help -- display this help message +help: + @sbin/makefile-extract-documentation "${SELF}" + + +############################################################################ +#= SETUP, INSTALLATION, PACKAGING + +#=> venv: make a Python 3 virtual environment +.PHONY: venv/% +venv/%: + python$* -m venv $@; \ + source $@/bin/activate; \ + python -m ensurepip --upgrade; \ + pip install --upgrade pip setuptools + +#=> develop: install package in develop mode +.PHONY: develop setup +develop setup: + pip install -e .[dev,tests] + +#=> devready: create venv, install prerequisites, install pkg in develop mode +.PHONY: devready +devready: + make ${VEDIR} && source ${VEDIR}/bin/activate && make develop + @echo '#################################################################################' + @echo '### Do not forget to `source ${VEDIR}/bin/activate` to use this environment ###' + @echo '#################################################################################' + +############################################################################ +#= TESTING +# see test configuration in pyproject.toml + +#=> test: execute tests +.PHONY: test +test: + pytest + +#=> doctest: execute documentation tests (requires extra data) +.PHONY: doctest +doctest: + pytest --doctest-modules + +############################################################################ +#= UTILITY TARGETS + +#=> format: reformat code with ruff +.PHONY: format +format: + ruff format + +#=> lint: static analysis check +.PHONY: lint +lint: + ruff check --fix --exit-zero + +############################################################################ +#= CLEANUP + +#=> clean: remove temporary and backup files +.PHONY: clean +clean: + find . \( -name \*~ -o -name \*.bak \) -print0 | ${XRM} + +#=> cleaner: remove files and directories that are easily rebuilt +.PHONY: cleaner +cleaner: clean + rm -fr .cache *.egg-info .pytest_cache build dist doc/_build htmlcov + find . \( -name \*.pyc -o -name \*.orig -o -name \*.rej \) -print0 | ${XRM} + find . -name __pycache__ -print0 | ${XRM} -fr + +#=> cleanest: remove files and directories that require more time/network fetches to rebuild +.PHONY: cleanest +cleanest: cleaner + rm -fr .eggs venv diff --git a/README.md b/README.md index b2af5b2..9016243 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,86 @@ # cat-vrs-python + GA4GH Categorical Variation Representation Python Implementation + +## Information + +[![license](https://img.shields.io/badge/license-Apache-green)](https://github.com/ga4gh/cat-vrs-python/blob/main/LICENSE) + +## Releases + +[![gitHub tag](https://img.shields.io/github/v/tag/ga4gh/cat-vrs-python.svg)](https://github.com/ga4gh/cat-vrs-python/releases) [![pypi](https://img.shields.io/pypi/v/ga4gh.cat_vrs.svg)](https://pypi.org/project/ga4gh.cat_vrs/) + +## Development + +[![action status](https://github.com/ga4gh/cat-vrs-python/actions/workflows/python-cqa.yaml/badge.svg)](https://github.com/ga4gh/cat-vrs-python/actions/workflows/python-cqa.yaml) [![issues](https://img.shields.io/github/issues-raw/ga4gh/cat-vrs-python.svg)](https://github.com/ga4gh/cat-vrs-python/issues) +[![GitHub Open Pull Requests](https://img.shields.io/github/issues-pr/ga4gh/cat-vrs-python.svg)](https://github.com/ga4gh/cat-vrs-python/pull/) [![GitHub license](https://img.shields.io/github/contributors/ga4gh/cat-vrs-python.svg)](https://github.com/ga4gh/cat-vrs-python/graphs/contributors/) [![GitHub stars](https://img.shields.io/github/stars/ga4gh/cat-vrs-python.svg?style=social&label=Stars)](https://github.com/ga4gh/cat-vrs-python/stargazers) [![GitHub forks](https://img.shields.io/github/forks/ga4gh/cat-vrs-python.svg?style=social&label=Forks)](https://github.com/ga4gh/cat-vrs-python/network) + +## Features + +- Pydantic implementation of Cat-VRS models + +## Known Issues + +**You are encouraged to** [browse issues](https://github.com/ga4gh/cat-vrs-python/issues). +All known issues are listed there. Please report any issues you find. + +## Developers + +This section is intended for developers who contribute to Cat-VRS-Python. + +### Installing for development + +#### Prerequisites + +- Python >= 3.10 + - _Note: Python 3.12 is required for developers contributing to Cat-VRS-Python_ + +Fork the repo at . + +Install development dependencies and `pre-commit`: + +```shell +git clone --recurse-submodules git@github.com:YOUR_GITHUB_ID/cat-vrs-python.git +cd cat-vrs-python +make devready +source venv/3.12/bin/activate +pre-commit install +``` + +Check style with `ruff`: + +```shell +make format; make lint +``` + +#### Submodules + +cat-vrs-python embeds cat-vrs as a submodule, only for testing purposes. When checking +out cat-vrs-python and switching branches, it is important to make sure that the +submodule tracks cat-vrs-python correctly. The recommended way to do this is +`git config --global submodule.recurse true`. **If you don't set submodule.recurse, +developers and reviewers must be extremely careful to not accidentally upgrade or +downgrade schemas with respect to cat-vrs-python.** + +If you already cloned the repo, but forgot to include `--recurse-submodules` you can run: + +```shell +git submodule update --init --recursive +``` + +### Testing + +To run tests: + +```shell +make test +``` + +## Security Note (from the GA4GH Security Team) + +A stand-alone security review has been performed on the specification itself. +This implementation is offered as-is, and without any security guarantees. It +will need an independent security review before it can be considered ready for +use in security-critical applications. If you integrate this code into your +application it is AT YOUR OWN RISK AND RESPONSIBILITY to arrange for a security +audit. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e23228b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,146 @@ +[project] +name = "ga4gh.cat_vrs" +authors = [ + {name = "Larry Babb", email = "lbabb@broadinstitute.org"}, + {name = "Alex Wagner", email = "alex.wagner@nationwidechildrens.org"}, + {name = "Daniel Puthawala", email = "daniel.puthawala@nationwidechildrens.org"}, +] +readme = "README.md" +description = "GA4GH Categorical Variation Representation (Cat-VRS) reference implementation" +license = {file = "LICENSE"} +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Healthcare Industry", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Bio-Informatics", + "Topic :: Scientific/Engineering :: Medical Science Apps.", +] +keywords = [ + "bioinformatics", + "ga4gh", + "genomics", + "variation" +] +requires-python = ">=3.10" +dynamic = ["version"] +dependencies = [] + +[project.optional-dependencies] +dev = [ + "pre-commit", + "ruff==0.4.9", +] +tests = [ + "pytest", + "pytest-cov", +] + +[project.urls] +Homepage = "https://github.com/ga4gh/cat-vrs-python" +Documentation = "https://github.com/ga4gh/cat-vrs-python" +Changelog = "https://github.com/ga4gh/cat-vrs-python/releases" +Source = "https://github.com/ga4gh/cat-vrs-python" +"Bug Tracker" = "https://github.com/ga4gh/cat-vrs-python/issues" + +[build-system] +requires = ["setuptools>=65.3", "setuptools_scm>=8"] +build-backend = "setuptools.build_meta" + +[tool.ruff] +exclude = [ + "submodules" +] + +[tool.ruff.lint] +select = [ + "F", # https://docs.astral.sh/ruff/rules/#pyflakes-f + "E", "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w + "I", # https://docs.astral.sh/ruff/rules/#isort-i + "N", # https://docs.astral.sh/ruff/rules/#pep8-naming-n + "D", # https://docs.astral.sh/ruff/rules/#pydocstyle-d + "UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up + "ANN", # https://docs.astral.sh/ruff/rules/#flake8-annotations-ann + "ASYNC", # https://docs.astral.sh/ruff/rules/#flake8-async-async + "S", # https://docs.astral.sh/ruff/rules/#flake8-bandit-s + "B", # https://docs.astral.sh/ruff/rules/#flake8-bugbear-b + "A", # https://docs.astral.sh/ruff/rules/#flake8-builtins-a + "C4", # https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 + "DTZ", # https://docs.astral.sh/ruff/rules/#flake8-datetimez-dtz + "T10", # https://docs.astral.sh/ruff/rules/#flake8-datetimez-dtz + "EM", # https://docs.astral.sh/ruff/rules/#flake8-errmsg-em + "G", # https://docs.astral.sh/ruff/rules/#flake8-logging-format-g + "PIE", # https://docs.astral.sh/ruff/rules/#flake8-pie-pie + "T20", # https://docs.astral.sh/ruff/rules/#flake8-print-t20 + "PT", # https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt + "Q", # https://docs.astral.sh/ruff/rules/#flake8-quotes-q + "RSE", # https://docs.astral.sh/ruff/rules/#flake8-raise-rse + "RET", # https://docs.astral.sh/ruff/rules/#flake8-return-ret + "SIM", # https://docs.astral.sh/ruff/rules/#flake8-simplify-sim + "PTH", # https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth + "PGH", # https://docs.astral.sh/ruff/rules/#pygrep-hooks-pgh + "RUF", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf +] +fixable = [ + "I", + "F401", + "D", + "UP", + "ANN", + "B", + "C4", + "G", + "PIE", + "PT", + "RSE", + "SIM", + "RUF" +] +# ANN101 - missing-type-self +# ANN003 - missing-type-kwargs +# D203 - one-blank-line-before-class +# D205 - blank-line-after-summary +# D206 - indent-with-spaces* +# D213 - multi-line-summary-second-line +# D300 - triple-single-quotes* +# D400 - ends-in-period +# D415 - ends-in-punctuation +# E111 - indentation-with-invalid-multiple* +# E114 - indentation-with-invalid-multiple-comment* +# E117 - over-indented* +# E501 - line-too-long* +# W191 - tab-indentation* +# S321 - suspicious-ftp-lib-usage +# *ignored for compatibility with formatter +ignore = [ + "ANN101", "ANN003", + "D203", "D205", "D206", "D213", "D300", "D400", "D415", + "E111", "E114", "E117", "E501", + "W191", + "S321", +] + +[tool.ruff.lint.per-file-ignores] +# ANN001 - missing-type-function-argument +# ANN2 - missing-return-type +# ANN102 - missing-type-cls +# S101 - assert +# B011 - assert-false +"tests/*" = ["ANN001", "ANN2", "ANN102", "S101", "B011"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools_scm] + +[tool.pytest.ini_options] +addopts = "--cov-report=term-missing --cov=ga4gh" +testpaths = ["tests", "src"] +doctest_optionflags = "ALLOW_UNICODE ALLOW_BYTES ELLIPSIS IGNORE_EXCEPTION_DETAIL NORMALIZE_WHITESPACE" diff --git a/src/ga4gh/cat_vrs/__init__.py b/src/ga4gh/cat_vrs/__init__.py new file mode 100644 index 0000000..fd0f4a9 --- /dev/null +++ b/src/ga4gh/cat_vrs/__init__.py @@ -0,0 +1 @@ +"""Package for Cat-VRS Python implementation"""