From de07b907a067d012fb14c7cf27ec15b6b667473d Mon Sep 17 00:00:00 2001 From: caniko Date: Fri, 10 Mar 2023 15:56:08 +0100 Subject: [PATCH] Fix: Fixed incorrect methodology of getting Config from model instance, self.Config -> self.__config__ Test: Improved coverage for NumpyModel Chore: Version bump, PATCH --- .gitignore | 4 +++ pydantic_numpy/model.py | 4 +-- pydantic_numpy/ndarray.py | 4 +-- pyproject.toml | 2 +- tests/test_model.py | 64 ++++++++++++++++++++++++++++++--------- 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index f73e4dd..9411d3c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# Project + +delete_me_test_dump*/ + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/pydantic_numpy/model.py b/pydantic_numpy/model.py index 6a94323..20e827d 100644 --- a/pydantic_numpy/model.py +++ b/pydantic_numpy/model.py @@ -25,8 +25,8 @@ def model_directory_path(cls, pre_model_path: Path) -> DirectoryPath: return pre_model_path.parent / f"{pre_model_path.stem}-{cls.__name__}{cls._directory_suffix}" def dump(self, dump_directory_path: Path, compress: bool = True, pickle: bool = False) -> None: - assert not ( - self.Config.arbitrary_types_allowed and not pickle + assert not self.__config__.arbitrary_types_allowed or ( + self.__config__.arbitrary_types_allowed and pickle ), "Arbitrary types are only supported in pickle mode" dump_directory_path = self.model_directory_path(dump_directory_path) diff --git a/pydantic_numpy/ndarray.py b/pydantic_numpy/ndarray.py index 8a87853..fa6bbe0 100644 --- a/pydantic_numpy/ndarray.py +++ b/pydantic_numpy/ndarray.py @@ -1,5 +1,3 @@ -from __future__ import annotations - from abc import ABC, abstractmethod from pathlib import Path from typing import TYPE_CHECKING, Any, Generic, Mapping, Optional, TypeVar @@ -27,7 +25,7 @@ def check_absolute(cls, value: Path) -> Path: class BaseNDArrayType(Generic[T, ScalarType], np.ndarray[T, np.dtype[ScalarType]], ABC): @classmethod - def __get_validators__(cls) -> CallableGenerator: + def __get_validators__(cls) -> "CallableGenerator": yield cls.validate @classmethod diff --git a/pyproject.toml b/pyproject.toml index 86ee4e1..56b5239 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pydantic_numpy" -version = "2.0.1" +version = "2.0.2" description = "Seamlessly integrate numpy arrays into pydantic models" authors = ["Can H. Tartanoglu ", "Christoph Heindl"] license = "MIT" diff --git a/tests/test_model.py b/tests/test_model.py index 14993b4..d81e9b5 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1,50 +1,84 @@ import shutil from pathlib import Path +from typing import Union import numpy as np import pytest -from pydantic_numpy import NDArray +from pydantic_numpy import NDArray, NDArrayBool from pydantic_numpy.model import NumpyModel -TEST_DUMP_PATH: Path = Path("./test_dump").resolve() +TEST_DUMP_PATH: Path = Path("../delete_me_test_dump").resolve() -class TestNumpyModel(NumpyModel): +class NumpyModelForTest(NumpyModel): array: NDArray non_array: int +class TestWithArbitraryForTest(NumpyModelForTest): + my_arbitrary_slice: slice + + class Config: + arbitrary_types_allowed = True + + +numpy_bool_array: NDArrayBool = np.array([True, True, True, True, True], dtype=bool) + + +def _numpy_model(): + return NumpyModelForTest(array=numpy_bool_array, non_array=5) + + @pytest.fixture -def test_numpy_model(): - return TestNumpyModel(array=np.array([True, False, True, True, True], dtype=bool), non_array=5) +def numpy_model(): + return _numpy_model() + +@pytest.fixture(params=[ + _numpy_model(), + TestWithArbitraryForTest(array=numpy_bool_array, non_array=5, my_arbitrary_slice=slice(0, 10)) +]) +def numpy_model_with_arbitrary(request): + return request.param -def test_io_yaml(test_numpy_model): + +def test_io_yaml(numpy_model): try: - test_numpy_model.dump(TEST_DUMP_PATH) - test_numpy_model.load(TEST_DUMP_PATH) + numpy_model.dump(TEST_DUMP_PATH) + _test_loaded_numpy_model(numpy_model.load(TEST_DUMP_PATH)) finally: _delete_leftovers() -def test_io_compressed_pickle(test_numpy_model): +def test_io_compressed_pickle(numpy_model_with_arbitrary): try: - test_numpy_model.dump(TEST_DUMP_PATH, pickle=True) - test_numpy_model.load(TEST_DUMP_PATH) + numpy_model_with_arbitrary.dump(TEST_DUMP_PATH, pickle=True) + _test_loaded_numpy_model(numpy_model_with_arbitrary.load(TEST_DUMP_PATH)) + finally: _delete_leftovers() -def test_io_pickle(test_numpy_model): +def test_io_pickle(numpy_model_with_arbitrary): try: - test_numpy_model.dump(TEST_DUMP_PATH, pickle=True, compress=False) - test_numpy_model.load(TEST_DUMP_PATH) + numpy_model_with_arbitrary.dump(TEST_DUMP_PATH, pickle=True, compress=False) + _test_loaded_numpy_model(numpy_model_with_arbitrary.load(TEST_DUMP_PATH)) finally: _delete_leftovers() +def _test_loaded_numpy_model(model: Union[NumpyModelForTest, TestWithArbitraryForTest]): + assert np.all(model.array) and len(model.array) == 5 + if isinstance(model, TestWithArbitraryForTest): + assert isinstance(model.my_arbitrary_slice, slice) + + def _delete_leftovers(): - dump_path = TestNumpyModel.model_directory_path(TEST_DUMP_PATH) + dump_path = NumpyModelForTest.model_directory_path(TEST_DUMP_PATH) + if dump_path.exists(): + shutil.rmtree(dump_path) + + dump_path = TestWithArbitraryForTest.model_directory_path(TEST_DUMP_PATH) if dump_path.exists(): shutil.rmtree(dump_path)