mirror of
https://github.com/p2p-ld/numpydantic.git
synced 2025-01-09 13:44:26 +00:00
Merge pull request #14 from p2p-ld/bugfix-revalidation
[bugfix] Revalidate with already-validated/proxied array
This commit is contained in:
commit
c46015d306
6 changed files with 68 additions and 23 deletions
|
@ -2,7 +2,17 @@
|
|||
|
||||
## 1.*
|
||||
|
||||
### 1.5.0 - 24-09-02 - `str` support for HDF5
|
||||
### 1.5.*
|
||||
|
||||
#### 1.5.1 - 24-09-03 - Fix revalidation with proxy classes
|
||||
|
||||
Bugfix:
|
||||
- [#14](https://github.com/p2p-ld/numpydantic/pull/14): Allow revalidation of proxied arrays
|
||||
|
||||
Tests:
|
||||
- Add test module for tests against all interfaces, test for above bug
|
||||
|
||||
#### 1.5.0 - 24-09-02 - `str` support for HDF5
|
||||
|
||||
Strings in hdf5 are tricky! HDF5 doesn't have native support for unicode,
|
||||
but it can be persuaded to store data in ASCII or virtualized utf-8 under somewhat obscure conditions.
|
||||
|
@ -36,7 +46,9 @@ instance[0,0] = 'hey'
|
|||
assert instance[0,0] == 'hey'
|
||||
```
|
||||
|
||||
### 1.4.1 - 24-09-02 - `len()` support and dunder method testing
|
||||
### 1.4.*
|
||||
|
||||
#### 1.4.1 - 24-09-02 - `len()` support and dunder method testing
|
||||
|
||||
It's pretty natural to want to do `len(array)` as a shorthand for `array.shape[0]`,
|
||||
but since some of the numpydantic classes are passthrough proxy objects,
|
||||
|
@ -52,7 +64,7 @@ There is a certain combinatoric explosion when we start testing across all inter
|
|||
for all input types, for all dtype and all shape cases,
|
||||
but for now numpydantic is fast enough that this doesn't matter <3.
|
||||
|
||||
### 1.4.0 - 24-09-02 - HDF5 Compound Dtype Support
|
||||
#### 1.4.0 - 24-09-02 - HDF5 Compound Dtype Support
|
||||
|
||||
HDF5 can have compound dtypes like:
|
||||
|
||||
|
@ -107,7 +119,9 @@ my_model = MyModel(
|
|||
np.dtype('int64')
|
||||
```
|
||||
|
||||
### 1.3.3 - 24-08-13 - Callable type annotations
|
||||
### 1.3.*
|
||||
|
||||
#### 1.3.3 - 24-08-13 - Callable type annotations
|
||||
|
||||
Problem, when you use a numpydantic `"wrap"` validator, it gives the annotation as a `handler` function.
|
||||
|
||||
|
@ -162,11 +176,11 @@ ShapeError: Invalid shape! expected shape ['3'], got shape (4,)
|
|||
using it. This shaves ~600ms off import time.
|
||||
|
||||
|
||||
### 1.3.2 - 24-08-12 - Allow subclasses of dtypes
|
||||
#### 1.3.2 - 24-08-12 - Allow subclasses of dtypes
|
||||
|
||||
(also when using objects for dtypes, subclasses of that object are allowed to validate)
|
||||
|
||||
### 1.3.1 - 24-08-12 - Allow arbitrary dtypes, pydantic models as dtypes
|
||||
#### 1.3.1 - 24-08-12 - Allow arbitrary dtypes, pydantic models as dtypes
|
||||
|
||||
Previously we would only allow dtypes if we knew for sure that there was some
|
||||
python base type to generate a schema with.
|
||||
|
@ -183,7 +197,7 @@ Only one substantial change, and that is a `get_object_dtype` method which
|
|||
interfaces can override if there is some fancy way they have of getting
|
||||
types/items from an object array.
|
||||
|
||||
### 1.3.0 - 24-08-05 - Better string dtype handling
|
||||
#### 1.3.0 - 24-08-05 - Better string dtype handling
|
||||
|
||||
API Changes:
|
||||
- Split apart the validation methods into smaller chunks to better support
|
||||
|
@ -194,7 +208,9 @@ Bugfix:
|
|||
- [#4](https://github.com/p2p-ld/numpydantic/issues/4) - Support dtype checking
|
||||
for strings in zarr and numpy arrays
|
||||
|
||||
### 1.2.3 - 24-07-31 - Vendor `nptyping`
|
||||
### 1.2.*
|
||||
|
||||
#### 1.2.3 - 24-07-31 - Vendor `nptyping`
|
||||
|
||||
`nptyping` vendored into `numpydantic.vendor.nptyping` -
|
||||
`nptyping` is no longer maintained, and pins `numpy<2`.
|
||||
|
@ -221,22 +237,24 @@ Tidying:
|
|||
- Remove `monkeypatch` module! we don't need it anymore!
|
||||
everything has either been upstreamed or vendored.
|
||||
|
||||
### 1.2.2 - 24-07-31
|
||||
#### 1.2.2 - 24-07-31
|
||||
|
||||
Add `datetime` map to numpy's :class:`numpy.datetime64` type
|
||||
|
||||
### 1.2.1 - 24-06-27
|
||||
#### 1.2.1 - 24-06-27
|
||||
|
||||
Fix a minor bug where {class}`~numpydantic.exceptions.DtypeError` would not cause
|
||||
pydantic to throw a {class}`pydantic.ValidationError` because custom validator functions
|
||||
need to raise either `AssertionError` or `ValueError` - made `DtypeError` also
|
||||
inherit from `ValueError` because that is also technically true.
|
||||
|
||||
### 1.2.0 - 24-06-13 - Shape ranges
|
||||
#### 1.2.0 - 24-06-13 - Shape ranges
|
||||
|
||||
- Add ability to specify shapes as ranges - see [shape ranges](shape-ranges)
|
||||
|
||||
### 1.1.0 - 24-05-24 - Instance Checking
|
||||
### 1.1.*
|
||||
|
||||
#### 1.1.0 - 24-05-24 - Instance Checking
|
||||
|
||||
https://github.com/p2p-ld/numpydantic/pull/1
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "numpydantic"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
description = "Type and shape validation and serialization for arbitrary array types in pydantic models"
|
||||
authors = [
|
||||
{name = "sneakers-the-rat", email = "sneakers-the-rat@protonmail.com"},
|
||||
|
|
|
@ -194,10 +194,7 @@ class H5Interface(Interface):
|
|||
passthrough numpy-like interface to the dataset.
|
||||
"""
|
||||
|
||||
input_types = (
|
||||
H5ArrayPath,
|
||||
H5Arraylike,
|
||||
)
|
||||
input_types = (H5ArrayPath, H5Arraylike, H5Proxy)
|
||||
return_type = H5Proxy
|
||||
|
||||
@classmethod
|
||||
|
@ -211,7 +208,7 @@ class H5Interface(Interface):
|
|||
Check that the given array is a :class:`.H5ArrayPath` or something that
|
||||
resembles one.
|
||||
"""
|
||||
if isinstance(array, H5ArrayPath):
|
||||
if isinstance(array, (H5ArrayPath, H5Proxy)):
|
||||
return True
|
||||
|
||||
if isinstance(array, (tuple, list)) and len(array) in (2, 3):
|
||||
|
@ -242,6 +239,9 @@ class H5Interface(Interface):
|
|||
"""Create an :class:`.H5Proxy` to use throughout validation"""
|
||||
if isinstance(array, H5ArrayPath):
|
||||
array = H5Proxy.from_h5array(h5array=array)
|
||||
elif isinstance(array, H5Proxy):
|
||||
# nothing to do, already proxied
|
||||
pass
|
||||
elif isinstance(array, (tuple, list)) and len(array) == 2: # pragma: no cover
|
||||
array = H5Proxy(file=array[0], path=array[1])
|
||||
elif isinstance(array, (tuple, list)) and len(array) == 3:
|
||||
|
|
|
@ -190,7 +190,7 @@ class VideoInterface(Interface):
|
|||
OpenCV interface to treat videos as arrays.
|
||||
"""
|
||||
|
||||
input_types = (str, Path, VideoCapture)
|
||||
input_types = (str, Path, VideoCapture, VideoProxy)
|
||||
return_type = VideoProxy
|
||||
|
||||
@classmethod
|
||||
|
@ -204,7 +204,9 @@ class VideoInterface(Interface):
|
|||
Check if array is a string or Path with a supported video extension,
|
||||
or an opened VideoCapture object
|
||||
"""
|
||||
if VideoCapture is not None and isinstance(array, VideoCapture):
|
||||
if (VideoCapture is not None and isinstance(array, VideoCapture)) or isinstance(
|
||||
array, VideoProxy
|
||||
):
|
||||
return True
|
||||
|
||||
if isinstance(array, str):
|
||||
|
@ -220,6 +222,8 @@ class VideoInterface(Interface):
|
|||
"""Get a :class:`.VideoProxy` object for this video"""
|
||||
if isinstance(array, VideoCapture):
|
||||
proxy = VideoProxy(video=array)
|
||||
elif isinstance(array, VideoProxy):
|
||||
proxy = array
|
||||
else:
|
||||
proxy = VideoProxy(path=array)
|
||||
return proxy
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import pytest
|
||||
"""
|
||||
Tests for the interface base model,
|
||||
for tests that should apply to all interfaces, use ``test_interfaces.py``
|
||||
"""
|
||||
|
||||
import gc
|
||||
|
||||
import pytest
|
||||
import numpy as np
|
||||
|
||||
from numpydantic.interface import Interface
|
||||
|
@ -8,6 +14,7 @@ from numpydantic.interface import Interface
|
|||
@pytest.fixture(scope="module")
|
||||
def interfaces():
|
||||
"""Define test interfaces in this module, and delete afterwards"""
|
||||
interfaces_enabled = True
|
||||
|
||||
class Interface1(Interface):
|
||||
input_types = (list,)
|
||||
|
@ -24,7 +31,7 @@ def interfaces():
|
|||
|
||||
@classmethod
|
||||
def enabled(cls) -> bool:
|
||||
return True
|
||||
return interfaces_enabled
|
||||
|
||||
Interface2 = type("Interface2", Interface1.__bases__, dict(Interface1.__dict__))
|
||||
Interface2.checked = False
|
||||
|
@ -44,7 +51,7 @@ def interfaces():
|
|||
|
||||
@classmethod
|
||||
def enabled(cls) -> bool:
|
||||
return True
|
||||
return interfaces_enabled
|
||||
|
||||
class Interfaces:
|
||||
interface1 = Interface1
|
||||
|
@ -55,9 +62,13 @@ def interfaces():
|
|||
yield Interfaces
|
||||
# Interface.__subclasses__().remove(Interface1)
|
||||
# Interface.__subclasses__().remove(Interface2)
|
||||
del Interfaces
|
||||
del Interface1
|
||||
del Interface2
|
||||
del Interface3
|
||||
del Interface4
|
||||
interfaces_enabled = False
|
||||
gc.collect()
|
||||
|
||||
|
||||
def test_interface_match_error(interfaces):
|
12
tests/test_interface/test_interfaces.py
Normal file
12
tests/test_interface/test_interfaces.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
"""
|
||||
Tests that should be applied to all interfaces
|
||||
"""
|
||||
|
||||
|
||||
def test_interface_revalidate(all_interfaces):
|
||||
"""
|
||||
An interface should revalidate with the output of its initial validation
|
||||
|
||||
See: https://github.com/p2p-ld/numpydantic/pull/14
|
||||
"""
|
||||
_ = type(all_interfaces)(array=all_interfaces.array)
|
Loading…
Reference in a new issue