Skip to content

Commit

Permalink
feat: initial implementation of python bindings for bwa aln
Browse files Browse the repository at this point in the history
  • Loading branch information
nh13 committed Dec 16, 2024
1 parent b4c505d commit ea8ac13
Show file tree
Hide file tree
Showing 30 changed files with 60,805 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @nh13
90 changes: 90 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: CI

on: push
env:
POETRY_VERSION: 1.8

jobs:
testing:
runs-on: ubuntu-24.04
strategy:
matrix:
PYTHON_VERSION: ["3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: "lh3/bwa"
path: "bwa"
- name: Set up Python ${{matrix.PYTHON_VERSION}}
uses: actions/setup-python@v1
with:
python-version: ${{matrix.PYTHON_VERSION}}

- name: Get full Python version
id: full-python-version
shell: bash
run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")

- name: Install poetry
shell: bash
run: |
python -m pip install --upgrade pip
pip install poetry==${{env.POETRY_VERSION}}
- name: Configure poetry
shell: bash
run: poetry config virtualenvs.in-project true

- name: Set up cache
uses: actions/cache@v2
id: cache
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }}

- name: Ensure cache is healthy
if: steps.cache.outputs.cache-hit == 'true'
shell: bash
run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv

- name: Check that the lock file is up to date
shell: bash
run: |
poetry lock --check
- name: Install deps
shell: bash
run: |
poetry install
- name: Style checking
shell: bash
run: |
poetry run ruff format --check bwapy tests
- name: Run lint
shell: bash
run: |
poetry run ruff check bwapy tests
- name: Run mypy
shell: bash
run: |
poetry run mypy bwapy tests --config=pyproject.toml
- name: Run pytest
shell: bash
run: |
poetry run python -m pytest --cov=bwapy --cov-report=xml --cov-branch
- name: Run docs
shell: bash
run: |
set -euo pipefail
poetry run mkdocs build --strict
- name: Upload code coverage
uses: codecov/[email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}
20 changes: 20 additions & 0 deletions .github/workflows/readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: readthedocs/actions
on:
pull_request_target:
types:
- opened
# Execute this action only on PRs that touch
# documentation files.
paths:
- "docs/**"

permissions:
pull-requests: write

jobs:
documentation-links:
runs-on: ubuntu-24.04
steps:
- uses: readthedocs/actions/preview@v1
with:
project-slug: "bwapy"
12 changes: 12 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
build:
os: ubuntu-24.04
tools:
python: "3.12"
jobs:
post_install:
- pip install poetry==1.8.3
- poetry config virtualenvs.create false
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install
mkdocs:
configuration: mkdocs.yml
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
[![Language][language-badge]][language-link]
[![Code Style][code-style-badge]][code-style-link]
[![Type Checked][type-checking-badge]][type-checking-link]
[![PEP8][pep-8-badge]][pep-8-link]
[![Code Coverage][code-coverage-badge]][code-coverage-link]
[![License][license-badge]][license-link]


[language-badge]: http://img.shields.io/badge/language-python-brightgreen.svg
[language-link]: http://www.python.org/
[code-style-badge]: https://img.shields.io/badge/code%20style-black-000000.svg
[code-style-link]: https://black.readthedocs.io/en/stable/
[type-checking-badge]: http://www.mypy-lang.org/static/mypy_badge.svg
[type-checking-link]: http://mypy-lang.org/
[pep-8-badge]: https://img.shields.io/badge/code%20style-pep8-brightgreen.svg
[pep-8-link]: https://www.python.org/dev/peps/pep-0008/
[code-coverage-badge]: https://codecov.io/gh/fulcrumgenomics/bwapy/branch/main/graph/badge.svg
[code-coverage-link]: https://codecov.io/gh/fulcrumgenomics/bwapy
[license-badge]: http://img.shields.io/badge/license-MIT-blue.svg
[license-link]: https://github.com/fulcrumgenomics/bwapy/blob/main/LICENSE

# bwapy

Python language bindings for [bwa][bwa-link]

See documentation on [bwapy.readthedocs.org][rtd-link].


