Add len method to video and hdf5 interfaces, make dunder test module to test dunder methods across all interfaces

This commit is contained in:
sneakers-the-rat 2024-09-02 18:13:28 -07:00
parent 9364cacc90
commit b1c8d3e422
Signed by untrusted user who does not match committer: jonny
GPG key ID: 6DCB96EF1E4D232D
6 changed files with 73 additions and 35 deletions

View file

@ -121,6 +121,10 @@ class H5Proxy:
else: else:
obj[key, self.field] = value obj[key, self.field] = value
def __len__(self) -> int:
"""self.shape[0]"""
return self.shape[0]
def open(self, mode: str = "r") -> "h5py.Dataset": def open(self, mode: str = "r") -> "h5py.Dataset":
""" """
Return the opened :class:`h5py.Dataset` object Return the opened :class:`h5py.Dataset` object

View file

@ -180,6 +180,10 @@ class VideoProxy:
def __getattr__(self, item: str): def __getattr__(self, item: str):
return getattr(self.video, item) return getattr(self.video, item)
def __len__(self) -> int:
"""Number of frames in the video"""
return self.shape[0]
class VideoInterface(Interface): class VideoInterface(Interface):
""" """

View file

@ -8,6 +8,7 @@ import numpy as np
import pytest import pytest
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
import zarr import zarr
import cv2
from numpydantic.interface.hdf5 import H5ArrayPath from numpydantic.interface.hdf5 import H5ArrayPath
from numpydantic.interface.zarr import ZarrArrayPath from numpydantic.interface.zarr import ZarrArrayPath
@ -150,3 +151,34 @@ def zarr_array(tmp_output_dir_func) -> Path:
array = zarr.open(str(file), mode="w", shape=(100, 100), chunks=(10, 10)) array = zarr.open(str(file), mode="w", shape=(100, 100), chunks=(10, 10))
array[:] = 0 array[:] = 0
return file return file
@pytest.fixture(scope="function")
def avi_video(tmp_path) -> Callable[[Tuple[int, int], int, bool], Path]:
video_path = tmp_path / "test.avi"
def _make_video(shape=(100, 50), frames=10, is_color=True) -> Path:
writer = cv2.VideoWriter(
str(video_path),
cv2.VideoWriter_fourcc(*"RGBA"), # raw video for testing purposes
30,
(shape[1], shape[0]),
is_color,
)
if is_color:
shape = (*shape, 3)
for i in range(frames):
# make fresh array every time bc opencv eats them
array = np.zeros(shape, dtype=np.uint8)
if not is_color:
array[i, i] = i
else:
array[i, i, :] = i
writer.write(array)
writer.release()
return video_path
yield _make_video
video_path.unlink(missing_ok=True)

View file

@ -1,10 +1,12 @@
import pytest import pytest
from typing import Tuple, Callable
import numpy as np import numpy as np
import dask.array as da import dask.array as da
import zarr import zarr
from pydantic import BaseModel
from numpydantic import interface from numpydantic import interface, NDArray
@pytest.fixture( @pytest.fixture(
@ -17,6 +19,7 @@ from numpydantic import interface
(zarr.ones((10, 10)), interface.ZarrInterface), (zarr.ones((10, 10)), interface.ZarrInterface),
("zarr_nested_array", interface.ZarrInterface), ("zarr_nested_array", interface.ZarrInterface),
("zarr_array", interface.ZarrInterface), ("zarr_array", interface.ZarrInterface),
("avi_video", interface.VideoInterface),
], ],
ids=[ ids=[
"numpy_list", "numpy_list",
@ -26,9 +29,10 @@ from numpydantic import interface
"zarr_memory", "zarr_memory",
"zarr_nested", "zarr_nested",
"zarr_array", "zarr_array",
"video",
], ],
) )
def interface_type(request): def interface_type(request) -> Tuple[NDArray, interface.Interface]:
""" """
Test cases for each interface's ``check`` method - each input should match the Test cases for each interface's ``check`` method - each input should match the
provided interface and that interface only provided interface and that interface only
@ -37,3 +41,20 @@ def interface_type(request):
return (request.getfixturevalue(request.param[0]), request.param[1]) return (request.getfixturevalue(request.param[0]), request.param[1])
else: else:
return request.param return request.param
@pytest.fixture()
def all_interfaces(interface_type) -> BaseModel:
"""
An instantiated version of each interface within a basemodel,
with the array in an `array` field
"""
array, interface = interface_type
if isinstance(array, Callable):
array = array()
class MyModel(BaseModel):
array: NDArray
instance = MyModel(array=array)
return instance

View file

@ -0,0 +1,10 @@
"""
Tests for dunder methods on all interfaces
"""
def test_dunder_len(all_interfaces):
"""
Each interface or proxy type should support __len__
"""
assert len(all_interfaces.array) == all_interfaces.array.shape[0]

View file

@ -2,8 +2,6 @@
Needs to be refactored to DRY, but works for now Needs to be refactored to DRY, but works for now
""" """
import pdb
import numpy as np import numpy as np
import pytest import pytest
@ -17,37 +15,6 @@ from numpydantic import dtype as dt
from numpydantic.interface.video import VideoProxy from numpydantic.interface.video import VideoProxy
@pytest.fixture(scope="function")
def avi_video(tmp_path):
video_path = tmp_path / "test.avi"
def _make_video(shape=(100, 50), frames=10, is_color=True) -> Path:
writer = cv2.VideoWriter(
str(video_path),
cv2.VideoWriter_fourcc(*"RGBA"), # raw video for testing purposes
30,
(shape[1], shape[0]),
is_color,
)
if is_color:
shape = (*shape, 3)
for i in range(frames):
# make fresh array every time bc opencv eats them
array = np.zeros(shape, dtype=np.uint8)
if not is_color:
array[i, i] = i
else:
array[i, i, :] = i
writer.write(array)
writer.release()
return video_path
yield _make_video
video_path.unlink(missing_ok=True)
@pytest.mark.parametrize("input_type", [str, Path]) @pytest.mark.parametrize("input_type", [str, Path])
def test_video_validation(avi_video, input_type): def test_video_validation(avi_video, input_type):
"""Color videos should validate for normal uint8 shape specs""" """Color videos should validate for normal uint8 shape specs"""