Source code for moptipy.tests.space

"""Functions that can be used to test spaces."""
from typing import Any, Callable

# noinspection PyPackageRequirements
import pytest
from pycommons.io.csv import COMMENT_START
from pycommons.types import type_error

from moptipy.api.space import Space, check_space
from moptipy.tests.component import validate_component
from moptipy.utils.logger import SECTION_END, SECTION_START


[docs] def validate_space( space: Space, make_element_valid: Callable[[Any], Any] | None = lambda x: x, make_element_invalid: Callable[[Any], Any] | None = None) -> None: """ Check whether an object is a moptipy space. :param space: the space to test :param make_element_valid: a method that can turn a point from the space into a valid point :param make_element_invalid: a method can a valid point from the space into an invalid one :raises ValueError: if `space` is not a valid instance of :class:`~moptipy.api.space.Space` :raises TypeError: if incorrect types are encountered """ if not isinstance(space, Space): raise type_error(space, "space", Space) check_space(space) validate_component(space) if not (hasattr(space, "create") and callable(getattr(space, "create"))): raise ValueError("space must have method create.") x1 = space.create() if x1 is None: raise ValueError("Spaces must create() valid objects, " "but returned None.") x2 = space.create() if x2 is None: raise ValueError("Spaces must create() valid objects, " "but returned None.") if x2 is x1: raise ValueError("The create() method must produce different " "instances when invoked twice, but returned the " "same object.") if type(x1) is not type(x2): # noqa: PIE789 raise ValueError("The create() method must produce instances of " f"the same type, but got {type(x1)} and {type(x2)}.") if not (hasattr(space, "copy") and callable(getattr(space, "copy"))): raise ValueError("space must have method copy.") space.copy(x2, x1) if not (hasattr(space, "is_equal") and callable(getattr(space, "is_equal"))): raise ValueError("space must have method is_equal.") if not space.is_equal(x1, x2): raise ValueError("space.copy(x1, x2) did not lead to " "space.is_equal(x1, x2).") if make_element_valid is None: return x1 = make_element_valid(x1) if not (hasattr(space, "validate") and callable(getattr(space, "validate"))): raise ValueError("space must have method validate.") space.validate(x1) if not (hasattr(space, "to_str") and callable(getattr(space, "to_str"))): raise ValueError("space must have method to_str.") strstr = space.to_str(x1) if not isinstance(strstr, str): raise type_error(strstr, f"space.to_str(x) for {x1}", str) if len(strstr) <= 0: raise ValueError( "space.to_str(x) must not produce empty strings, " f"but we got {strstr!r}.") if strstr.strip() != strstr: raise ValueError( "space.to_str(x) must not include leading or trailing spaces," f" but we go {strstr!r}.") if SECTION_START in strstr: raise ValueError(f"space.to_str() must not include " f"{SECTION_START!r}, but is {strstr!r}.") if SECTION_END in strstr: raise ValueError(f"space.to_str() must not include " f"{SECTION_END!r}, but is {strstr!r}.") if COMMENT_START in strstr: raise ValueError(f"space.to_str() must not include " f"{COMMENT_START!r}, but is {strstr!r}.") if not (hasattr(space, "from_str") and callable(getattr(space, "from_str"))): raise ValueError("space must have method from_str.") x3 = space.from_str(strstr) if (x3 is x1) or (x3 is x2): raise ValueError("from_str() cannot return the same object as " "create().") if not space.is_equal(x1, x3): raise ValueError("from_str(to_str()) must return equal object.") if space.to_str(x3) != strstr: raise ValueError("to_str(from_str(to_str())) must return same " "string.") space.validate(x3) if make_element_invalid is None: return x2 = make_element_invalid(x3) if space.is_equal(x1, x2): raise ValueError( "make_element_invalid did not lead to a change in element!") with pytest.raises(ValueError): # noqa space.validate(x2)