[med-svn] [Git][med-team/cyvcf2][upstream] New upstream version 0.34.0
Andreas Tille (@tille)
gitlab at salsa.debian.org
Mon Sep 21 09:45:47 BST 2026
Andreas Tille pushed to branch upstream at Debian Med / cyvcf2
Commits:
7960b528 by Andreas Tille at 2026-09-21T10:19:36+02:00
New upstream version 0.34.0
- - - - -
22 changed files:
- .github/workflows/build.yml
- .github/workflows/wheels.yml
- CHANGES.md
- + CMakeLists.txt
- − MANIFEST.in
- README.md
- ci/Dockerfile.alpine.test
- ci/Dockerfile.slim.test
- ci/linux-deps
- ci/osx-deps
- cyvcf2/__init__.py
- + cyvcf2/_version.py
- cyvcf2/cyvcf2.pxd
- cyvcf2/cyvcf2.pyx
- cyvcf2/helpers.h
- + cyvcf2/tests/test.warnings.vcf.gz
- + cyvcf2/tests/test.warnings.vcf.gz.tbi
- cyvcf2/tests/test_cli.py
- pyproject.toml
- requirements.txt
- − setup.cfg
- − setup.py
Changes:
=====================================
.github/workflows/build.yml
=====================================
@@ -1,6 +1,14 @@
name: Build
-on: [push, pull_request]
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
jobs:
docker-build:
@@ -28,6 +36,7 @@ jobs:
with:
submodules: recursive
- name: Set up QEMU
+ if: matrix.platform == 'linux/arm64'
uses: docker/setup-qemu-action at v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action at v3
@@ -41,37 +50,33 @@ jobs:
tags: cyvcf2:${{ matrix.python_tag_type }}-test
push: false
load: true
+ cache-from: type=gha,scope=docker-test-${{ matrix.python_tag_type }}
+ cache-to: type=gha,mode=max,scope=docker-test-${{ matrix.python_tag_type }}
build-args: |
PYTHON_VERSION=${{ matrix.python_tag_type }}
- name: Docker Run Tests
run: |
- docker run --rm --platform ${{ matrix.platform }} cyvcf2:${{ matrix.python_tag_type }}-test pytest --cov cyvcf2 --cov-report term-missing
+ docker run --rm --platform ${{ matrix.platform }} cyvcf2:${{ matrix.python_tag_type }}-test pytest -q
build:
name: Run tests on Python ${{ matrix.python-version }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [ubuntu-22.04, macos-13]
+ os: [ubuntu-22.04, macos-14]
python-version:
- ["pypy3.10", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+ ["pypy3.10", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
exclude:
# Run only the latest versions on macOS and windows
- - os: macos-13
+ - os: macos-14
python-version: "pypy3.10"
- - os: macos-13
- python-version: "3.7"
- - os: macos-13
- python-version: "3.8"
- - os: macos-13
+ - os: macos-14
python-version: "3.9"
- - os: macos-13
+ - os: macos-14
python-version: "3.10"
- - os: macos-13
+ - os: macos-14
python-version: "3.11"
- - os: macos-12
- python-version: "3.12"
steps:
- uses: actions/checkout at v4
@@ -85,41 +90,54 @@ jobs:
- name: Set macOS env
if: runner.os == 'macOS'
run: |
- # building options
- echo "MACOSX_DEPLOYMENT_TARGET=10.9" >> "$GITHUB_ENV"
- echo "ARCHFLAGS=-arch x86_64" >> "$GITHUB_ENV"
+ BREW_PREFIX="$(brew --prefix)"
+ LIBDEFLATE_PREFIX="${BREW_PREFIX}/opt/libdeflate"
+
+ # Homebrew on arm64 installs under /opt/homebrew, which is not in default compiler search paths.
+ echo "CPPFLAGS=-I${BREW_PREFIX}/include -I${LIBDEFLATE_PREFIX}/include ${CPPFLAGS:-}" >> "$GITHUB_ENV"
+ echo "LDFLAGS=-L${BREW_PREFIX}/lib -L${LIBDEFLATE_PREFIX}/lib ${LDFLAGS:-}" >> "$GITHUB_ENV"
+ echo "PKG_CONFIG_PATH=${LIBDEFLATE_PREFIX}/lib/pkgconfig:${BREW_PREFIX}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}" >> "$GITHUB_ENV"
+
+ # arm64 requires a newer deployment target than x86_64.
+ if [ "${{ runner.arch }}" = "X64" ]; then
+ echo "MACOSX_DEPLOYMENT_TARGET=10.9" >> "$GITHUB_ENV"
+ echo "ARCHFLAGS=-arch x86_64" >> "$GITHUB_ENV"
+ else
+ echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> "$GITHUB_ENV"
+ fi
- name: Install Linux build prerequisites
if: runner.os == 'Linux'
run: |
sudo apt-get update
- sudo apt-get install -y --no-install-recommends libcurl4-openssl-dev zlib1g-dev libssl-dev liblzma-dev \
- libbz2-dev libdeflate-dev
+ sudo apt-get install -y --no-install-recommends cmake ninja-build libcurl4-openssl-dev zlib1g-dev \
+ libssl-dev liblzma-dev libbz2-dev libdeflate-dev
- name: Install macOS build prerequisites
if: runner.os == 'macOS'
run: |
- brew install automake libdeflate
+ brew install automake cmake libdeflate ninja pkg-config
- name: Install
run: |
- pip install -r requirements.txt
- pip install pytest pytest-cov
+ python -m pip install --upgrade pip
+ python -m pip install pytest pytest-cov
CYVCF2_HTSLIB_CONFIGURE_OPTIONS="--enable-libcurl --enable-s3 --enable-lzma --enable-bz2 --with-libdeflate" \
- CYTHONIZE=1 python setup.py build_ext -i
+ python -m pip install -v -e .
- name: Test
run: |
pytest --cov cyvcf2 --cov-report term-missing
- # make sure to keep this numpy version in sync with setup.py
+ # make sure to keep this numpy version in sync with pyproject.toml
- name: Test with oldest numpy that we support
- if: contains(fromJson('["3.7"]'), matrix.python-version)
+ if: contains(fromJson('["3.9"]'), matrix.python-version)
run: |
- pip install --force-reinstall --no-cache-dir 'numpy==1.16.0'
+ pip install --force-reinstall --no-cache-dir 'numpy==2.0.0'
pytest --cov cyvcf2 --cov-report term-missing
- name: Test with newest available numpy
+ if: matrix.os == 'ubuntu-22.04' && matrix.python-version == '3.14'
run: |
pip install -U numpy
pytest --cov cyvcf2 --cov-report term-missing
@@ -147,6 +165,7 @@ jobs:
mingw-w64-ucrt-x86_64-libdeflate
mingw-w64-ucrt-x86_64-xz
mingw-w64-ucrt-x86_64-curl
+ mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-zlib
mingw-w64-ucrt-x86_64-bzip2
mingw-w64-ucrt-x86_64-tools-git
@@ -170,19 +189,84 @@ jobs:
- name: Install
run: |
- pip install -r requirements.txt
- pip install pytest pytest-cov
- CYTHONIZE=1 python setup.py build_ext -i
+ python -m venv .venv
+ . .venv/bin/activate
+ python -m pip install --upgrade pip
+ python -m pip install pytest pytest-cov
+ python -m pip install -v -e .
- name: Test
run: |
+ . .venv/bin/activate
pytest --cov cyvcf2 --cov-report term-missing
- name: Test with newest available numpy
run: |
+ . .venv/bin/activate
pip install -U numpy
pytest --cov cyvcf2 --cov-report term-missing
+ conda_external_htslib:
+ name: Conda external htslib ${{ matrix.htslib-version }}
+ runs-on: ubuntu-22.04
+ strategy:
+ fail-fast: false
+ matrix:
+ htslib-version: ["1.21", "1.22.1", "1.23.1"]
+
+ steps:
+ - uses: actions/checkout at v4
+ with:
+ submodules: recursive
+
+ - name: Set up micromamba
+ uses: mamba-org/setup-micromamba at v2
+ with:
+ environment-name: cyvcf2-conda-external
+ condarc: |
+ channels:
+ - conda-forge
+ - bioconda
+ channel_priority: strict
+ create-args: >-
+ python=3.12
+ pip
+ scikit-build-core>=0.11
+ cmake>=3.20
+ ninja
+ cython>=3
+ numpy>=2.0.0
+ htslib=${{ matrix.htslib-version }}
+ pkg-config
+ setuptools
+ wheel
+
+ - name: Install against conda htslib
+ shell: micromamba-shell {0}
+ run: |
+ export CYVCF2_HTSLIB_MODE=EXTERNAL
+ export CMAKE_PREFIX_PATH="${CONDA_PREFIX}${CMAKE_PREFIX_PATH:+:${CMAKE_PREFIX_PATH}}"
+ export PKG_CONFIG_PATH="${CONDA_PREFIX}/lib/pkgconfig${PKG_CONFIG_PATH:+:${PKG_CONFIG_PATH}}"
+
+ python -m pip install . --no-deps --no-build-isolation -v > conda-external-build.log 2>&1
+ cat conda-external-build.log
+ if grep -E "building bundled( shared)? htslib" conda-external-build.log; then
+ echo "Expected external htslib, but build used bundled htslib"
+ exit 1
+ fi
+
+ - name: Verify external htslib linkage
+ shell: micromamba-shell {0}
+ run: |
+ extension="$(cd "${RUNNER_TEMP}" && python -c 'import cyvcf2.cyvcf2 as module; print(module.__file__)')"
+ echo "Extension path: ${extension}"
+
+ cd "${RUNNER_TEMP}"
+ python -c 'from cyvcf2 import VCF; print(VCF)'
+
+ ldd "${extension}" | tee "${GITHUB_WORKSPACE}/conda-external-linkage.txt"
+ grep -E "libhts\.so" "${GITHUB_WORKSPACE}/conda-external-linkage.txt"
+
sdist:
runs-on: ubuntu-22.04
strategy:
@@ -200,10 +284,10 @@ jobs:
- name: Install sdist prerequisites
run: |
- pip install -r requirements.txt
+ python -m pip install --upgrade pip build
- name: Create source distribution
- run: CYTHONIZE=1 python setup.py sdist
+ run: python -m build --sdist
- name: Install Linux build prerequisites
if: runner.os == 'Linux'
@@ -213,7 +297,7 @@ jobs:
libbz2-dev libdeflate-dev
- name: Build (via sdist tarball)
- run: pip install --verbose --no-deps --no-binary='cyvcf2' cyvcf2-*.tar.gz
+ run: python -m pip install --verbose --no-binary='cyvcf2' cyvcf2-*.tar.gz
working-directory: dist
- name: Install test prerequisites
=====================================
.github/workflows/wheels.yml
=====================================
@@ -14,12 +14,35 @@ on:
required: false
default: false
schedule:
- # run weekly on a Monday
- - cron: "0 0 * * 1"
+ # run monthly on the 1st
+ - cron: "0 0 1 * *"
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ CIBW_ENABLE: pypy
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
+ # manylinux2014 can't build on aarch64
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
+ CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2
+ CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2
+ CIBW_ARCHS_LINUX: auto64 aarch64
+ CIBW_BEFORE_BUILD_LINUX: "{project}/ci/linux-deps"
+ CIBW_REPAIR_WHEEL_COMMAND_LINUX: 'LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib64" && auditwheel repair -w {dest_dir} {wheel}'
+ CIBW_ARCHS_MACOS: auto64
+ CIBW_BEFORE_BUILD_MACOS: "{project}/ci/osx-deps"
+ CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
+ CIBW_ENVIRONMENT: >-
+ CYVCF2_HTSLIB_CONFIGURE_OPTIONS="--enable-libcurl --enable-s3 --enable-lzma --enable-bz2 --with-libdeflate"
+ CIBW_TEST_COMMAND: "{project}/ci/test"
jobs:
build_wheels:
- name: Build wheels for ${{ matrix.python-version }}-${{ matrix.buildplat[1] }}
+ # Full wheel matrix for releases, schedule, and manual runs.
+ if: github.event_name != 'push' || github.ref != 'refs/heads/main'
+ name: Build wheels (full matrix)
runs-on: ${{ matrix.buildplat[0] }}
strategy:
matrix:
@@ -28,67 +51,52 @@ jobs:
- [ubuntu-22.04, musllinux_x86_64]
- [ubuntu-22.04, manylinux_aarch64]
- [ubuntu-22.04, musllinux_aarch64]
- - [macos-13, macosx_x86_64]
+ - [macos-15-intel, macosx_x86_64]
- [macos-14, macosx_arm64]
- python-version: [pp310, cp38, cp39, cp310, cp311, cp312, cp313, cp314]
+ python-version: [pp311, cp39, cp310, cp311, cp312, cp313, cp314]
exclude:
- # pp310, cp38 on musllinux is not support
+ # pp311 not built on musllinux or manylinux_aarch64
# cp39, cp310 on musllinux_aarch64, wheel building may hangup, ignore it
# drop 37 so we can use newer cibuildwheel
+ - buildplat: [ubuntu-22.04, manylinux_aarch64]
+ python-version: pp311
- buildplat: [ubuntu-22.04, musllinux_x86_64]
- python-version: cp38
- - buildplat: [ubuntu-22.04, musllinux_x86_64]
- python-version: pp310
- - buildplat: [ubuntu-22.04, musllinux_aarch64]
- python-version: cp38
+ python-version: pp311
- buildplat: [ubuntu-22.04, musllinux_aarch64]
python-version: cp39
- buildplat: [ubuntu-22.04, musllinux_aarch64]
python-version: cp310
- buildplat: [ubuntu-22.04, musllinux_aarch64]
- python-version: pp310
+ python-version: pp311
steps:
- uses: actions/checkout at v4
with:
submodules: recursive
+ - name: Cache wheel build downloads
+ uses: actions/cache at v4
+ with:
+ path: |
+ ~/.cache/pip
+ ~/.cache/cibuildwheel
+ key: ${{ runner.os }}-${{ matrix.buildplat[1] }}-cibw-${{ hashFiles('pyproject.toml', 'requirements.txt', 'ci/linux-deps', 'ci/osx-deps') }}
+ restore-keys: |
+ ${{ runner.os }}-${{ matrix.buildplat[1] }}-cibw-
+ ${{ runner.os }}-cibw-
+
- name: Set up QEMU
- if: runner.os == 'Linux'
+ if: runner.os == 'Linux' && contains(matrix.buildplat[1], 'aarch64')
uses: docker/setup-qemu-action at v3
- name: Build wheels
- uses: pypa/cibuildwheel at v3.1.4
+ uses: pypa/cibuildwheel at v4.1.0
with:
package-dir: .
output-dir: wheelhouse
config-file: "{package}/pyproject.toml"
env:
- # select
CIBW_BUILD: ${{ matrix.python-version }}-${{ matrix.buildplat[1] }}
- CIBW_ENABLE: pypy
- CIBW_PRERELEASE_PYTHONS: 1
-
- # linux
- CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
- # manylinux2014 can't build on aarch64
- CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
- CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2
- CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2
- CIBW_ARCHS_LINUX: auto64 aarch64
- CIBW_BEFORE_BUILD_LINUX: "{project}/ci/linux-deps"
- CIBW_REPAIR_WHEEL_COMMAND_LINUX: 'LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib64" && auditwheel repair -w {dest_dir} {wheel}'
-
- # macos
- CIBW_ARCHS_MACOS: auto64
- CIBW_BEFORE_BUILD_MACOS: "{project}/ci/osx-deps"
- CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
-
- # build
- CIBW_ENVIRONMENT: >-
- CYVCF2_HTSLIB_CONFIGURE_OPTIONS="--enable-libcurl --enable-s3 --enable-lzma --enable-bz2 --with-libdeflate"
- CYTHONIZE=1
- CIBW_TEST_COMMAND: "{project}/ci/test"
# Enable tmate debugging of manually-triggered workflows if the input option was provided
- name: Setup tmate session
@@ -100,6 +108,65 @@ jobs:
name: artifact-${{ matrix.python-version }}-${{ matrix.buildplat[1] }}
path: ./wheelhouse/*.whl
+ build_wheels_smoke:
+ # Smaller matrix on main to keep CI cost controlled.
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
+ name: Build wheels (smoke matrix)
+ runs-on: ${{ matrix.buildplat[0] }}
+ strategy:
+ matrix:
+ include:
+ - buildplat: [ubuntu-22.04, manylinux_x86_64]
+ python-version: cp39
+ - buildplat: [ubuntu-22.04, manylinux_x86_64]
+ python-version: cp314
+ - buildplat: [ubuntu-22.04, manylinux_x86_64]
+ python-version: pp311
+ - buildplat: [ubuntu-22.04, musllinux_x86_64]
+ python-version: cp314
+ - buildplat: [ubuntu-22.04, manylinux_aarch64]
+ python-version: cp314
+ - buildplat: [ubuntu-22.04, musllinux_aarch64]
+ python-version: cp314
+ - buildplat: [macos-15-intel, macosx_x86_64]
+ python-version: cp314
+ - buildplat: [macos-14, macosx_arm64]
+ python-version: cp314
+
+ steps:
+ - uses: actions/checkout at v4
+ with:
+ submodules: recursive
+
+ - name: Cache wheel build downloads
+ uses: actions/cache at v4
+ with:
+ path: |
+ ~/.cache/pip
+ ~/.cache/cibuildwheel
+ key: ${{ runner.os }}-${{ matrix.buildplat[1] }}-cibw-${{ hashFiles('pyproject.toml', 'requirements.txt', 'ci/linux-deps', 'ci/osx-deps') }}
+ restore-keys: |
+ ${{ runner.os }}-${{ matrix.buildplat[1] }}-cibw-
+ ${{ runner.os }}-cibw-
+
+ - name: Set up QEMU
+ if: runner.os == 'Linux' && contains(matrix.buildplat[1], 'aarch64')
+ uses: docker/setup-qemu-action at v3
+
+ - name: Build wheels
+ uses: pypa/cibuildwheel at v4.1.0
+ with:
+ package-dir: .
+ output-dir: wheelhouse
+ config-file: "{package}/pyproject.toml"
+ env:
+ CIBW_BUILD: ${{ matrix.python-version }}-${{ matrix.buildplat[1] }}
+
+ - uses: actions/upload-artifact at v4
+ with:
+ name: artifact-smoke-${{ matrix.python-version }}-${{ matrix.buildplat[1] }}
+ path: ./wheelhouse/*.whl
+
build_sdist:
name: Build source distribution
runs-on: ubuntu-22.04
@@ -111,13 +178,15 @@ jobs:
name: Install Python
with:
python-version: "3.14"
+ cache: pip
+ cache-dependency-path: requirements.txt
- name: Install dependencies
run: |
- pip install -r requirements.txt
+ python -m pip install --upgrade pip build
- name: Build sdist
- run: CYTHONIZE=1 python setup.py sdist
+ run: python -m build --sdist
- uses: actions/upload-artifact at v4
with:
=====================================
CHANGES.md
=====================================
@@ -1,3 +1,11 @@
+# v0.34.0
++ drop support for end-of-life Python 3.8 (minimum is now 3.9)
++ add PyPI trove classifiers (Python 3.9–3.14)
++ bump cibuildwheel to v4 and drop the stale prerelease-pythons flag
+
+# v0.33.0
++ modernize build system to use scikit-build-core (thanks @jhl-oai #327)
+
# v0.32.0
+ make repeated `vcf()` calls restart from the beginning and isolate region
queries from the main iterator state. *NOTE* this can be backwards incompatible for those using vcf() to iterate without an index.
=====================================
CMakeLists.txt
=====================================
@@ -0,0 +1,273 @@
+cmake_minimum_required(VERSION 3.20...3.30)
+
+project(${SKBUILD_PROJECT_NAME} LANGUAGES C)
+
+if(SKBUILD_STATE STREQUAL "sdist")
+ find_program(MAKE_EXECUTABLE NAMES make gmake mingw32-make REQUIRED)
+ execute_process(
+ COMMAND "${MAKE_EXECUTABLE}" htscodecs/htscodecs/version.h
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/htslib"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ return()
+endif()
+
+find_package(Python COMPONENTS Interpreter Development.Module NumPy REQUIRED)
+
+set(CYVCF2_HTSLIB_CONFIGURE_OPTIONS "$ENV{CYVCF2_HTSLIB_CONFIGURE_OPTIONS}" CACHE STRING "Extra options passed to htslib configure")
+set(CYVCF2_HTSLIB_MODE "$ENV{CYVCF2_HTSLIB_MODE}" CACHE STRING "How to link htslib: BUILTIN or EXTERNAL")
+set(CYVCF2_CYTHONIZE_DEFAULT "$ENV{CYVCF2_CYTHONIZE}")
+if(CYVCF2_CYTHONIZE_DEFAULT STREQUAL "")
+ set(CYVCF2_CYTHONIZE_DEFAULT "$ENV{CYTHONIZE}")
+endif()
+set(CYVCF2_CYTHONIZE "${CYVCF2_CYTHONIZE_DEFAULT}" CACHE STRING "Whether to regenerate cyvcf2.c from Cython: AUTO, ON, or OFF")
+
+if(CYVCF2_HTSLIB_MODE STREQUAL "")
+ if(WIN32)
+ set(CYVCF2_HTSLIB_MODE "EXTERNAL")
+ else()
+ set(CYVCF2_HTSLIB_MODE "BUILTIN")
+ endif()
+endif()
+
+string(TOUPPER "${CYVCF2_HTSLIB_MODE}" CYVCF2_HTSLIB_MODE)
+set_property(CACHE CYVCF2_HTSLIB_MODE PROPERTY STRINGS BUILTIN EXTERNAL)
+set_property(CACHE CYVCF2_CYTHONIZE PROPERTY STRINGS AUTO ON OFF)
+
+if(NOT CYVCF2_HTSLIB_MODE STREQUAL "BUILTIN" AND NOT CYVCF2_HTSLIB_MODE STREQUAL "EXTERNAL")
+ message(FATAL_ERROR "CYVCF2_HTSLIB_MODE must be BUILTIN or EXTERNAL, got '${CYVCF2_HTSLIB_MODE}'")
+endif()
+
+set(CYVCF2_SOURCE_C "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2/cyvcf2.c")
+set(CYVCF2_GENERATED_C "${CMAKE_CURRENT_BINARY_DIR}/generated/cyvcf2.c")
+
+function(cyvcf2_boolish INPUT OUTPUT)
+ string(TOUPPER "${INPUT}" NORMALIZED_INPUT)
+ if(NORMALIZED_INPUT STREQUAL "" OR NORMALIZED_INPUT STREQUAL "AUTO")
+ set(${OUTPUT} "AUTO" PARENT_SCOPE)
+ elseif(NORMALIZED_INPUT MATCHES "^(1|ON|TRUE|YES)$")
+ set(${OUTPUT} "ON" PARENT_SCOPE)
+ elseif(NORMALIZED_INPUT MATCHES "^(0|OFF|FALSE|NO)$")
+ set(${OUTPUT} "OFF" PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Expected a boolean-like value or AUTO, got '${INPUT}'")
+ endif()
+endfunction()
+
+cyvcf2_boolish("${CYVCF2_CYTHONIZE}" CYVCF2_CYTHONIZE_NORMALIZED)
+
+if(CYVCF2_CYTHONIZE_NORMALIZED STREQUAL "AUTO")
+ if(EXISTS "${CYVCF2_SOURCE_C}")
+ set(CYVCF2_CYTHONIZE_NORMALIZED "OFF")
+ else()
+ set(CYVCF2_CYTHONIZE_NORMALIZED "ON")
+ endif()
+endif()
+
+if(CYVCF2_CYTHONIZE_NORMALIZED)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated")
+ add_custom_command(
+ OUTPUT "${CYVCF2_GENERATED_C}"
+ COMMAND Python::Interpreter -m cython
+ "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2/cyvcf2.pyx"
+ --output-file "${CYVCF2_GENERATED_C}"
+ DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2/cyvcf2.pyx"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2/cyvcf2.pxd"
+ COMMENT "Generating cyvcf2.c from Cython"
+ VERBATIM
+ )
+ set(CYVCF2_EXTENSION_SOURCE "${CYVCF2_GENERATED_C}")
+else()
+ if(NOT EXISTS "${CYVCF2_SOURCE_C}")
+ message(FATAL_ERROR "CYVCF2_CYTHONIZE is OFF, but ${CYVCF2_SOURCE_C} does not exist")
+ endif()
+ set(CYVCF2_EXTENSION_SOURCE "${CYVCF2_SOURCE_C}")
+endif()
+
+function(cyvcf2_split_configure_options OUTPUT)
+ if(CYVCF2_HTSLIB_CONFIGURE_OPTIONS STREQUAL "")
+ set(${OUTPUT} "" PARENT_SCOPE)
+ else()
+ separate_arguments(_cyvcf2_configure_options UNIX_COMMAND "${CYVCF2_HTSLIB_CONFIGURE_OPTIONS}")
+ set(${OUTPUT} "${_cyvcf2_configure_options}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(cyvcf2_build_htslib STATIC_MODE)
+ find_program(MAKE_EXECUTABLE NAMES make gmake mingw32-make REQUIRED)
+
+ set(HTSLIB_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/htslib")
+ cyvcf2_split_configure_options(HTSLIB_CONFIGURE_OPTION_LIST)
+
+ if(NOT EXISTS "${HTSLIB_SOURCE_DIR}/config.status")
+ execute_process(
+ COMMAND autoreconf -i
+ WORKING_DIRECTORY "${HTSLIB_SOURCE_DIR}"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+
+ set(HTSLIB_CONFIGURE_COMMAND ./configure)
+ if(STATIC_MODE)
+ list(APPEND HTSLIB_CONFIGURE_COMMAND "CFLAGS=-fPIC")
+ endif()
+ list(APPEND HTSLIB_CONFIGURE_COMMAND ${HTSLIB_CONFIGURE_OPTION_LIST})
+
+ execute_process(
+ COMMAND ${HTSLIB_CONFIGURE_COMMAND}
+ WORKING_DIRECTORY "${HTSLIB_SOURCE_DIR}"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+ endif()
+
+ execute_process(
+ COMMAND "${MAKE_EXECUTABLE}" htscodecs/htscodecs/version.h
+ WORKING_DIRECTORY "${HTSLIB_SOURCE_DIR}"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+
+ if(STATIC_MODE)
+ set(HTSLIB_BUILD_TARGET libhts.a)
+ elseif(APPLE)
+ set(HTSLIB_BUILD_TARGET libhts.dylib)
+ elseif(WIN32)
+ set(HTSLIB_BUILD_TARGET hts-3.dll)
+ else()
+ set(HTSLIB_BUILD_TARGET libhts.so)
+ endif()
+
+ execute_process(
+ COMMAND "${MAKE_EXECUTABLE}" "${HTSLIB_BUILD_TARGET}"
+ WORKING_DIRECTORY "${HTSLIB_SOURCE_DIR}"
+ COMMAND_ERROR_IS_FATAL ANY
+ )
+endfunction()
+
+function(cyvcf2_read_htslib_static_libs OUTPUT)
+ set(HTSLIB_CONFIG_STATUS "${CMAKE_CURRENT_SOURCE_DIR}/htslib/config.status")
+ if(NOT EXISTS "${HTSLIB_CONFIG_STATUS}")
+ set(${OUTPUT} "" PARENT_SCOPE)
+ return()
+ endif()
+
+ file(READ "${HTSLIB_CONFIG_STATUS}" HTSLIB_CONFIG_STATUS_CONTENTS)
+ string(REGEX MATCH "S\\[[\"']static_LIBS[\"']\\][ ]*=[ ]*[\"']([^\"']*)[\"']" _static_libs_match "${HTSLIB_CONFIG_STATUS_CONTENTS}")
+ if(_static_libs_match)
+ separate_arguments(HTSLIB_STATIC_LIBS UNIX_COMMAND "${CMAKE_MATCH_1}")
+ set(${OUTPUT} "${HTSLIB_STATIC_LIBS}" PARENT_SCOPE)
+ else()
+ set(${OUTPUT} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+set(CYVCF2_HTSLIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/htslib" "${CMAKE_CURRENT_SOURCE_DIR}/htslib/htslib")
+set(CYVCF2_HTSLIB_LIBRARIES "")
+set(CYVCF2_HTSLIB_TARGET "")
+
+if(CYVCF2_HTSLIB_MODE STREQUAL "BUILTIN")
+ if(WIN32)
+ message(FATAL_ERROR "CYVCF2_HTSLIB_MODE=BUILTIN is not supported on Windows")
+ endif()
+
+ message(STATUS "cyvcf2: building bundled htslib")
+ cyvcf2_build_htslib(TRUE)
+ cyvcf2_read_htslib_static_libs(CYVCF2_HTSLIB_STATIC_LIBS)
+
+ set(CYVCF2_HTSLIB_STATIC_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/htslib/libhts.a")
+ if(NOT EXISTS "${CYVCF2_HTSLIB_STATIC_LIBRARY}")
+ message(FATAL_ERROR "Expected ${CYVCF2_HTSLIB_STATIC_LIBRARY} after building htslib")
+ endif()
+
+ add_library(cyvcf2_htslib STATIC IMPORTED GLOBAL)
+ set_target_properties(cyvcf2_htslib PROPERTIES
+ IMPORTED_LOCATION "${CYVCF2_HTSLIB_STATIC_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${CYVCF2_HTSLIB_INCLUDE_DIRS}"
+ )
+ set(CYVCF2_HTSLIB_TARGET cyvcf2_htslib)
+ list(APPEND CYVCF2_HTSLIB_LIBRARIES ${CYVCF2_HTSLIB_STATIC_LIBS})
+else()
+ find_package(PkgConfig QUIET)
+ if(PkgConfig_FOUND)
+ if(WIN32)
+ pkg_check_modules(HTSLIB_PC QUIET htslib)
+ else()
+ pkg_check_modules(HTSLIB_PC QUIET IMPORTED_TARGET htslib)
+ endif()
+ endif()
+
+ if(HTSLIB_PC_FOUND)
+ if(WIN32)
+ find_path(HTSLIB_INCLUDE_DIR htslib/hts.h)
+ if(NOT HTSLIB_INCLUDE_DIR)
+ message(FATAL_ERROR "Could not find external htslib headers")
+ endif()
+ list(APPEND CYVCF2_HTSLIB_INCLUDE_DIRS "${HTSLIB_INCLUDE_DIR}")
+ list(APPEND CYVCF2_HTSLIB_LIBRARIES ${HTSLIB_PC_LIBRARIES})
+ else()
+ list(APPEND CYVCF2_HTSLIB_LIBRARIES PkgConfig::HTSLIB_PC)
+ endif()
+ else()
+ find_path(HTSLIB_INCLUDE_DIR htslib/hts.h)
+ find_library(HTSLIB_LIBRARY NAMES hts hts-3 libhts)
+ endif()
+
+ if(NOT HTSLIB_PC_FOUND AND (NOT HTSLIB_INCLUDE_DIR OR NOT HTSLIB_LIBRARY))
+ if(WIN32)
+ message(FATAL_ERROR "Could not find external htslib; install htslib first")
+ endif()
+
+ message(STATUS "cyvcf2: external htslib not found; building bundled shared htslib")
+ cyvcf2_build_htslib(FALSE)
+ set(HTSLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/htslib")
+ find_library(HTSLIB_LIBRARY NAMES hts PATHS "${CMAKE_CURRENT_SOURCE_DIR}/htslib" NO_DEFAULT_PATH)
+ endif()
+
+ if(NOT HTSLIB_PC_FOUND AND NOT HTSLIB_LIBRARY)
+ message(FATAL_ERROR "Could not locate htslib library")
+ endif()
+
+ if(NOT HTSLIB_PC_FOUND)
+ list(APPEND CYVCF2_HTSLIB_INCLUDE_DIRS "${HTSLIB_INCLUDE_DIR}")
+ list(APPEND CYVCF2_HTSLIB_LIBRARIES "${HTSLIB_LIBRARY}")
+ endif()
+endif()
+
+Python_add_library(cyvcf2_extension MODULE WITH_SOABI
+ "${CYVCF2_EXTENSION_SOURCE}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2/helpers.c"
+)
+
+set_target_properties(cyvcf2_extension PROPERTIES
+ OUTPUT_NAME "cyvcf2"
+)
+
+target_include_directories(cyvcf2_extension PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/cyvcf2"
+ ${CYVCF2_HTSLIB_INCLUDE_DIRS}
+ ${Python_NumPy_INCLUDE_DIRS}
+)
+
+if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
+ target_compile_options(cyvcf2_extension PRIVATE
+ -Wno-sign-compare
+ -Wno-unused-function
+ -Wno-strict-prototypes
+ -Wno-unused-result
+ )
+endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(cyvcf2_extension PRIVATE -Wno-discarded-qualifiers)
+endif()
+if(CMAKE_C_COMPILER_ID MATCHES "^(AppleClang|Clang)$")
+ target_compile_options(cyvcf2_extension PRIVATE -Wno-incompatible-pointer-types-discards-qualifiers)
+endif()
+
+if(CYVCF2_HTSLIB_TARGET)
+ target_link_libraries(cyvcf2_extension PRIVATE ${CYVCF2_HTSLIB_TARGET})
+endif()
+target_link_libraries(cyvcf2_extension PRIVATE ${CYVCF2_HTSLIB_LIBRARIES})
+
+install(TARGETS cyvcf2_extension
+ LIBRARY DESTINATION cyvcf2
+ RUNTIME DESTINATION cyvcf2
+)
=====================================
MANIFEST.in deleted
=====================================
@@ -1,18 +0,0 @@
-include LICENSE
-include *.md
-include cyvcf2/*.pyx
-include cyvcf2/*.pxd
-include cyvcf2/*.[ch]
-
-# exclude tests from pypi because no data file
-prune cyvcf2/tests
-
-# htslib
-include htslib/LICENSE htslib/README
-recursive-include htslib *.[ch]
-exclude htslib/*config*.h
-
-include htslib/configure.ac htslib/m4/*.m4 htslib/*.in
-include htslib/configure htslib/version.sh
-include htslib/Makefile htslib/*.mk
-exclude htslib/config.mk htslib/htscodecs.mk
=====================================
README.md
=====================================
@@ -11,7 +11,7 @@ The latest documentation for cyvcf2 can be found here:
If you use cyvcf2, please cite the [paper](https://academic.oup.com/bioinformatics/article/2971439/cyvcf2)
-Fast python **(2 and 3)** parsing of VCF and BCF including region-queries.
+Fast Python **(3.9+)** parsing of VCF and BCF including region-queries.
[](https://github.com/brentp/cyvcf2/actions/workflows/build.yml)
@@ -75,35 +75,72 @@ all_vars = list(vcf())
Installation
============
-## pip with bundled htslib
+## pip or uv with bundled htslib
+
+If a binary wheel is available for your platform, pip and uv will install it
+without building from source.
+
```
pip install cyvcf2
+uv pip install cyvcf2
```
-## pip with system htslib
+## pip or uv with system htslib
Assuming you have already built and installed htslib version 1.12 or higher.
```
CYVCF2_HTSLIB_MODE=EXTERNAL pip install --no-binary cyvcf2 cyvcf2
+CYVCF2_HTSLIB_MODE=EXTERNAL uv pip install --no-binary cyvcf2 cyvcf2
```
-## windows (experimental, only test on MSYS2)
+## windows (experimental, only tested on MSYS2)
Assuming you have already built and installed htslib.
```
-SETUPTOOLS_USE_DISTUTILS=stdlib pip install cyvcf2
+CYVCF2_HTSLIB_MODE=EXTERNAL pip install cyvcf2
```
## github (building htslib and cyvcf2 from source)
```
git clone --recursive https://github.com/brentp/cyvcf2
-pip install -r requirements.txt
-# sometimes it can be required to remove old files:
-# python setup.py clean_ext
-CYVCF2_HTSLIB_MODE=BUILTIN CYTHONIZE=1 python setup.py install
+cd cyvcf2
+CYVCF2_HTSLIB_MODE=BUILTIN python -m pip install .
+CYVCF2_HTSLIB_MODE=BUILTIN uv pip install .
# or to use a system htslib.so
-CYVCF2_HTSLIB_MODE=EXTERNAL python setup.py install
+CYVCF2_HTSLIB_MODE=EXTERNAL python -m pip install .
+CYVCF2_HTSLIB_MODE=EXTERNAL uv pip install .
+```
+
+Source builds use scikit-build-core and CMake. Python build dependencies such
+as Cython, NumPy, CMake, and Ninja are installed by PEP 517 build isolation, but
+you still need a C compiler plus the htslib native dependencies for your
+platform.
+
+Most users can leave `CYVCF2_CYTHONIZE` unset. It is mainly for developers
+building from a Git checkout who need to control when CMake regenerates
+`cyvcf2.c` from `cyvcf2/cyvcf2.pyx`:
+
+- `AUTO` (the default) uses an existing `cyvcf2/cyvcf2.c` when present and runs
+ Cython only when the file is missing.
+- `ON` regenerates the C file after edits to `cyvcf2.pyx` or `cyvcf2.pxd`, or
+ when testing Cython-generated output.
+- `OFF` requires an existing C file.
+
+For example:
+
+```
+CYVCF2_CYTHONIZE=ON python -m pip install .
+python -m pip install . --config-settings=cmake.define.CYVCF2_CYTHONIZE=ON
+```
+
+The legacy `CYTHONIZE=1` environment variable is still accepted.
+
+To build source distributions and wheels locally:
+
+```
+python -m build
+uv build
```
On **OSX**, using brew, you may have to set the following as indicated by the brew install:
@@ -124,6 +161,7 @@ Install `pytest`, then tests can be run with:
```
pytest
+uv run --with pytest pytest
```
CLI
=====================================
ci/Dockerfile.alpine.test
=====================================
@@ -4,12 +4,12 @@ FROM python:${PYTHON_VERSION}
WORKDIR /workspace
-RUN apk add --no-cache build-base autoconf automake git xz-dev curl-dev libdeflate-dev bzip2-dev
+RUN apk add --no-cache build-base autoconf automake cmake ninja git xz-dev curl-dev libdeflate-dev bzip2-dev
-COPY . .
+RUN pip install pytest pytest-cov
-RUN pip install -r requirements.txt && pip install pytest pytest-cov
+COPY . .
# build cyvcf2
RUN CYVCF2_HTSLIB_CONFIGURE_OPTIONS="--enable-libcurl --enable-s3 --enable-lzma --enable-bz2 --with-libdeflate" \
- CYTHONIZE=1 python setup.py build_ext -i
+ python -m pip install -v -e .
=====================================
ci/Dockerfile.slim.test
=====================================
@@ -4,14 +4,14 @@ FROM python:${PYTHON_VERSION}
WORKDIR /workspace
-RUN apt-get update && apt-get install --no-install-recommends -y autoconf automake gcc libcurl4-openssl-dev \
- make git libc6-dev zlib1g-dev libssl-dev liblzma-dev libbz2-dev libdeflate-dev && \
+RUN apt-get update && apt-get install --no-install-recommends -y autoconf automake cmake gcc libcurl4-openssl-dev \
+ make ninja-build git libc6-dev zlib1g-dev libssl-dev liblzma-dev libbz2-dev libdeflate-dev && \
rm -rf /var/lib/apt/lists/*
-COPY . .
+RUN pip install pytest pytest-cov
-RUN pip install -r requirements.txt && pip install pytest pytest-cov
+COPY . .
# build cyvcf2
RUN CYVCF2_HTSLIB_CONFIGURE_OPTIONS="--enable-libcurl --enable-s3 --enable-lzma --enable-bz2 --with-libdeflate" \
- CYTHONIZE=1 python setup.py build_ext -i
+ python -m pip install -v -e .
=====================================
ci/linux-deps
=====================================
@@ -14,14 +14,14 @@ echo "manylinux image woking on $ID"
# Install cyvcf2 development files.
case "$ID" in
almalinux)
- dnf install -y bzip2-devel xz-devel libcurl-devel openssl-devel openblas-devel epel-release
+ dnf install -y bzip2-devel cmake ninja-build xz-devel libcurl-devel openssl-devel openblas-devel epel-release
# packages at epel
dnf install -y libdeflate-devel
;;
alpine)
- apk add --no-cache xz-dev curl-dev libdeflate-dev
+ apk add --no-cache cmake ninja xz-dev curl-dev libdeflate-dev
;;
centos)
=====================================
ci/osx-deps
=====================================
@@ -10,7 +10,7 @@ COMMON_CMAKE_ARGS=(
-DCMAKE_BUILD_TYPE=Release
)
-brew install automake libdeflate
+brew install automake cmake libdeflate ninja
brew unlink xz
# build liblzma and libdeflate for deployment target
=====================================
cyvcf2/__init__.py
=====================================
@@ -1,5 +1,4 @@
+from ._version import __version__
from .cyvcf2 import (VCF, Variant, Writer, r_ as r_unphased, par_relatedness,
par_het)
Reader = VCFReader = VCF
-
-__version__ = "0.32.0"
=====================================
cyvcf2/_version.py
=====================================
@@ -0,0 +1 @@
+__version__ = "0.34.0"
=====================================
cyvcf2/cyvcf2.pxd
=====================================
@@ -3,6 +3,9 @@ import numpy as np
cimport numpy as np
np.import_array()
+cdef extern from "htslib/hts_log.h":
+ void hts_set_log_level(int val)
+
cdef extern from "string.h":
void* memcpy(void* dest, const void* src, size_t n)
=====================================
cyvcf2/cyvcf2.pyx
=====================================
@@ -30,6 +30,47 @@ from cython cimport view
from cpython.version cimport PY_MAJOR_VERSION
+def set_htslib_log_level(int level):
+ """
+ Set htslib log level.
+
+ Parameters:
+ level (int): The desired log level. Per htslib's documentation (https://www.htslib.org/doc/samtools.html), the following values are supported:
+ - 0 or 1: Suppress some error messages.
+ - 2: Reduce warning messages.
+ - 3: Default level (HTS_LOG_WARNING).
+ - >3: Increase verbosity with additional warnings and logging messages.
+ """
+ hts_set_log_level(level)
+
+
+def _init_logging_from_env():
+ """
+ If a valid CYVCF2_HTSLIB_LOG_LEVEL environment variable exists, use it to set htslib log level.
+ Otherwise use the htslib default: 3 (HTS_LOG_WARNING).
+ """
+ HTSLIB_DEFAULT = 3
+
+ s = stdlib.getenv("CYVCF2_HTSLIB_LOG_LEVEL")
+ if s is NULL:
+ set_htslib_log_level(HTSLIB_DEFAULT)
+ return
+
+ py_s = s.decode()
+ try:
+ level = int(py_s)
+ if level < 0:
+ warnings.warn(f"CYVCF2_HTSLIB_LOG_LEVEL={py_s!r} is not a non-negative integer; using htslib default")
+ level = HTSLIB_DEFAULT
+ except (ValueError, TypeError):
+ warnings.warn(f"CYVCF2_HTSLIB_LOG_LEVEL={py_s!r} is not a valid integer; using htslib default")
+ level = HTSLIB_DEFAULT
+
+ set_htslib_log_level(level)
+
+_init_logging_from_env()
+
+
# overcome lack of __file__ in cython
import inspect
if not hasattr(sys.modules[__name__], '__file__'):
=====================================
cyvcf2/helpers.h
=====================================
@@ -1,4 +1,5 @@
#include <htslib/vcf.h>
+#include <htslib/hts_log.h>
#include <htslib/khash.h>
int as_gts(int *gts, int num_samples, int ploidy, int strict_gt, int HOM_ALT, int UNKNOWN);
=====================================
cyvcf2/tests/test.warnings.vcf.gz
=====================================
Binary files /dev/null and b/cyvcf2/tests/test.warnings.vcf.gz differ
=====================================
cyvcf2/tests/test.warnings.vcf.gz.tbi
=====================================
Binary files /dev/null and b/cyvcf2/tests/test.warnings.vcf.gz.tbi differ
=====================================
cyvcf2/tests/test_cli.py
=====================================
@@ -1,16 +1,72 @@
+import os
from cyvcf2 import VCF
-import os.path
-
from click.testing import CliRunner
-
from cyvcf2.cli import cyvcf2
+from cyvcf2.cyvcf2 import set_htslib_log_level, _init_logging_from_env
HERE = os.path.dirname(__file__)
VCF_PATH = os.path.join(HERE, "test.vcf.gz")
+VCF_WITH_WARNINGS_PATH = os.path.join(HERE, "test.warnings.vcf.gz")
-#Sanity check for cli
+# Sanity check for cli
def test_version():
runner = CliRunner()
result = runner.invoke(cyvcf2, [VCF_PATH])
assert result.exit_code == 0
+
+
+def test_htslib_log_level(capfd):
+ runner = CliRunner()
+
+ for log_level in [4, 5]:
+ set_htslib_log_level(log_level)
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" in captured.err
+ assert "[I::hts_idx_check_local" in captured.err
+
+ set_htslib_log_level(3)
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" in captured.err
+ assert "[I::hts_idx_check_local" not in captured.err
+
+ for log_level in [0, 1, 2]:
+ set_htslib_log_level(log_level)
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" not in captured.err
+ assert "[I::hts_idx_check_local" not in captured.err
+
+
+def test_htslib_log_level_env(monkeypatch, capfd):
+ runner = CliRunner()
+
+ monkeypatch.setenv("CYVCF2_HTSLIB_LOG_LEVEL", "5")
+ _init_logging_from_env()
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" in captured.err
+ assert "[I::hts_idx_check_local" in captured.err
+
+ monkeypatch.setenv("CYVCF2_HTSLIB_LOG_LEVEL", "3")
+ _init_logging_from_env()
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" in captured.err
+ assert "[I::hts_idx_check_local" not in captured.err
+
+ monkeypatch.setenv("CYVCF2_HTSLIB_LOG_LEVEL", "0")
+ _init_logging_from_env()
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" not in captured.err
+ assert "[I::hts_idx_check_local" not in captured.err
+
+ monkeypatch.delenv("CYVCF2_HTSLIB_LOG_LEVEL", raising=False)
+ _init_logging_from_env()
+ _ = runner.invoke(cyvcf2, [VCF_WITH_WARNINGS_PATH])
+ captured = capfd.readouterr()
+ assert "[W::vcf_parse_format" in captured.err
+ assert "[I::hts_idx_check_local" not in captured.err
=====================================
pyproject.toml
=====================================
@@ -1,10 +1,85 @@
[build-system]
requires = [
- "setuptools",
- "wheel",
- 'cython>=0.23.3,<3; python_version < "3.9"',
- 'cython>=3; python_version >= "3.9"',
- 'oldest-supported-numpy; os_name != "nt" and python_version < "3.9"',
- 'numpy; os_name == "nt" and python_version < "3.9"',
- 'numpy>=2.0.0; python_version >= "3.9"',
+ "scikit-build-core>=0.11",
+ "cython>=3",
+ "numpy>=2.0.0",
]
+build-backend = "scikit_build_core.build"
+
+[project]
+name = "cyvcf2"
+dynamic = ["version"]
+description = "fast vcf parsing with cython + htslib"
+readme = "README.md"
+requires-python = ">=3.9"
+license = { text = "MIT" }
+authors = [
+ { name = "Brent Pedersen", email = "bpederse at gmail.com" },
+]
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Science/Research",
+ "Operating System :: POSIX :: Linux",
+ "Operating System :: MacOS",
+ "Operating System :: Microsoft :: Windows",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
+ "Programming Language :: Cython",
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
+]
+dependencies = [
+ "numpy>=2.0.0",
+ "coloredlogs",
+ "click",
+]
+
+[project.urls]
+Homepage = "https://github.com/brentp/cyvcf2/"
+Documentation = "https://brentp.github.io/cyvcf2/"
+
+[project.scripts]
+cyvcf2 = "cyvcf2.__main__:cli"
+
+[tool.scikit-build]
+wheel.packages = ["cyvcf2"]
+wheel.exclude = [
+ "cyvcf2/tests/**",
+ "cyvcf2/*.c",
+ "cyvcf2/*.h",
+ "cyvcf2/*.pxd",
+ "cyvcf2/*.pyx",
+]
+sdist.cmake = true
+sdist.include = [
+ "CMakeLists.txt",
+ "htslib/htscodecs/htscodecs/version.h",
+]
+sdist.exclude = [
+ "cyvcf2/tests/**",
+ "htslib/test/**",
+ "htslib/htscodecs/tests/**",
+ "htslib/htscodecs/javascript/**",
+ "htslib/config.status",
+ "htslib/config.mk",
+ "htslib/htscodecs.mk",
+ "htslib/*.o",
+ "htslib/**/*.o",
+ "htslib/*.a",
+ "htslib/*.so",
+ "htslib/*.dylib",
+ "htslib/*.dll",
+]
+
+[tool.scikit-build.metadata.version]
+provider = "scikit_build_core.metadata.regex"
+input = "cyvcf2/_version.py"
+
+[tool.pytest.ini_options]
+testpaths = ["cyvcf2/tests"]
=====================================
requirements.txt
=====================================
@@ -1,8 +1,5 @@
-cython>=0.23.3,<3; python_version < "3.9"
-cython>=3; python_version >= "3.9"
+cython>=3
coloredlogs
click
setuptools
-oldest-supported-numpy; os_name != "nt" and python_version < "3.9"
-numpy; os_name == "nt" and python_version < "3.9"
-numpy>=2.0.0; python_version >= "3.9"
+numpy>=2.0.0
=====================================
setup.cfg deleted
=====================================
@@ -1,2 +0,0 @@
-[tool:pytest]
-testpaths = cyvcf2/tests
=====================================
setup.py deleted
=====================================
@@ -1,302 +0,0 @@
-import ctypes
-import glob
-import os
-import platform
-import shutil
-import sys
-import subprocess
-
-from setuptools import setup, Extension, Command
-from setuptools.command.build_ext import build_ext
-from setuptools.command.sdist import sdist
-
-if sys.version_info.major == 2 and sys.version_info.minor != 7:
- sys.stderr.write(
- "ERROR: cyvcf2 is only for python 2.7 or greater you are running %d.%d\n",
- (sys.version_info.major, sys.version_info.minor),
- )
- sys.exit(1)
-
-import numpy as np
-
-
-def get_version():
- """Get the version info from the mpld3 package without importing it"""
- import ast
-
- with open(os.path.join("cyvcf2", "__init__.py"), "r") as init_file:
- module = ast.parse(init_file.read())
-
- version = (
- ast.literal_eval(node.value)
- for node in ast.walk(module)
- if isinstance(node, ast.Assign) and node.targets[0].id == "__version__"
- )
- try:
- return next(version)
- except StopIteration:
- raise ValueError("version could not be located")
-
-
-def no_cythonize(extensions, **_ignore):
- for extension in extensions:
- sources = []
- for sfile in extension.sources:
- path, ext = os.path.splitext(sfile)
- if ext in (".pyx", ".py"):
- sfile = path + ".c"
- sources.append(sfile)
- extension.sources[:] = sources
- return extensions
-
-
-def check_libhts():
- os_type = platform.system()
- if os_type == "Linux":
- lib_name = "libhts.so"
- elif os_type == "Darwin": # macOS
- lib_name = "libhts.dylib"
- elif os_type == "Windows":
- lib_name = "hts-3.dll"
- else:
- return False # Unsupported OS
-
- try:
- ctypes.CDLL(lib_name)
- return True
- except Exception:
- return False
-
-
-def build_htslib(htslib_configure_options, static_mode):
- current_directory = os.getcwd()
- os.chdir(os.path.join(current_directory, "htslib"))
-
- if os.path.exists("config.status"):
- print("# cyvcf2: config.status exists, skip configure htslib")
- else:
- subprocess.run(["autoreconf", "-i"], check=True)
-
- configure_args = ["./configure"]
- if static_mode:
- configure_args.append("CFLAGS=-fPIC")
- if htslib_configure_options:
- configure_args.extend(htslib_configure_options.split())
-
- subprocess.run(configure_args, check=True)
- subprocess.run(["make"], check=True)
-
- os.chdir(current_directory)
-
-
-def pre_sdist():
- current_directory = os.getcwd()
- os.chdir(os.path.join(current_directory, "htslib"))
-
- # generate version.h
- subprocess.run(["make", "htscodecs/htscodecs/version.h"], check=True)
-
- # remove redundant file
- redudant_files = ["htscodecs.mk"]
- for redudant_file in redudant_files:
- if os.path.exists(redudant_file):
- os.remove(redudant_file)
-
- os.chdir(current_directory)
-
-
-class cyvcf2_build_ext(build_ext):
- def run(self):
- print("# cyvcf2: htslib mode is {}".format(CYVCF2_HTSLIB_MODE))
- if CYVCF2_HTSLIB_MODE == "BUILTIN" or not check_libhts():
- if platform.system() == "Windows":
- # Windows htslib can't be built internall
- raise RuntimeError(
- "Required library 'hts-3.dll' not found. Please install htslib first."
- )
-
- print(
- "# cyvcf2: htslib configure options is {}".format(
- CYVCF2_HTSLIB_CONFIGURE_OPTIONS
- )
- )
- build_htslib(
- CYVCF2_HTSLIB_CONFIGURE_OPTIONS, CYVCF2_HTSLIB_MODE == "BUILTIN"
- )
-
- if CYVCF2_HTSLIB_MODE == "BUILTIN":
- # add htslib linked libraries
- # libcrypto is bundled with libssl, capabale to replace libssl
- all_dynamic_libs = {
- "z",
- "bz2",
- "lzma",
- "curl",
- "deflate",
- "crypto",
- }
-
- extra_libs = []
- # read the htslib config.status file to get the linked libraries
- with open(os.path.join("htslib", "config.status"), "r") as f:
- for line in f:
- if 'S["static_LIBS"]' in line:
- linked_libs_str = line.split("=")[1].strip()[1:-1]
- print("# cyvcf2: htslib librarys is {}".format(linked_libs_str))
- linked_libs = linked_libs_str.split()
- for lib in linked_libs:
- if lib[2:] in all_dynamic_libs: # remove -l prefix
- extra_libs.append(lib[2:])
-
- self.extensions[0].libraries = self.extensions[0].libraries + extra_libs
-
- super().run()
-
-
-class cyvcf2_sdist(sdist):
- def run(self):
- if platform.system() == "Windows":
- raise RuntimeError("cyvcf2 Can't build sdist on Windows")
-
- pre_sdist()
-
- super().run()
-
-
-class clean_ext(Command):
- description = "clean up Cython temporary files and htslib build files"
- user_options = []
-
- def initialize_options(self):
- pass
-
- def finalize_options(self):
- pass
-
- def run(self):
- print("cleaning build files")
- if os.path.exists("build"):
- shutil.rmtree("build")
-
- if os.path.exists("cyvcf2.egg-info"):
- shutil.rmtree("cyvcf2.egg-info")
-
- print("cleaning Cython temporary files")
- cyvcf2_c_path = os.path.join("cyvcf2", "cyvcf2.c")
- if os.path.exists(cyvcf2_c_path):
- os.remove(cyvcf2_c_path)
-
- lib_files = glob.glob("cyvcf2/cyvcf2.cpython-*")
- for file in lib_files:
- os.remove(file)
-
- if platform.system() != "Windows":
- print("cleaning htslib build files")
- current_directory = os.getcwd()
- os.chdir(os.path.join(current_directory, "htslib"))
- subprocess.run(["make", "distclean"], check=True)
- os.chdir(current_directory)
-
-
-# How to link against HTSLIB
-# BUILTIN: build and static link against htslib from
-# builtin htslib code (default)
-# EXTERNAL: use shared libhts.so compiled outside of
-# cyvcf2
-if platform.system() == "Windows":
- # can't static link to htslib on Windows
- htslib_mode_default = "EXTERNAL"
-else:
- htslib_mode_default = "BUILTIN"
-
-CYVCF2_HTSLIB_MODE = os.environ.get("CYVCF2_HTSLIB_MODE", htslib_mode_default)
-
-if platform.system() == "Windows" and CYVCF2_HTSLIB_MODE == "BUILTIN":
- print(
- "# cyvcf2 WARNING: The use of cyvcf2 on Windows is experimental. It will not work when statically linked to htslib. Fallback to htslib EXTERNAL mode"
- )
- CYVCF2_HTSLIB_MODE = "EXTERNAL"
-
-CYVCF2_HTSLIB_CONFIGURE_OPTIONS = os.environ.get(
- "CYVCF2_HTSLIB_CONFIGURE_OPTIONS", None
-)
-
-htslib_objects = []
-htslib_librarys = []
-htslib_library_dirs = []
-
-if CYVCF2_HTSLIB_MODE == "BUILTIN":
- htslib_objects = ["htslib/libhts.a"]
-else:
- htslib_librarys = ["hts"]
- if not check_libhts():
- htslib_library_dirs = ["htslib"]
-
-htslib_include_dirs = ["htslib", "htslib/htslib"]
-
-# Build the Cython extension by statically linking to the bundled htslib
-sources = ["cyvcf2/cyvcf2.pyx", "cyvcf2/helpers.c"]
-
-extensions = [
- Extension(
- "cyvcf2.cyvcf2",
- sources,
- extra_objects=htslib_objects,
- libraries=htslib_librarys,
- extra_compile_args=[
- "-Wno-sign-compare",
- "-Wno-unused-function",
- "-Wno-strict-prototypes",
- "-Wno-unused-result",
- "-Wno-discarded-qualifiers",
- ],
- include_dirs=["cyvcf2", np.get_include()] + htslib_include_dirs,
- library_dirs=htslib_library_dirs,
- )
-]
-
-
-CYTHONIZE = bool(int(os.getenv("CYTHONIZE", 0)))
-if CYTHONIZE:
- try:
- from Cython.Build import cythonize
- except ImportError:
- sys.stderr.write(
- "Cannot find Cython. Have you installed all the requirements?\n"
- "Try pip install -r requirements.txt\n"
- )
- sys.exit(1)
- compiler_directives = {"language_level": 2, "embedsignature": True}
- extensions = cythonize(extensions, compiler_directives=compiler_directives)
-else:
- extensions = no_cythonize(extensions)
-
-
-setup(
- name="cyvcf2",
- description="fast vcf parsing with cython + htslib",
- long_description_content_type="text/markdown",
- url="https://github.com/brentp/cyvcf2/",
- long_description=open("README.md").read(),
- license="MIT",
- author="Brent Pedersen",
- author_email="bpederse at gmail.com",
- version=get_version(),
- ext_modules=extensions,
- packages=["cyvcf2"],
- entry_points=dict(
- console_scripts=[
- "cyvcf2 = cyvcf2.__main__:cli",
- ],
- ),
- python_requires=">=3.7",
- # make sure to keep this numpy version in sync with build.yml
- install_requires=["numpy>=1.16.0", "coloredlogs", "click"],
- include_package_data=True,
- zip_safe=False,
- cmdclass={
- "clean_ext": clean_ext,
- "build_ext": cyvcf2_build_ext,
- "sdist": cyvcf2_sdist,
- },
-)
View it on GitLab: https://salsa.debian.org/med-team/cyvcf2/-/commit/7960b5282c3059a952e56351f239cb95ea2d639e
--
View it on GitLab: https://salsa.debian.org/med-team/cyvcf2/-/commit/7960b5282c3059a952e56351f239cb95ea2d639e
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260921/afee29a3/attachment-0001.htm>
More information about the debian-med-commit
mailing list