Skip to content

Commit

Permalink
Merge pull request #28 from jeromekelleher/lowlevel-tests
Browse files Browse the repository at this point in the history
Initial start on cpython interface testing
  • Loading branch information
jeromekelleher authored Jul 15, 2024
2 parents 660bd65 + 4193038 commit 3f6c405
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 21 deletions.
64 changes: 46 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ on:
- main

jobs:
test:
name: Test
python_test:
name: Python tests
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand Down Expand Up @@ -42,30 +42,32 @@ jobs:
run: |
pytest
packaging:
name: Packaging
c_python_test:
name: CPython interface tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
- name: Install system dependencies
run: |
sudo apt install -y gcovr
- name: Install python dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build twine validate-pyproject[all]
- name: Check and install package
python -m pip install numpy pytest
- name: Build module with coverage
run: |
validate-pyproject pyproject.toml
python -m build
python -m twine check --strict dist/*
python -m pip install dist/*.whl
- name: Check vcztools CLI
# Build the extension module in-place so pytest can find it
CFLAGS="--coverage" python3 setup.py build_ext --inplace
- name: Run tests
run: |
vcztools --help
# Make sure we don't have ``vcztools`` in the CWD
cd tests
python -m vcztools --help
pytest -vs tests/test_cpython_interface.py
- name: Show coverage
run: |
gcovr --filter vcztools
c_test:
name: C tests
Expand All @@ -88,7 +90,33 @@ jobs:
run: |
ninja -C build coverage-text
cat build/meson-logs/coverage.txt
- name: Valgrind
- name: Valgrind
working-directory: ./lib
run: |
valgrind --leak-check=full --error-exitcode=1 ./build/tests
packaging:
name: Packaging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build twine validate-pyproject[all]
- name: Check and install package
run: |
validate-pyproject pyproject.toml
python -m build
python -m twine check --strict dist/*
python -m pip install dist/*.whl
- name: Check vcztools CLI
run: |
vcztools --help
# Make sure we don't have ``vcztools`` in the CWD
cd tests
python -m vcztools --help
53 changes: 53 additions & 0 deletions tests/test_cpython_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import pytest
import numpy as np

from vcztools import _vcztools

FIXED_FIELD_NAMES = ["chrom", "pos", "id", "qual", "ref", "alt", "filter"]


def example_fixed_data(num_variants, num_samples=0):
chrom = np.array(["X"] * num_variants, dtype="S")
pos = np.arange(num_variants, dtype=np.int32)
id = np.array(["."] * num_variants, dtype="S").reshape((num_variants, 1))
ref = np.array(["A"] * num_variants, dtype="S")
alt = np.array(["T"] * num_variants, dtype="S").reshape((num_variants, 1))
qual = np.arange(num_variants, dtype=np.float32)
filter_ = np.ones(num_variants, dtype=bool).reshape((num_variants, 1))
filter_id = np.array(["PASS"], dtype="S")
return {
"chrom": chrom,
"pos": pos,
"id": id,
"qual": qual,
"ref": ref,
"alt": alt,
"filter": filter_,
"filter_ids": filter_id,
}


class TestTypeChecking:
@pytest.mark.parametrize("name", FIXED_FIELD_NAMES)
def test_field_incorrect_length(self, name):
num_variants = 5
data = example_fixed_data(num_variants)
data[name] = data[name][1:]
with pytest.raises(ValueError, match=f"Array {name.upper()} must have "):
_vcztools.VcfEncoder(num_variants, 0, **data)

@pytest.mark.parametrize("name", FIXED_FIELD_NAMES)
def test_field_incorrect_dtype(self, name):
num_variants = 5
data = example_fixed_data(num_variants)
data[name] = np.zeros(data[name].shape, dtype=np.int64)
with pytest.raises(ValueError, match=f"Wrong dtype for {name.upper()}"):
_vcztools.VcfEncoder(num_variants, 0, **data)

@pytest.mark.parametrize("name", FIXED_FIELD_NAMES)
def test_field_incorrect_type(self, name):
num_variants = 5
data = example_fixed_data(num_variants)
data[name] = "A Python string"
with pytest.raises(TypeError, match=f"must be numpy.ndarray"):
_vcztools.VcfEncoder(num_variants, 0, **data)
6 changes: 3 additions & 3 deletions vcztools/_vcztoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ VcfEncoder_store_fixed_array(VcfEncoder *self, PyArrayObject *array, const char
goto out;
}
if (PyArray_DTYPE(array)->type_num != type) {
PyErr_Format(PyExc_ValueError, "Array %s is not of the correct type", name);
PyErr_Format(PyExc_ValueError, "Wrong dtype for %s", name);
goto out;
}

Expand Down Expand Up @@ -189,7 +189,7 @@ VcfEncoder_init(VcfEncoder *self, PyObject *args, PyObject *kwds)
goto out;
}

/* NOTE: we generalise this pattern for CHROM also to save a bit of time
/* NOTE: we could generalise this pattern for CHROM also to save a bit of time
* in building numpy String arrays */
assert(PyArray_CheckExact(filter_ids));
if (!PyArray_CHKFLAGS(filter_ids, NPY_ARRAY_IN_ARRAY)) {
Expand All @@ -209,7 +209,7 @@ VcfEncoder_init(VcfEncoder *self, PyObject *args, PyObject *kwds)
if (VcfEncoder_add_array(self, "IDS/", "FILTER", filter_ids) != 0) {
goto out;
}
if (VcfEncoder_store_fixed_array(self, filter, "filter", NPY_BOOL, 2, num_variants)
if (VcfEncoder_store_fixed_array(self, filter, "FILTER", NPY_BOOL, 2, num_variants)
!= 0) {
goto out;
}
Expand Down

0 comments on commit 3f6c405

Please sign in to comment.