[rtd-link]: http://bwapy.readthedocs.org/en/stable
[bwa-link]: https://github.com/lh3/bwa].
112 changes: 112 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from setuptools import Extension, Distribution
from typing import List

from Cython.Build import cythonize
from Cython.Distutils.build_ext import new_build_ext as cython_build_ext
import multiprocessing
from pathlib import Path

SOURCE_DIR = Path("bwapy")
BUILD_DIR = Path("cython_build")
compile_args = []
link_args = []
include_dirs = ["bwa"]
libraries = ['m', 'z', 'pthread']
library_dirs=['bwa']
extra_objects = [] #glob.glob(os.path.join('bwa', '*.o'))
h_files = []
c_files = []
for root_dir in ["bwa", "bwapy"]:
h_files.extend(str(x) for x in Path(root_dir).rglob("*.h"))
c_files.extend(str(x) for x in Path(root_dir).rglob("*.c") if x.name not in ['example.c', 'main.c'])

extension_module = Extension(
name='bwapy.libbwapy',
sources=['bwapy/libbwapy.pyx'] + c_files,
depends=h_files,
extra_compile_args=compile_args,
extra_link_args=link_args,
extra_objects=extra_objects,
include_dirs=include_dirs,
language='c',
libraries=libraries,
library_dirs=library_dirs,
)


def cythonize_helper(extension_modules: List[Extension]) -> List[Extension]:
"""Cythonize all Python extensions"""

return cythonize(
module_list=extension_modules,

# Don't build in source tree (this leaves behind .c files)
build_dir=BUILD_DIR,

# Don't generate an .html output file. Would contain source.
annotate=False,

# Parallelize our build
nthreads=multiprocessing.cpu_count() * 2,

# Tell Cython we're using Python 3. Becomes default in Cython 3
compiler_directives={"language_level": "3"},

# (Optional) Always rebuild, even if files untouched
force=True,
)

CLASSIFIERS = '''
Development Status :: 4 - Beta
Intended Audience :: Science/Research
Intended Audience :: Developers
License :: OSI Approved
Programming Language :: Python
Topic :: Software Development
Topic :: Scientific/Engineering
Operating System :: POSIX
Operating System :: Unix
Operating System :: MacOS
'''


def build():
# Collect and cythonize all files
extension_modules = cythonize_helper([extension_module])

# Use Setuptools to collect files
distribution = Distribution({
"name": "bwapy",
'version': '0.0.1', # FIXME
'description': 'Todo', # FIXME
'long_description': 'FIXME',
'long_description_content_type': 'text/x-rst',
'author': 'Nils Homer',
'author_email': '[email protected]',
'license': 'MIT',
'platforms': ['POSIX', 'UNIX', 'MacOS'],
'classifiers': [_f for _f in CLASSIFIERS.split('\n') if _f],
'url': 'https://github.com/fulcrumgenomics/bwapy',
'packages': ['bwapy'],
'package_dirs': {'bwapy': 'bwapy'},
"ext_modules": extension_modules,
"cmdclass": {
"build_ext": cython_build_ext,
},
})

# Grab the build_ext command and copy all files back to source dir.
# Done so Poetry grabs the files during the next step in its build.
build_ext_cmd = distribution.get_command_obj("build_ext")
build_ext_cmd.ensure_finalized()
# Set the value to 1 for "inplace", with the goal to build extensions
# in build directory, and then copy all files back to the source dir
# (under the hood, "copy_extensions_to_source" will be called after
# building the extensions). This is done so Poetry grabs the files
# during the next step in its build.
build_ext_cmd.inplace = 1
build_ext_cmd.run()


if __name__ == "__main__":
build()
9 changes: 9 additions & 0 deletions bwapy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: bwapy
channels:
- defaults
- conda-forge
- bioconda
dependencies:
- python=3.11
- cython=3.0.11
- pysam=0.22.1
4 changes: 4 additions & 0 deletions bwapy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import bwapy.libbwapy as libbwapy
from bwapy.libbwapy import * # noqa: F403

__all__ = libbwapy
Loading

0 comments on commit ea8ac13

Please sign in to comment.