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)