p2p-ld / numpydantic

Type annotations for specifying, validating, and serializing arrays with arbitrary backends in Pydantic (and beyond)
https://numpydantic.readthedocs.io/
MIT License
66 stars 1 forks source link

[tests] `numpydantic.testing` - exposing helpers for 3rd-party interface development & combinatoric testing #31

Closed sneakers-the-rat closed 1 month ago

sneakers-the-rat commented 1 month ago

Currently

we have fixtures for specifying a number of test cases for dtypes and shapes, and then each interface validates against those test cases.

To make that work, we..

The shape/dtype cases look something like this:

@pytest.fixture(
    scope="module",
    params=[
        ValidationCase(annotation=RGB_UNION, shape=(5, 5), passes=True),
        ValidationCase(annotation=RGB_UNION, shape=(5, 5, 3), passes=True),
        ValidationCase(annotation=RGB_UNION, shape=(5, 5, 3, 6), passes=False),
        ValidationCase(annotation=RGB_UNION, shape=(5, 5, 4, 6), passes=False),
        # ...
    ])
def shape_cases(request) -> ValidationCase:
    return request.param

The numpy interface tests are like this

def numpy_array(case: ValidationCase) -> np.ndarray:
    if issubclass(case.dtype, BaseModel):
        return np.full(shape=case.shape, fill_value=case.dtype(x=1))
    else:
        return np.zeros(shape=case.shape, dtype=case.dtype)

def _test_np_case(case: ValidationCase):
    array = numpy_array(case)
    if case.passes:
        case.model(array=array)
    else:
        with pytest.raises((ValidationError, DtypeError, ShapeError)):
            case.model(array=array)

@pytest.mark.shape
def test_numpy_shape(shape_cases):
    _test_np_case(shape_cases)

@pytest.mark.dtype
def test_numpy_dtype(dtype_cases):
    _test_np_case(dtype_cases)

Problem

this is proving to be a little bit brittle, and we don't test against, eg, the product of the dtype and shape cases even though we should.

we also want to test behaviors that should be true for all generators, all dtypes, and all shapes, but currently we can only run those tests against a fixed model and array pair for each interface.

we also want to make it possible for people to develop their own interfaces, and so it would be nice if we could facilitate that by providing structure for testing them and a set of tests that need to pass in order for an interface to be added to the package. (or not if they don't want to idrc)

So this PR...

Also

coveralls commented 1 month ago

Pull Request Test Coverage Report for Build 11289913767

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details


Changes Missing Coverage Covered Lines Changed/Added Lines %
src/numpydantic/interface/numpy.py 7 8 87.5%
src/numpydantic/serialization.py 1 2 50.0%
src/numpydantic/testing/interfaces.py 132 134 98.51%
<!-- Total: 313 317 98.74% -->
Files with Coverage Reduction New Missed Lines %
src/numpydantic/interface/zarr.py 1 99.03%
src/numpydantic/interface/interface.py 3 98.56%
src/numpydantic/interface/video.py 5 96.24%
<!-- Total: 9 -->
Totals Coverage Status
Change from base Build 11063861484: -0.4%
Covered Lines: 1491
Relevant Lines: 1516

💛 - Coveralls