helpers

class InterfaceCase[source]

An interface test helper that allows a given interface to generate and validate arrays in one of its formats.

Each instance of “interface test case” should be considered one of the potentially multiple realizations of a given interface. If an interface has multiple formats (eg. zarr’s different store s), then it should have several test helpers.

abstract property interface: Interface

The interface that this helper is for

classmethod array_from_case(case: ValidationCase, path: Path | None = None) NDArrayType | None[source]

Generate an array from the given validation case.

Returns None if an array can’t be generated for a specific case.

abstract classmethod make_array(shape: tuple[int, ...] = (10, 10), dtype: str | type | ~typing.Any | ~numpy.generic = <class 'float'>, path: ~pathlib.Path | None = None, array: ~numpydantic.types.NDArrayType | None = None) NDArrayType | None[source]

Make an array from a shape and dtype, and a path if needed

Parameters:
  • shape – shape of the array

  • dtype – dtype of the array

  • path – Path, if needed to generate on disk

  • array – Rather than passing shape and dtype, pass a literal arraylike thing

classmethod validate_case(case: ValidationCase, path: Path) bool[source]

Validate a generated array against the annotation in the validation case.

Kept in the InterfaceCase in case an interface has specific needs aside from just validating against a model, but typically left as is.

If an array can’t be generated for a given case, returns None so that the calling function can know to skip rather than fail the case.

Raises exceptions if validation fails (or succeeds when it shouldn’t)

Parameters:
  • case (ValidationCase) – The validation case to validate.

  • path (Path) – Path to generate arrays into, if any.

Returns:

True if array is valid and was supposed to be,

or invalid and wasn’t supposed to be

classmethod skip(shape: tuple[int, ...], dtype: str | type | Any | generic) bool[source]

Whether a given interface should be skipped for the case

pydantic model ValidationCase[source]

Test case for validating an array.

Contains both the validating model and the parameterization for an array to test in a given interface

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Config:
  • arbitrary_types_allowed: bool = True

Fields:
field annotation_dtype: str | type | Any | generic | Sequence[str | type | Any | generic] = (<class 'numpy.float16'>, <class 'numpy.float32'>, <class 'numpy.float64'>, <class 'numpy.float32'>, <class 'numpy.float64'>)

Dtype to use in computed annotation used to validate against

field annotation_shape: tuple[int | str, ...] | tuple[tuple[int | str, ...], ...] = (10, 10, '*', '*')

Shape to use in computed annotation used to validate against

field dtype: type | dtype = <class 'float'>

Dtype of the array to validate

field id: str | None = None

String identifying the validation case

field interface: type[InterfaceCase] | None = None

The interface test case to generate and validate the array with

field marks: set[str] [Optional]

pytest marks to set for this test case

field passes: bool = False

Whether the validation should pass or not

field path: Path | None = None

The path to generate arrays into, if any.

field shape: tuple[int, ...] = (10, 10, 2, 2)

Shape of the array to validate

array(path: Path) NDArrayType[source]

Generate an array for the validation case if we have an interface to do so

merge(other: ValidationCase | Sequence[ValidationCase]) ValidationCase[source]

Merge two validation cases

Dump both, excluding any unset fields, and merge, preferring other.

valid is True if and only if it is True in both.

skip() bool[source]

Whether this case should be skipped (eg. due to the interface case being incompatible with the requested dtype or shape)

validate_case(path: Path | None = None) bool[source]

Whether the generated array correctly validated against the annotation, given the interface

Parameters:

path (pathlib.Path) – Directory to generate array into, if on disk.

Raises:

ValueError – if an interface is missing

property annotation: NDArray[Any, Any]

Annotation used in the model we validate against

property model: type[BaseModel]

A model with a field array with the given annotation

property pytest_marks: list[MarkDecorator]

Instantiated pytest marks from ValidationCase.marks plus the interface name.

merge_cases(*args: ValidationCase) ValidationCase[source]

Merge multiple validation cases

merged_product(*args: Sequence[ValidationCase], conditions: dict = None) list[ValidationCase][source]

Generator for the product of the iterators of validation cases, merging each tuple, and respecting if they should be ValidationCase.skip() or not.

Examples

shape_cases = [
    ValidationCase(shape=(10, 10, 10), passes=True, id="valid shape"),
    ValidationCase(shape=(10, 10), passes=False, id="missing dimension"),
]
dtype_cases = [
    ValidationCase(dtype=float, passes=True, id="float"),
    ValidationCase(dtype=int, passes=False, id="int"),
]

iterator = merged_product(shape_cases, dtype_cases))
next(iterator)
# ValidationCase(
#     shape=(10, 10, 10),
#     dtype=float,
#     passes=True,
#     id="valid shape-float"
# )
next(iterator)
# ValidationCase(
#     shape=(10, 10, 10),
#     dtype=int,
#     passes=False,
#     id="valid shape-int"
# )