[med-svn] [Git][med-team/cyvcf2][master] 10 commits: New upstream version 0.30.11
Nilesh Patra (@nilesh)
gitlab at salsa.debian.org
Sat Dec 18 08:31:17 GMT 2021
Nilesh Patra pushed to branch master at Debian Med / cyvcf2
Commits:
fce26697 by Nilesh Patra at 2021-08-08T17:00:49+05:30
New upstream version 0.30.11
- - - - -
cbfe78b6 by Nilesh Patra at 2021-12-18T13:34:23+05:30
d/watch: Fix broken regex in watch file
- - - - -
c6bc65e7 by Nilesh Patra at 2021-12-18T13:34:36+05:30
New upstream version 0.30.14
- - - - -
63781a2a by Nilesh Patra at 2021-12-18T13:34:37+05:30
Update upstream source from tag 'upstream/0.30.14'
Update to upstream version '0.30.14'
with Debian dir 3627f390eb6ca8b778c00d2e2de59cbe12a44411
- - - - -
520a7d8f by Nilesh Patra at 2021-12-18T13:42:21+05:30
Drop d/p/python-3.10.patch, merged upstream
- - - - -
35366c45 by Nilesh Patra at 2021-12-18T13:55:23+05:30
Rediff and refresh patches
- - - - -
4481a480 by Nilesh Patra at 2021-12-18T13:55:23+05:30
Upstream has switched to pytest
- - - - -
e60d363c by Nilesh Patra at 2021-12-18T13:55:23+05:30
Bump Standards-Version to 4.6.0 (no changes needed)
- - - - -
33aa4333 by Nilesh Patra at 2021-12-18T13:55:23+05:30
d/copyright: s/MIT/Expat/
- - - - -
bebf5620 by Nilesh Patra at 2021-12-18T13:56:21+05:30
Upload to unstable
- - - - -
27 changed files:
- .github/workflows/build.yml
- .github/workflows/wheels.yml
- CHANGES.md
- README.md
- ci/linux-deps
- ci/osx-deps
- cyvcf2/__init__.py
- cyvcf2/cyvcf2.pxd
- cyvcf2/cyvcf2.pyx
- cyvcf2/helpers.c
- cyvcf2/helpers.h
- + cyvcf2/tests/test-genotypes.vcf
- cyvcf2/tests/test_hemi.py
- cyvcf2/tests/test_reader.py
- debian/changelog
- debian/control
- debian/copyright
- debian/patches/add_htslib_link_dependency.patch
- debian/patches/i386.patch
- − debian/patches/python-3.10.patch
- debian/patches/series
- debian/tests/control
- debian/tests/run-unit-test
- debian/watch
- docs/source/index.rst
- setup.cfg
- setup.py
Changes:
=====================================
.github/workflows/build.yml
=====================================
@@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-18.04
strategy:
matrix:
- python-version: [3.6, 3.7, 3.8, 3.9]
+ python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
steps:
- uses: actions/checkout at v2
@@ -23,14 +23,14 @@ jobs:
sudo apt-get update
sudo apt-get install libcurl4-openssl-dev
pip install -r requirements.txt
- pip install nose
+ pip install pytest pytest-cov
cd htslib
autoheader && autoconf
./configure --enable-s3 --disable-lzma --disable-bz2
make
cd ..
- CYTHONIZE=1 python setup.py install
+ CYTHONIZE=1 python setup.py build_ext -i
- name: Test
run: |
- python setup.py test
+ pytest --cov cyvcf2 --cov-report term-missing
=====================================
.github/workflows/wheels.yml
=====================================
@@ -32,29 +32,36 @@ jobs:
- name: Install cibuildwheel
run: |
- python -m pip install cibuildwheel
+ python -m pip install -U cibuildwheel
- name: Build wheels for Linux
if: matrix.os == 'ubuntu-18.04'
run: |
python -m cibuildwheel --output-dir wheelhouse
env:
- CIBW_SKIP: "pp* cp27-* cp34-* cp35-* *i686*"
+ CIBW_SKIP: "pp* *i686* *musllinux*"
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_BEFORE_BUILD_LINUX: "{project}/ci/linux-deps"
CIBW_TEST_COMMAND: "{project}/ci/test"
- CIBW_ENVIRONMENT: "CYTHONIZE=1 LDFLAGS='-L/usr/lib64/openssl11' CPPFLAGS='-I/usr/include/openssl11' C_INCLUDE_PATH='/root/include' LIBRARY_PATH='/root/lib'"
+ CIBW_ENVIRONMENT: "CYTHONIZE=1 LIBDEFLATE=1 LDFLAGS='-L/usr/lib64/openssl11' CPPFLAGS='-I/usr/include/openssl11' C_INCLUDE_PATH='/root/include' LIBRARY_PATH='/root/lib'"
+ CIBW_REPAIR_WHEEL_COMMAND_LINUX: LD_LIBRARY_PATH='/root/lib' auditwheel repair -w {dest_dir} {wheel}
- name: Build wheels for Mac OS
if: matrix.os == 'macos-latest'
run: |
python -m cibuildwheel --output-dir wheelhouse
env:
- CIBW_SKIP: "pp* cp27-* cp34-* cp35-* *i686*"
+ CIBW_SKIP: "pp* cp310-* *i686*"
+ CIBW_ARCHS_MACOS: "x86_64 arm64"
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_BEFORE_BUILD_MACOS: "{project}/ci/osx-deps"
CIBW_TEST_COMMAND: "{project}/ci/test"
- CIBW_ENVIRONMENT: "CYTHONIZE=1"
+ CIBW_TEST_SKIP: "*-macosx_arm64"
+ CIBW_ENVIRONMENT: "CYTHONIZE=1 LIBDEFLATE=1 C_INCLUDE_PATH='/usr/local/include' LIBRARY_PATH='/usr/local/lib'"
+ # https://cibuildwheel.readthedocs.io/en/stable/faq/#macos-passing-dyld_library_path-to-delocate
+ CIBW_REPAIR_WHEEL_COMMAND_MACOS: >
+ DYLD_LIBRARY_PATH=/usr/local/lib delocate-listdeps {wheel} &&
+ DYLD_LIBRARY_PATH=/usr/local/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}
LDFLAGS: "-L/usr/local/opt/openssl at 1.1/lib"
CPPFLAGS: "-I/usr/local/opt/openssl at 1.1/include"
PKG_CONFIG_PATH: "/usr/local/opt/openssl at 1.1/lib/pkgconfig"
=====================================
CHANGES.md
=====================================
@@ -1,3 +1,17 @@
+# v0.30.14
++ use warnings instead of sys.stderr (#229 from @grahamgower)
++ use libdeflate in wheel build (#231 from @grahamgower)
++ use pytest instead of nose and update numpy stuff (#232 from @grahamgower)
+
+# v0.30.13
++ fixes for mixed ploidy samples affecting `variant.num_het`,
+ `variant.num_hom_ref`, etc. Also affects `variant.genotypes` and
+ `variant.genotype` (see #227. Thanks @davmlaw and @grahamgower for
+ test-cases and insight.)
+
+# v0.30.12
++ add variant.FILTERS (by @tomwhite, #149)
+
# v0.30.11
+ bump for CI
=====================================
README.md
=====================================
@@ -107,10 +107,10 @@ For pkg-config to find openssl you may need to set:
Testing
=======
-Tests can be run with:
+Install `pytest`, then tests can be run with:
```
-python setup.py test
+pytest
```
CLI
=====================================
ci/linux-deps
=====================================
@@ -29,6 +29,13 @@ make install
cd ..
rm -rf curl-7.73.0
+curl -L -o libdeflate-v1.8.tar.gz https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.8.tar.gz
+tar xzf libdeflate-v1.8.tar.gz
+cd libdeflate-1.8
+make
+make install PREFIX=/root
+cd ..
+
cd htslib
# configure fails with autoconf 2.71 (in /usr/local/bin), so use 2.69 (in /usr/bin)
/usr/bin/autoconf -V
=====================================
ci/osx-deps
=====================================
@@ -13,6 +13,13 @@ brew install autoconf at 2.69 && \
brew link --overwrite autoconf at 2.69 && \
autoconf -V
+curl -L -o libdeflate-v1.8.tar.gz https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.8.tar.gz
+tar xzf libdeflate-v1.8.tar.gz
+cd libdeflate-1.8
+make
+make install
+cd ..
+
cd htslib
autoheader
autoconf
=====================================
cyvcf2/__init__.py
=====================================
@@ -2,4 +2,4 @@ from .cyvcf2 import (VCF, Variant, Writer, r_ as r_unphased, par_relatedness,
par_het)
Reader = VCFReader = VCF
-__version__ = "0.30.11"
+__version__ = "0.30.14"
=====================================
cyvcf2/cyvcf2.pxd
=====================================
@@ -13,8 +13,7 @@ cdef extern from "relatedness.h":
int32_t n_samples, double *ab)
cdef extern from "helpers.h":
- int as_gts(int32_t *gts, int num_samples, int ploidy, int strict_gt);
- int as_gts012(int32_t *gts, int num_samples, int ploidy, int strict_gt);
+ int as_gts(int32_t *gts, int num_samples, int ploidy, int strict_gt, int HOM_ALT, int UNKNOWN);
int32_t* bcf_hdr_seqlen(const bcf_hdr_t *hdr, int32_t *nseq)
cdef extern from "htslib/kstring.h":
=====================================
cyvcf2/cyvcf2.pyx
=====================================
@@ -12,6 +12,7 @@ import numpy as np
from array import array
import math
import ctypes
+import warnings
try:
from pathlib import Path
except ImportError:
@@ -350,12 +351,12 @@ cdef class VCF(HTSFile):
ret = bcf_hdr_set_samples(self.hdr, <const char *>samples, 0)
assert ret >= 0, ("error setting samples", ret)
+ self.n_samples = bcf_hdr_nsamples(self.hdr)
if ret != 0 and samples != "-":
s = from_bytes(samples).split(",")
- if ret < len(s):
- sys.stderr.write("warning: not all requested samples found in VCF\n")
+ if self.n_samples < len(s):
+ warnings.warn("not all requested samples found in VCF")
- self.n_samples = bcf_hdr_nsamples(self.hdr)
def update(self, id, type, number, description):
"""Update the header with an INFO field of the given parameters.
@@ -400,7 +401,7 @@ cdef class VCF(HTSFile):
itr = bcf_itr_querys(self.hidx, self.hdr, to_bytes(region))
if itr == NULL:
- sys.stderr.write("no intervals found for %s at %s\n" % (self.fname, region))
+ warnings.warn("no intervals found for %s at %s" % (self.fname, region))
raise StopIteration
try:
while True:
@@ -409,10 +410,8 @@ cdef class VCF(HTSFile):
if ret < 0:
bcf_destroy(b)
break
- if bcf_subset_format(self.hdr, b) != 0:
- sys.stderr.write("could not subset variant")
- bcf_destroy(b)
- break
+ ret = bcf_subset_format(self.hdr, b)
+ assert ret == 0, ("could not subset variant", self.fname, region)
yield newVariant(b, self)
finally:
if itr != NULL:
@@ -454,7 +453,7 @@ cdef class VCF(HTSFile):
itr = tbx_itr_querys(self.idx, cregion)
if itr == NULL:
- sys.stderr.write("no intervals found for %s at %s\n" % (self.fname, region))
+ warnings.warn("no intervals found for %s at %s" % (self.fname, region))
raise StopIteration
try:
@@ -905,7 +904,7 @@ cdef class VCF(HTSFile):
nv += 1
if nv == n_variants:
break
- sys.stderr.write("tested: %d variants out of %d\n" % (nv, nvt))
+ warnings.warn("tested: %d variants out of %d" % (nv, nvt))
return self._relatedness_finish(ibs, n, hets)
cdef dict _relatedness_finish(self,
@@ -929,7 +928,7 @@ cdef class VCF(HTSFile):
for sj in range(ns):
sample_j = samples[sj]
if _hets[sj] == 0:
- print("peddy: no hets found for sample %s\n" % sample_j, file=sys.stderr)
+ warnings.warn("peddy: no hets found for sample %s" % sample_j)
for sk in range(sj, ns):
if sj == sk: continue
sample_k = samples[sk]
@@ -1024,9 +1023,13 @@ cdef class Genotypes(object):
cdef int32_t v
for j in range(self.ploidy):
v = self._raw[i * self.ploidy + j]
- result.append((v >> 1) - 1)
+ if v != bcf_int32_vector_end:
+ result.append((v >> 1) - 1)
return result
+ def __repr__(self):
+ return str(self.array())
+
def array(Genotypes self, int fill=-2):
"""
array returns an int16 numpy array of shape n_samples, (ploidy + 1).
@@ -1171,7 +1174,7 @@ cdef class Variant(object):
if a >= -1 and b >= -1:
bases[j] = d[a] + lookup[phased[j]] + d[b]
else:
- bases[j] = d[a]
+ bases[j] = d[max(-1, a)]
elif n == 1:
bases[j] = d[self._gt_idxs[i]]
else:
@@ -1351,9 +1354,10 @@ cdef class Variant(object):
if self.vcf.n_samples == 0: return None
cdef int32_t *gts = NULL
cdef int ndst = 0
- if bcf_get_genotypes(self.vcf.hdr, self.b, >s, &ndst) <= 0:
+ cdef int nret = bcf_get_genotypes(self.vcf.hdr, self.b, >s, &ndst)
+ if nret < 0:
raise Exception("couldn't get genotypes for variant")
- return newGenotypes(gts, int(ndst/self.vcf.n_samples), self.vcf.n_samples)
+ return newGenotypes(gts, int(nret/self.vcf.n_samples), self.vcf.n_samples)
@genotype.setter
def genotype(self, Genotypes g):
@@ -1487,12 +1491,12 @@ cdef class Variant(object):
if self._gt_types == NULL:
self._gt_phased = <int *>stdlib.malloc(sizeof(int) * self.vcf.n_samples)
ngts = bcf_get_genotypes(self.vcf.hdr, self.b, &self._gt_types, &ndst)
- nper = int(ndst / self.vcf.n_samples)
+ nper = int(ngts / self.vcf.n_samples)
self._ploidy = nper
self._gt_idxs = <int *>stdlib.malloc(sizeof(int) * self.vcf.n_samples * nper)
- if ndst == 0 or nper == 0:
+ if ngts == 0 or nper == 0:
return np.array([])
- for i in range(0, ndst, nper):
+ for i in range(0, ngts, nper):
for k in range(i, i + nper):
a = self._gt_types[k]
if a >= 0:
@@ -1504,9 +1508,9 @@ cdef class Variant(object):
j += 1
if self.vcf.gts012:
- n = as_gts012(self._gt_types, self.vcf.n_samples, nper, self.vcf.strict_gt)
+ n = as_gts(self._gt_types, self.vcf.n_samples, nper, self.vcf.strict_gt, 2, 3)
else:
- n = as_gts(self._gt_types, self.vcf.n_samples, nper, self.vcf.strict_gt)
+ n = as_gts(self._gt_types, self.vcf.n_samples, nper, self.vcf.strict_gt, 3, 2)
cdef np.npy_intp shape[1]
shape[0] = <np.npy_intp> self.vcf.n_samples
return np.PyArray_SimpleNewFromData(1, shape, np.NPY_INT32, self._gt_types)
@@ -1700,8 +1704,8 @@ cdef class Variant(object):
def __get__(self):
if self.vcf.n_samples == 0:
return []
- t = np.array(self.gt_depths, np.float)
- a = np.array(self.gt_alt_depths, np.float)
+ t = np.array(self.gt_depths, float)
+ a = np.array(self.gt_alt_depths, float)
# for which samples are the alt or total depths unknown?
tU = t < 0
@@ -1893,9 +1897,7 @@ cdef class Variant(object):
new_rid = bcf_hdr_id2int(self.vcf.hdr, BCF_DT_CTG, new_chrom.encode())
if new_rid < 0:
raise ValueError("Unable to add {} to CHROM".format(new_chrom))
- sys.stderr.write(
- "[cyvcf2]: added new contig {} to header".format(new_chrom)
- )
+ warnings.warn("added new contig {} to header".format(new_chrom))
self.b.rid = new_rid
property var_type:
@@ -1995,6 +1997,16 @@ cdef class Variant(object):
if ret != 0:
raise Exception("not able to set filter: %s", filters)
+ property FILTERS:
+ """the FILTER values as a list from the VCF field.
+
+ a value '.' in the VCF will return an empty list for this property
+ """
+ def __get__(self):
+ cdef int i
+ cdef int n = self.b.d.n_flt
+ return [from_bytes(bcf_hdr_int2id(self.vcf.hdr, BCF_DT_ID, self.b.d.flt[i])) for i in range(n)]
+
property QUAL:
"the float value of QUAL from the VCF field."
def __get__(self):
@@ -2246,7 +2258,8 @@ cdef inline Variant newVariant(bcf1_t *b, VCF vcf):
v.vcf = vcf
v.POS = v.b.pos + 1
cdef INFO i = INFO.__new__(INFO)
- i.b, i.hdr = b, vcf.hdr
+ i.b = b
+ i.hdr = vcf.hdr
v.INFO = i
return v
=====================================
cyvcf2/helpers.c
=====================================
@@ -1,34 +1,37 @@
#include <helpers.h>
-int as_gts(int32_t *gts, int num_samples, int ploidy, int strict_gt) {
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+
+int as_gts(int32_t *gts, int num_samples, int ploidy, int strict_gt, int HOM_ALT, int UNKNOWN) {
int j = 0, i, k;
- int missing= 0;
+ int missing= 0, found=0;
for (i = 0; i < ploidy * num_samples; i += ploidy){
- missing = 0;
- for (k = 0; k < ploidy; k++) {
- if (gts[i+k] <= 1) {
- missing += 1;
- }
- }
- if (missing == ploidy) {
- gts[j++] = 2; // unknown
- continue;
- } else if ( (missing != 0) && (strict_gt == 1) ) {
- gts[j++] = 2; // unknown
- continue;
- }
+ missing = 0;
+ found = 0;
+ for (k = 0; k < ploidy; k++) {
+ if bcf_gt_is_missing(gts[i+k]) {
+ missing += 1;
+ }
+ }
+ if (missing == ploidy) {
+ gts[j++] = UNKNOWN; // unknown
+ continue;
+ } else if ( (missing != 0) && (strict_gt == 1) ) {
+ gts[j++] = UNKNOWN; // unknown
+ continue;
+ }
- if(ploidy == 1) {
- int a = bcf_gt_allele(gts[i]);
- if (a == 0) {
- gts[j++] = 0;
- } else if (a == 1) {
- gts[j++] = 3;
- } else {
- gts[j++] = 2;
- }
- continue;
- }
+ if(ploidy == 1 || gts[i+1] == bcf_int32_vector_end) {
+ int a = bcf_gt_allele(gts[i]);
+ if (a == 0) {
+ gts[j++] = 0;
+ } else if (a == 1) {
+ gts[j++] = HOM_ALT;
+ } else {
+ gts[j++] = UNKNOWN;
+ }
+ continue;
+ }
int a = bcf_gt_allele(gts[i]);
int b = bcf_gt_allele(gts[i+1]);
@@ -44,78 +47,21 @@ int as_gts(int32_t *gts, int num_samples, int ploidy, int strict_gt) {
continue;
}
else if((a == 1) && (b == 1)) {
- gts[j] = 3; // HOM_ALT
+ gts[j] = HOM_ALT; // HOM_ALT
}
else if((a != b)) {
gts[j] = 1; // HET
}
else if((a == b)) {
- gts[j] = 3; // HOM_ALT
+ gts[j] = HOM_ALT; // HOM_ALT
} else {
- gts[j] = 2; // unknown
+ gts[j] = UNKNOWN; // unknown
}
j++;
}
return j;
}
-int as_gts012(int32_t *gts, int num_samples, int ploidy, int strict_gt) {
- int j = 0, i, k;
- int missing;
- for (i = 0; i < ploidy * num_samples; i += ploidy){
- missing = 0;
- for (k = 0; k < ploidy; k++) {
- if (gts[i+k] <= 1) {
- missing += 1;
- }
- }
- if (missing == ploidy) {
- gts[j++] = 3; // unknown
- continue;
- } else if ( (missing != 0) && (strict_gt == 1) ) {
- gts[j++] = 3; // unknown
- continue;
- }
-
- if(ploidy == 1) {
- int a = bcf_gt_allele(gts[i]);
- if (a == 0) {
- gts[j++] = 0;
- } else if (a == 1) {
- gts[j++] = 2;
- } else {
- gts[j++] = 3;
- }
- continue;
- }
-
- int a = bcf_gt_allele(gts[i]);
- int b = bcf_gt_allele(gts[i+1]);
-
- if((a == 0) && (b == 0)) {
- gts[j++] = 0; // HOM_REF
- continue;
- }
- if ((missing > 0) && ((a == 0) || b == 0)) {
- gts[j] = 0; // HOM_REF
- }
- else if((a == 1) && (b == 1)) {
- gts[j] = 2; // HOM_ALT
- }
- else if((a != b)) {
- gts[j] = 1; // HET
- }
- else if ((a == b)) {
- gts[j] = 2; // HOM_ALT
- } else {
- gts[j] = 3; // unknown
- }
- j++;
- }
- return j;
-}
-
-
KHASH_MAP_INIT_STR(vdict, bcf_idinfo_t)
typedef khash_t(vdict) vdict_t;
@@ -136,9 +82,9 @@ int32_t* bcf_hdr_seqlen(const bcf_hdr_t *hdr, int32_t *nseq)
int j;
if (lens[tid] > 0 && sscanf(kh_val(d, k).hrec[0]->vals[lens[tid]],"%d",&j) )
lens[tid] = j;
- if(lens[tid] > 0){
- found++;
- }
+ if(lens[tid] > 0){
+ found++;
+ }
}
*nseq = m;
// found is used to check that we actually got the lengths.
=====================================
cyvcf2/helpers.h
=====================================
@@ -1,6 +1,5 @@
#include <htslib/vcf.h>
#include <htslib/khash.h>
-int as_gts(int *gts, int num_samples, int ploidy, int strict_gt);
-int as_gts012(int *gts, int num_samples, int ploidy, int strict_gt);
+int as_gts(int *gts, int num_samples, int ploidy, int strict_gt, int HOM_ALT, int UNKNOWN);
int32_t* bcf_hdr_seqlen(const bcf_hdr_t *hdr, int32_t *nseq);
=====================================
cyvcf2/tests/test-genotypes.vcf
=====================================
@@ -0,0 +1,10 @@
+##fileformat=VCFv4.1
+##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
+##FORMAT=<ID=PL,Number=G,Type=Integer,Description="Normalized, Phred-scaled likelihoods for genotypes as defined in the VCF specification">
+##contig=<ID=1,length=249250621,assembly=b37>
+#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT samplea sampleb
+1 8466747 . A C . PASS . GT:PL .:. 1:36,0
+1 8466747 . A C . PASS . GT:PL ./.:. ./1:36,0,40
+1 8466747 . A T . PASS . GT:PL ./.:. 1:36,0
+1 8466747 . A T . PASS . GT 0/1 0
+1 8466747 . A T . PASS . GT 0 0/1
=====================================
cyvcf2/tests/test_hemi.py
=====================================
@@ -1,7 +1,6 @@
import numpy as np
from cyvcf2 import VCF, Variant, Writer
import os.path
-from nose.tools import assert_raises
HERE = os.path.dirname(__file__)
HEM_PATH = os.path.join(HERE, "test-hemi.vcf")
=====================================
cyvcf2/tests/test_reader.py
=====================================
@@ -1,8 +1,5 @@
from __future__ import print_function
-from ..cyvcf2 import VCF, Variant, Writer
-import numpy as np
import os.path
-from nose.tools import assert_raises
import tempfile
import sys
import os
@@ -11,6 +8,12 @@ try:
from pathlib import Path
except ImportError:
from pathlib2 import Path # python 2 backport
+import warnings
+
+import numpy as np
+import pytest
+
+from ..cyvcf2 import VCF, Variant, Writer
HERE = os.path.dirname(__file__)
@@ -87,11 +90,17 @@ def test_format_str():
def test_missing_samples():
samples = ['101976-101976', 'sample_not_in_vcf']
- vcf = VCF(VCF_PATH, gts012=True, samples=samples)
+ with warnings.catch_warnings(record=True) as w:
+ vcf = VCF(VCF_PATH, gts012=True, samples=samples)
+ assert len(w) == 1
+ assert "not all requested samples found" in str(w[-1].message)
assert len(vcf.samples) == 1
vcf.close()
samples = '101976-101976,sample_not_in_vcf'
- vcf = VCF(VCF_PATH, gts012=True, samples=samples)
+ with warnings.catch_warnings(record=True) as w:
+ vcf = VCF(VCF_PATH, gts012=True, samples=samples)
+ assert len(w) == 1
+ assert "not all requested samples found" in str(w[-1].message)
assert len(vcf.samples) == 1
def test_ibd():
@@ -104,7 +113,11 @@ def test_ibd():
def test_relatedness():
vcf = VCF(VCF_PATH, gts012=True)
- df = vcf.relatedness(gap=0, linkage_max=2)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("ignore", category=DeprecationWarning)
+ df = vcf.relatedness(gap=0, linkage_max=2)
+ assert len(w) == 1
+ assert "tested:" in str(w[-1].message)
assert "ibs0" in df, df
assert "rel" in df
#vcf = VCF(VCF_PATH, gts012=True)
@@ -202,7 +215,8 @@ def test_phases():
assert not any(v.gt_phases)
def test_bad_init():
- assert_raises(Exception, VCF, "XXXXX")
+ with pytest.raises(Exception):
+ VCF("XXXXX")
def test_samples():
v = VCF(VCF_PATH)
@@ -214,7 +228,8 @@ def test_next():
assert isinstance(variant, Variant)
def test_variant():
- assert_raises(TypeError, Variant)
+ with pytest.raises(TypeError):
+ Variant()
def test_info_dict():
v = VCF(VCF_PATH)
@@ -247,7 +262,8 @@ def test_attrs():
def test_empty():
p = os.path.join(HERE, "empty.vcf")
assert os.path.exists(p)
- assert_raises(IOError, VCF, p)
+ with pytest.raises(IOError):
+ VCF(p)
def test_format_field():
vcf = VCF(VCF_PATH)
@@ -269,7 +285,6 @@ def test_writer_from_string():
w.close()
def test_isa():
-
vcf = VCF(os.path.join(HERE, "test.isa.vcf"))
for i, v in enumerate(vcf):
if i in {0, 1, 2, 3}:
@@ -321,6 +336,36 @@ def test_writer():
with open(VCF_PATH) as fp:
run_writer(Writer(fp, v), f, rec)
+def test_filters():
+ v = VCF(VCF_PATH)
+ f = tempfile.mktemp(suffix=".vcf")
+ atexit.register(os.unlink, f)
+ rec = next(v)
+
+ writer = Writer(f, v)
+
+ rec.INFO["AC"] = "3"
+ rec.FILTER = ["LowQual"]
+ writer.write_record(rec)
+
+ rec.FILTER = ["LowQual", "VQSRTrancheSNP99.90to100.00"]
+ writer.write_record(rec)
+
+ rec.FILTER = "PASS"
+ writer.write_record(rec)
+
+ rec.FILTER = []
+ writer.write_record(rec)
+
+ writer.close()
+
+ expected_filter = ["LowQual", "LowQual;VQSRTrancheSNP99.90to100.00", None, None]
+ expected_filters = [["LowQual"], ["LowQual", "VQSRTrancheSNP99.90to100.00"], ["PASS"], []]
+
+ for i, variant in enumerate(VCF(f)):
+ assert variant.FILTER == expected_filter[i], (variant.FILTER, expected_filter[i])
+ assert variant.FILTERS == expected_filters[i], (variant.FILTERS, expected_filters[i])
+
def test_add_info_to_header():
v = VCF(VCF_PATH)
v.add_info_to_header({'ID': 'abcdefg', 'Description': 'abcdefg',
@@ -377,7 +422,8 @@ def test_add_flag():
fh = VCF(f)
v = next(fh)
fh.close()
- assert_raises(KeyError, v.INFO.__getitem__, "myflag")
+ with pytest.raises(KeyError):
+ v.INFO["myflag"]
def test_issue198():
vcf = VCF(os.path.join(HERE, "issue_198.vcf"), strict_gt=True)
@@ -434,7 +480,7 @@ def test_seqnames():
def test_different_index():
b = VCF('{}/test.snpeff.bcf'.format(HERE), threads=3)
- b.set_index("cyvcf2/tests/test-diff.csi")
+ b.set_index("{}/test-diff.csi".format(HERE))
s = 0
for r in b("chr1:69427-69429"):
s += 1
@@ -454,16 +500,17 @@ def test_var_type():
def _get_line_for(v):
import gzip
- for i, line in enumerate(gzip.open(VCF_PATH), start=1):
- line = line.decode()
- if line[0] == "#": continue
- toks = line.strip().split("\t")
- if not (toks[0] == v.CHROM and int(toks[1]) == v.POS): continue
- if toks[3] != v.REF: continue
- if toks[4] not in v.ALT: continue
- return toks
- else:
- raise Exception("not found")
+ with gzip.open(VCF_PATH) as f:
+ for i, line in enumerate(f, start=1):
+ line = line.decode()
+ if line[0] == "#": continue
+ toks = line.strip().split("\t")
+ if not (toks[0] == v.CHROM and int(toks[1]) == v.POS): continue
+ if toks[3] != v.REF: continue
+ if toks[4] not in v.ALT: continue
+ return toks
+ else:
+ raise Exception("not found")
def _get_samples(v):
@@ -482,7 +529,7 @@ def _get_samples(v):
return 2
toks = _get_line_for(v)
samples = toks[9:]
- return np.array([_get_gt(s) for s in samples], np.int)
+ return np.array([_get_gt(s) for s in samples], np.int32)
def test_header_info():
v = VCF(VCF_PATH)
@@ -491,7 +538,8 @@ def test_header_info():
assert "Description" in csq
- assert_raises(KeyError, v.__getitem__, b'XXXXX')
+ with pytest.raises(KeyError):
+ v[b'XXXXX']
def test_snpeff_header():
v = VCF(VCF_PATH2)
@@ -613,13 +661,24 @@ def test_bcf():
viter = vcf("1:69260-69438")
sys.stderr.write("\nOK\n")
sys.stderr.flush()
- l = list(viter)
+ with warnings.catch_warnings(record=True) as w:
+ l = list(viter)
+ assert len(w) == 1
+ assert "no intervals found" in str(w[-1].message)
assert len(l) == 0, len(l)
iter = vcf("chr1:69260-69438")
l = list(iter)
assert len(l) == 2, len(l)
+def test_vcf_no_intervals():
+ vcf = VCF('{}/test.vcf.gz'.format(HERE))
+ viter = vcf("not_a_chrom")
+ with warnings.catch_warnings(record=True) as w:
+ l = list(viter)
+ assert len(w) == 1
+ assert "no intervals found" in str(w[-1].message)
+ assert len(l) == 0, len(l)
def test_issue12():
fields = "ADP_ALL ADPD ADPO ADP_PASS ADPR AFR AMBIG BMF_PASS BMF_QUANT AF_FAILED FA_FAILED FM_FAILED FP_FAILED FR_FAILED MD_FAILED IMPROPER MQ_FAILED OVERLAP PV_FAILED QSS".split()
@@ -634,7 +693,8 @@ def test_issue12():
vals = v.format("RVF")
assert vals.dtype in (np.float32, np.float64)
- assert_raises(KeyError, v.format, "RULE")
+ with pytest.raises(KeyError):
+ v.format("RULE")
def test_gt_bases_nondiploid():
"""Ensure gt_bases works with more complex base representations.
@@ -668,7 +728,7 @@ def test_set_format_int_a():
vcf = VCF('{}/test-format-string.vcf'.format(HERE))
assert vcf.add_format_to_header(dict(ID="PI", Number=1, Type="Integer", Description="Int example")) == 0
v = next(vcf)
- v.set_format("PI", np.array([5, 1], dtype=np.int))
+ v.set_format("PI", np.array([5, 1], dtype=int))
assert allclose(fmap(float, get_gt_str(v, "PI")), [5, 1])
def test_set_format_int_b():
@@ -693,7 +753,7 @@ def test_set_format_int3():
vcf = VCF('{}/test-format-string.vcf'.format(HERE))
assert vcf.add_format_to_header(dict(ID="P3", Number=3, Type="Integer", Description="Int example")) == 0
v = next(vcf)
- exp = np.array([[1, 11, 111], [2, 22, 222]], dtype=np.int)
+ exp = np.array([[1, 11, 111], [2, 22, 222]], dtype=int)
v.set_format("P3", exp)
res = get_gt_str(v, "P3")
assert res == ["1,11,111", "2,22,222"], (res, str(v))
@@ -723,7 +783,8 @@ def test_set_format_str_bytes_number3():
v = next(vcf)
contents = np.array([[b'foo', b'barbaz', b'biz'], [b'blub', b'bloop', b'blop']])
- assert_raises(Exception, v.set_format, "STR", contents)
+ with pytest.raises(Exception):
+ v.set_format("STR", contents)
def test_set_gts():
vcf = VCF('{}/test-format-string.vcf'.format(HERE))
@@ -983,7 +1044,10 @@ def test_set_chrom_when_contig_not_in_header():
assert new_chrom not in original_seqnames
v = next(vcf)
- v.CHROM = new_chrom
+ with warnings.catch_warnings(record=True) as w:
+ v.CHROM = new_chrom
+ assert len(w) == 1
+ assert "added new contig" in str(w[-1].message)
assert v.CHROM == new_chrom
expected_seqnames = sorted(original_seqnames + [new_chrom])
assert vcf.seqnames == expected_seqnames
@@ -1009,7 +1073,7 @@ def test_set_qual():
variant.QUAL = 30.0
assert variant.QUAL == 30.0
- with assert_raises(TypeError):
+ with pytest.raises(TypeError):
variant.QUAL = "30.0"
variant.QUAL = None
@@ -1018,6 +1082,9 @@ def test_set_qual():
def test_strict_gt_option_flag():
test_vcf = '{}/test-strict-gt-option-flag.vcf.gz'.format(HERE)
+ #T, C
+ #0/0 1/1 0/1 1/0 1/. ./1 0/. ./0 ./..
+
truth_gt_bases = ('T/T', 'C/C', 'T/C', 'C/T', 'C/.', './C', 'T/.', './T', './.')
truth_genotypes = (
[0, 0, False],
@@ -1036,7 +1103,11 @@ def test_strict_gt_option_flag():
msg = "VCF(gts012=False, strict_gt=False) not working"
truth_gt_types = (0, 3, 1, 1, 1, 1, 0, 0, 2)
+ print(variant.gt_bases.tolist(), file=sys.stderr)
+ print(variant.gt_types.tolist(), file=sys.stderr)
assert bool(tuple(variant.gt_bases.tolist()) == truth_gt_bases), '{} [gt_bases]'.format(msg)
+
+ """
assert bool(tuple(variant.gt_types.tolist()) == truth_gt_types), '{} [gt_types]'.format(msg)
assert bool(tuple(variant.genotypes) == truth_genotypes), '{} (genotypes)'.format(msg)
@@ -1069,6 +1140,7 @@ def test_strict_gt_option_flag():
assert tuple(variant.gt_bases.tolist()) == truth_gt_bases, '{} [gt_bases]'.format(msg)
assert tuple(variant.gt_types.tolist()) == truth_gt_types, '{} [gt_types]'.format(msg)
assert tuple(variant.genotypes) == truth_genotypes, '{} (genotypes)'.format(msg)
+ """
def test_alt_repr():
v = os.path.join(HERE, "test-alt-repr.vcf")
@@ -1103,7 +1175,8 @@ def test_closed_iter():
vcf = VCF(path, gts012=True, strict_gt=False)
vcf.close()
- assert_raises(Exception, next, vcf)
+ with pytest.raises(Exception):
+ next(vcf)
def test_issue72():
path = os.path.join(HERE, "test-alt-repr.vcf")
@@ -1165,9 +1238,8 @@ def test_no_seqlen():
vcf_path = os.path.join(HERE, "no-seq-len.vcf")
vcf = VCF(vcf_path)
assert vcf.seqnames == ["3"]
- with assert_raises(AttributeError) as ae:
+ with pytest.raises(AttributeError):
vcf.seqlens
- assert isinstance(ae.exception, AttributeError)
def test_set_unknown_format():
vcf = VCF(VCF_PATH)
@@ -1186,4 +1258,47 @@ def test_invalid_header():
# htslib produces the error "Empty sample name: trailing spaces/tabs in the header line?"
p = os.path.join(HERE, "test-invalid-header.vcf")
assert os.path.exists(p)
- assert_raises(Exception, VCF, p)
+ with pytest.raises(Exception):
+ VCF(p)
+
+
+def test_genotypes():
+ """
+. 1
+./. ./1
+./. 1
+0/1 0
+0 0/1
+ """
+ exp_array = [[-1, 0],
+ [-1, -1, 0],
+ [-1, -1, 0],
+ [0, 1, 0],
+ [0, -2, 1],
+ ]
+
+ non_strict_exp_num = [
+ [0, 0, 1, 1],
+ [0, 1, 1, 0],
+ [0, 0, 1, 1],
+ [1, 1, 0, 0],
+ [1, 1, 0, 0],
+ ]
+
+ strict_exp_num = [x[:] for x in non_strict_exp_num]
+ strict_exp_num[1] = [0, 0, 2, 0] # both unknown
+
+ for strict_gt in (False, True):
+ vcf = VCF(os.path.join(HERE, "test-genotypes.vcf"), strict_gt=strict_gt)
+
+ exp_num = strict_exp_num if strict_gt else non_strict_exp_num
+
+
+ for i, v in enumerate(vcf):
+ #if i != 3: continue
+ obs = [v.num_hom_ref, v.num_het, v.num_unknown, v.num_hom_alt]
+ assert obs == exp_num[i], ("error with num_*")
+
+ a = v.genotype.array()[0] # only 0'th item
+ print("i:", i, " a:", v.genotype.array()[0], " exp:", exp_array[i])
+ assert (a == exp_array[i]).all(), " error with array"
=====================================
debian/changelog
=====================================
@@ -1,3 +1,17 @@
+cyvcf2 (0.30.14-1) unstable; urgency=medium
+
+ * New upstream version 0.30.14
+ * d/watch: Fix broken regex in watch file
+ * Drop d/p/python-3.10.patch, merged upstream
+ * Rediff and refresh patches
+ * Upstream has switched to pytest
+ + d/control: B-D on python3-pytest
+ + d/tests: adapt autopkgtests as per pytest
+ * Bump Standards-Version to 4.6.0 (no changes needed)
+ * d/copyright: s/MIT/Expat/
+
+ -- Nilesh Patra <nilesh at debian.org> Sat, 18 Dec 2021 13:55:27 +0530
+
cyvcf2 (0.30.11-1.1) unstable; urgency=medium
* Non-maintainer upload.
=====================================
debian/control
=====================================
@@ -15,13 +15,13 @@ Build-Depends: debhelper-compat (= 13),
python3-numpy,
python3-coloredlogs,
python3-click,
- python3-nose,
+ python3-pytest,
libssl-dev,
libcurl4-gnutls-dev|libcurl4-openssl-dev,
libhts-dev,
libbz2-dev,
help2man <!nodoc>
-Standards-Version: 4.5.1
+Standards-Version: 4.6.0
Vcs-Browser: https://salsa.debian.org/med-team/cyvcf2
Vcs-Git: https://salsa.debian.org/med-team/cyvcf2.git
Homepage: https://github.com/brentp/cyvcf2
=====================================
debian/copyright
=====================================
@@ -4,13 +4,13 @@ Source: https://github.com/brentp/cyvcf2
Files: *
Copyright: 2015 Brent Pedersen
-License: MIT
+License: Expat
Files: debian/*
Copyright: 2018 Steffen Moeller <moeller at debian.org>
-License: MIT
+License: Expat
-License: MIT
+License: Expat
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
=====================================
debian/patches/add_htslib_link_dependency.patch
=====================================
@@ -17,10 +17,11 @@ Description: Add missing link dependency on htslib, cythonize modules
def get_version():
"""Get the version info from the mpld3 package without importing it"""
import ast
-@@ -44,27 +39,27 @@
+@@ -43,34 +38,33 @@
+ extension.sources[:] = sources
return extensions
-
+-
-# Build the Cython extension by statically linking to the bundled htslib
-sources = [
- x for x in glob.glob('htslib/*.c')
@@ -30,24 +31,31 @@ Description: Add missing link dependency on htslib, cythonize modules
-# Exclude the htslib sources containing main()'s
-sources = [x for x in sources if not x.endswith(('htsfile.c', 'tabix.c', 'bgzip.c'))]
-sources.append('cyvcf2/helpers.c')
+-
+ extra_libs = []
+ if platform.system() != 'Darwin':
+ extra_libs.append('crypt')
+ if bool(int(os.getenv("LIBDEFLATE", 0))):
+ extra_libs.append('deflate')
+
+-extensions = [Extension("cyvcf2.cyvcf2",
+extensions = []
+if "clean" not in sys.argv:
+ import numpy as np
+ # Build the Cython extension by statically linking to the bundled htslib
+ sources = [
-+ x for x in glob.glob('htslib/*.c')
++ x for x in glob.glob('htslib/*.c')
+ if not any(e in x for e in ['irods', 'plugin'])
+ ]
+ sources += glob.glob('htslib/cram/*.c')
+ # Exclude the htslib sources containing main()'s
+ sources = [x for x in sources if not x.endswith(('htsfile.c', 'tabix.c', 'bgzip.c'))]
+ sources.append('cyvcf2/helpers.c')
-
--extensions = [Extension("cyvcf2.cyvcf2",
++
+ extensions = [Extension("cyvcf2.cyvcf2",
["cyvcf2/cyvcf2.pyx"] + sources,
-- libraries=['z', 'bz2', 'lzma', 'curl', 'ssl'] + (['crypt'] if platform.system() != 'Darwin' else []),
-+ libraries=['z', 'bz2', 'lzma', 'curl', 'ssl', 'hts'] + (['crypt'] if platform.system() != 'Darwin' else []),
+- libraries=['z', 'bz2', 'lzma', 'curl', 'ssl'] + extra_libs,
++ libraries=['z', 'bz2', 'lzma', 'curl', 'ssl', 'hts'] + extra_libs,
extra_compile_args=["-Wno-sign-compare", "-Wno-unused-function",
"-Wno-strict-prototypes",
"-Wno-unused-result", "-Wno-discarded-qualifiers"],
@@ -59,7 +67,7 @@ Description: Add missing link dependency on htslib, cythonize modules
try:
from Cython.Build import cythonize
except ImportError:
-@@ -75,8 +70,6 @@
+@@ -81,8 +75,6 @@
sys.exit(1)
compiler_directives = {"language_level": 2, "embedsignature": True}
extensions = cythonize(extensions, compiler_directives=compiler_directives)
=====================================
debian/patches/i386.patch
=====================================
@@ -1,17 +1,18 @@
+Description: I386
--- a/cyvcf2/tests/test_reader.py
+++ b/cyvcf2/tests/test_reader.py
-@@ -12,6 +12,8 @@
- except ImportError:
- from pathlib2 import Path # python 2 backport
+@@ -15,6 +15,8 @@
+
+ from ..cyvcf2 import VCF, Variant, Writer
+import subprocess
+import unittest
HERE = os.path.dirname(__file__)
VCF_PATH = os.path.join(HERE, "test.vcf.gz")
-@@ -1169,6 +1171,7 @@
+@@ -1241,6 +1243,7 @@
+ with pytest.raises(AttributeError):
vcf.seqlens
- assert isinstance(ae.exception, AttributeError)
+ at unittest.skipIf('i386' in str(subprocess.check_output('dpkg-architecture -qDEB_BUILD_ARCH', shell=True)), reason="The file ends up with a few NaN values on i386 due to exceeding ranges, hence skipping")
def test_set_unknown_format():
=====================================
debian/patches/python-3.10.patch deleted
=====================================
@@ -1,46 +0,0 @@
-From: Stefano Rivera <stefano at rivera.za.net>
-Date: Sun, 21 Nov 2021 08:29:40 -0400
-Subject: Avoid a Python 3.10 regression in iterating GzipFiles
-
-Open the file with a context manager, so we're holding onto a reference to it, for the lifetime of the iteration.
-
-This avoids hitting https://bugs.python.org/issue45475 which affects python3.10 3.10.0-4 in Debian.
-
-Bug-Debian: https://bugs.debian.org/1000317
-Forwarded: https://github.com/brentp/cyvcf2/pull/225
----
- cyvcf2/tests/test_reader.py | 21 +++++++++++----------
- 1 file changed, 11 insertions(+), 10 deletions(-)
-
-diff --git a/cyvcf2/tests/test_reader.py b/cyvcf2/tests/test_reader.py
-index 76cb9f8..f81b920 100644
---- a/cyvcf2/tests/test_reader.py
-+++ b/cyvcf2/tests/test_reader.py
-@@ -456,16 +456,17 @@ def test_var_type():
- def _get_line_for(v):
- import gzip
-
-- for i, line in enumerate(gzip.open(VCF_PATH), start=1):
-- line = line.decode()
-- if line[0] == "#": continue
-- toks = line.strip().split("\t")
-- if not (toks[0] == v.CHROM and int(toks[1]) == v.POS): continue
-- if toks[3] != v.REF: continue
-- if toks[4] not in v.ALT: continue
-- return toks
-- else:
-- raise Exception("not found")
-+ with gzip.open(VCF_PATH) as f:
-+ for i, line in enumerate(f, start=1):
-+ line = line.decode()
-+ if line[0] == "#": continue
-+ toks = line.strip().split("\t")
-+ if not (toks[0] == v.CHROM and int(toks[1]) == v.POS): continue
-+ if toks[3] != v.REF: continue
-+ if toks[4] not in v.ALT: continue
-+ return toks
-+ else:
-+ raise Exception("not found")
-
-
- def _get_samples(v):
=====================================
debian/patches/series
=====================================
@@ -1,3 +1,2 @@
add_htslib_link_dependency.patch
i386.patch
-python-3.10.patch
=====================================
debian/tests/control
=====================================
@@ -1,3 +1,3 @@
Tests: run-unit-test
-Depends: @, python3-all, python3-nose
+Depends: @, python3-all, python3-pytest
Restrictions: allow-stderr
=====================================
debian/tests/run-unit-test
=====================================
@@ -14,5 +14,5 @@ cd "${AUTOPKGTEST_TMP}"
for py in $(py3versions -s 2> /dev/null)
do echo "Testing with $py in $(pwd):"
- ${py} -m nose -v
+ ${py} -m pytest -v
done
=====================================
debian/watch
=====================================
@@ -1,3 +1,3 @@
version=4
-https://github.com/brentp/cyvcf2/releases .*/archive/.*/v?@ANY_VERSION@@ARCHIVE_EXT@
+https://github.com/brentp/cyvcf2/tags .*/archive/.*/v?@ANY_VERSION@@ARCHIVE_EXT@
=====================================
docs/source/index.rst
=====================================
@@ -131,11 +131,11 @@ or via bioconda.
Testing
=======
-Tests can be run with:
+Install `pytest`, then tests can be run with:
.. code-block:: bash
- python setup.py test
+ pytest
Known Limitations
=================
=====================================
setup.cfg
=====================================
@@ -1,5 +1,2 @@
-[nosetests]
-verbosity=1
-detailed-errors=1
-with-coverage=1
-stop=1
+[tool:pytest]
+testpaths = cyvcf2/tests
=====================================
setup.py
=====================================
@@ -54,9 +54,15 @@ sources += glob.glob('htslib/cram/*.c')
sources = [x for x in sources if not x.endswith(('htsfile.c', 'tabix.c', 'bgzip.c'))]
sources.append('cyvcf2/helpers.c')
+extra_libs = []
+if platform.system() != 'Darwin':
+ extra_libs.append('crypt')
+if bool(int(os.getenv("LIBDEFLATE", 0))):
+ extra_libs.append('deflate')
+
extensions = [Extension("cyvcf2.cyvcf2",
["cyvcf2/cyvcf2.pyx"] + sources,
- libraries=['z', 'bz2', 'lzma', 'curl', 'ssl'] + (['crypt'] if platform.system() != 'Darwin' else []),
+ libraries=['z', 'bz2', 'lzma', 'curl', 'ssl'] + extra_libs,
extra_compile_args=["-Wno-sign-compare", "-Wno-unused-function",
"-Wno-strict-prototypes",
"-Wno-unused-result", "-Wno-discarded-qualifiers"],
@@ -96,8 +102,6 @@ setup(
'cyvcf2 = cyvcf2.__main__:cli',
],
),
- test_suite='nose.collector',
- tests_require='nose',
install_requires=['numpy', 'coloredlogs', 'click'],
include_package_data=True,
zip_safe=False,
View it on GitLab: https://salsa.debian.org/med-team/cyvcf2/-/compare/df9ade504e530e167fdaf16ea4ced6a6a4eb9734...bebf5620f7461c90b52eece28f88592e5b5073c0
--
View it on GitLab: https://salsa.debian.org/med-team/cyvcf2/-/compare/df9ade504e530e167fdaf16ea4ced6a6a4eb9734...bebf5620f7461c90b52eece28f88592e5b5073c0
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20211218/423a3b68/attachment-0001.htm>
More information about the debian-med-commit
mailing list