diff --git a/baybe/constraints/discrete.py b/baybe/constraints/discrete.py index 740e603f89..7acd39139d 100644 --- a/baybe/constraints/discrete.py +++ b/baybe/constraints/discrete.py @@ -3,6 +3,7 @@ from __future__ import annotations import gc +import warnings from collections.abc import Callable from functools import reduce from typing import TYPE_CHECKING, Any, ClassVar, cast @@ -233,13 +234,18 @@ def get_invalid(self, data: pd.DataFrame) -> pd.Index: # Create data copy and mark entries where the dependency conditions are negative # with a dummy value to cause degeneracy. censored_data = data.copy() - for k, _ in enumerate(self.parameters): - # .loc assignments are not supported by mypy + pandas-stubs yet - # See https://github.com/pandas-dev/pandas-stubs/issues/572 - censored_data.loc[ # type: ignore[call-overload] - ~self.conditions[k].evaluate(data[self.parameters[k]]), - self.affected_parameters[k], - ] = Dummy() + with warnings.catch_warnings(): + # Suppress pandas FutureWarning about setting incompatible dtype. + # TODO: Needs proper fix for pandas 3.0 compatibility. + warnings.simplefilter("ignore", FutureWarning) + + for k, _ in enumerate(self.parameters): + # .loc assignments are not supported by mypy + pandas-stubs yet + # See https://github.com/pandas-dev/pandas-stubs/issues/572 + censored_data.loc[ # type: ignore[call-overload] + ~self.conditions[k].evaluate(data[self.parameters[k]]), + self.affected_parameters[k], + ] = Dummy() # Create an invariant indicator: pair each value of an affected parameter with # the corresponding value of the parameter it depends on. These indicators diff --git a/baybe/surrogates/linear.py b/baybe/surrogates/linear.py index ba1fed5b2c..99d847f0cd 100644 --- a/baybe/surrogates/linear.py +++ b/baybe/surrogates/linear.py @@ -71,7 +71,9 @@ def _estimate_moments( import torch # Get predictions - dists = self._model.predict(candidates_comp_scaled.numpy(), return_std=True) + dists = self._model.predict( + candidates_comp_scaled.detach().numpy(), return_std=True + ) # Split into posterior mean and variance mean = torch.from_numpy(dists[0]) diff --git a/baybe/surrogates/ngboost.py b/baybe/surrogates/ngboost.py index 6cb1cee135..5d3c6dcc3b 100644 --- a/baybe/surrogates/ngboost.py +++ b/baybe/surrogates/ngboost.py @@ -98,7 +98,7 @@ def _estimate_moments( import torch # Get predictions - dists = self._model.pred_dist(candidates_comp_scaled) + dists = self._model.pred_dist(candidates_comp_scaled.detach().numpy()) # Split into posterior mean and variance mean = torch.from_numpy(dists.mean()) diff --git a/baybe/surrogates/random_forest.py b/baybe/surrogates/random_forest.py index 91ad599bb1..69f8588a0d 100644 --- a/baybe/surrogates/random_forest.py +++ b/baybe/surrogates/random_forest.py @@ -109,7 +109,7 @@ def predict(candidates_comp_scaled: Tensor) -> Tensor: return torch.from_numpy( self._predict_ensemble( - self._model.estimators_, candidates_comp_scaled.numpy() + self._model.estimators_, candidates_comp_scaled.detach().numpy() ) ) diff --git a/baybe/utils/clustering_algorithms/third_party/kmedoids.py b/baybe/utils/clustering_algorithms/third_party/kmedoids.py index 55369ebd1b..82be6bd76f 100644 --- a/baybe/utils/clustering_algorithms/third_party/kmedoids.py +++ b/baybe/utils/clustering_algorithms/third_party/kmedoids.py @@ -46,7 +46,6 @@ pairwise_distances_argmin, ) from sklearn.utils import check_array, check_random_state -from sklearn.utils.extmath import stable_cumsum from sklearn.utils.validation import check_is_fitted from baybe.settings import active_settings @@ -485,7 +484,9 @@ def _kpp_init(self, D, n_clusters, random_state_, n_local_trials=None): # pick the remaining n_clusters-1 points for cluster_index in range(1, n_clusters): rand_vals = random_state_.random_sample(n_local_trials) * current_pot - candidate_ids = np.searchsorted(stable_cumsum(closest_dist_sq), rand_vals) + candidate_ids = np.searchsorted( + np.cumulative_sum(closest_dist_sq), rand_vals + ) # Compute distances to center candidates distance_to_candidates = D[candidate_ids, :] ** 2 diff --git a/pytest.ini b/pytest.ini index 7ba12d0881..ea27ff0064 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,13 @@ [pytest] +strict = true + +markers = + filterwarnings: Apply warning filters to a test + +# Currently blocked by test_iterations.py. Should be activated once that test module +# has been properly refactored. +strict_parametrization_ids=false + addopts = --doctest-modules --ignore=examples @@ -6,7 +15,20 @@ addopts = ; Avoids import errors due to optional dependencies --doctest-ignore-import-errors + testpaths = baybe tests -xfail_strict=true + +filterwarnings = + error + ; Numerics/optimization + ignore:.*add(ed|ing) jitter.*:linear_operator.utils.warnings.NumericalWarning + ignore:Optimization failed.*:RuntimeWarning:botorch.optim.optimize + ; Note: File format instead of module format needed due to BoTorch reraising using `warn_explicit` without `module` argument + ignore:`scipy_minimize` terminated with status .*:botorch.exceptions.warnings.OptimizationWarning:.*botorch/fit + ; BoTorch warning recommending to switch to log-versions of acquisition functions + ignore:.*has known numerical issues that lead to suboptimal optimization performance.*:botorch.exceptions.warnings.NumericsWarning:botorch.acquisition + ; Temporary ignores + ; https://github.com/meta-pytorch/botorch/pull/3279 + ignore:chol argument to CholLinearOperator should be a TriangularLinearOperator.*:DeprecationWarning:linear_operator.operators.chol_linear_operator diff --git a/tests/conftest.py b/tests/conftest.py index 882204c156..51aa5a1b03 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -83,6 +83,13 @@ create_fake_input, ) +# TODO: Remove when https://github.com/cornellius-gp/linear_operator/pull/129 is ready +warnings.filterwarnings( + "ignore", + message=".*torch.jit.script.*is deprecated", + category=DeprecationWarning, +) + # Hypothesis settings hypothesis_settings.register_profile("ci", deadline=500, max_examples=100) if strtobool(os.getenv("CI", "false")): @@ -918,7 +925,7 @@ def fixture_default_onnx_str() -> bytes: # Train sklearn model train_x = torch.arange(10).view(-1, 1) - train_y = torch.arange(10).view(-1, 1) + train_y = torch.arange(10) model = BayesianRidge() model.fit(train_x, train_y) @@ -951,9 +958,6 @@ def fixture_default_onnx_surrogate(onnx_str) -> CustomONNXSurrogate: match=r".*Expected value argument.*to be within the support.*" ), ), - before_sleep=lambda x: warnings.warn( - f"Retrying iteration test due to '{x.outcome.exception()}'" - ), ) def run_iterations( campaign: Campaign, n_iterations: int, batch_size: int, add_noise: bool = True diff --git a/tests/constraints/test_cardinality_constraint_continuous.py b/tests/constraints/test_cardinality_constraint_continuous.py index 2717ceff42..04e9e10cf9 100644 --- a/tests/constraints/test_cardinality_constraint_continuous.py +++ b/tests/constraints/test_cardinality_constraint_continuous.py @@ -231,6 +231,7 @@ def prepare_measurements() -> pd.DataFrame: ) with warnings.catch_warnings(record=True) as captured_warnings: + warnings.filterwarnings("always", category=MinimumCardinalityViolatedWarning) BotorchRecommender().recommend( BATCH_SIZE, searchspace, objective, prepare_measurements() ) diff --git a/tests/constraints/test_constraints_continuous.py b/tests/constraints/test_constraints_continuous.py index e2ed9361bb..2b5c91e112 100644 --- a/tests/constraints/test_constraints_continuous.py +++ b/tests/constraints/test_constraints_continuous.py @@ -221,7 +221,7 @@ def test_hybridspace_ineq(campaign, n_iterations, batch_size): param(["A", "B"], [1.0, 2.0, 3.0], 0.0, ">=", id="ineq_too_many_coeffs"), param(["A", "B"], [1.0, 2.0], "bla", ">=", id="ineq_invalid_rhs"), param(["A", "B"], [1.0, 2.0], 0.0, "invalid", id="ineq_invalid_operator1"), - param(["A", "B"], [1.0, 2.0], 0.0, 2.0, id="ineq_invalid_operator1"), + param(["A", "B"], [1.0, 2.0], 0.0, 2.0, id="ineq_invalid_operator2"), ], ) def test_invalid_constraints(parameters, coefficients, rhs, op): diff --git a/tests/hypothesis_strategies/alternative_creation/test_acquisition.py b/tests/hypothesis_strategies/alternative_creation/test_acquisition.py index 513e7a2679..933ffcf201 100644 --- a/tests/hypothesis_strategies/alternative_creation/test_acquisition.py +++ b/tests/hypothesis_strategies/alternative_creation/test_acquisition.py @@ -6,22 +6,22 @@ from baybe.recommenders import BotorchRecommender from baybe.utils.basic import get_subclasses -abbreviation_list = [ +abbreviations = [ cl.abbreviation for cl in get_subclasses(AcquisitionFunction) if hasattr(cl, "abbreviation") ] +fullnames = [cl.__name__ for cl in get_subclasses(AcquisitionFunction)] +combined = set(abbreviations + fullnames) -fullname_list = [cl.__name__ for cl in get_subclasses(AcquisitionFunction)] - -@pytest.mark.parametrize("acqf", abbreviation_list + fullname_list) +@pytest.mark.parametrize("acqf", combined) def test_creation_from_string(acqf): """Tests the creation from strings.""" AcquisitionFunction.from_dict({"type": acqf}) -@pytest.mark.parametrize("acqf", abbreviation_list + fullname_list) +@pytest.mark.parametrize("acqf", combined) def test_string_usage_in_recommender(acqf): """Tests the recommender initialization with acqfs as string.""" BotorchRecommender(acquisition_function=acqf) diff --git a/tests/test_deprecations.py b/tests/test_deprecations.py index b1961d31a6..47849d6659 100644 --- a/tests/test_deprecations.py +++ b/tests/test_deprecations.py @@ -243,6 +243,7 @@ def test_target_deprecation_helpers(): NumericalTarget.from_modern_interface("t", minimize=True) +@pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_target_legacy_deserialization(): """Deserialization also works from legacy arguments.""" actual = NumericalTarget.from_dict({"name": "t", "mode": "MATCH", "bounds": (1, 2)}) @@ -259,6 +260,7 @@ def series() -> pd.Series: return sample_input() +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("mode", ["MAX", "MIN"]) def test_constructor_equivalence_min_max(mode): """ @@ -300,6 +302,7 @@ def test_constructor_equivalence_min_max(mode): assert t1 == t2 +@pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("transformation", ["TRIANGULAR", "BELL"]) def test_constructor_equivalence_match(transformation): """ @@ -340,9 +343,13 @@ def test_constructor_equivalence_match(transformation): assert t1 == t2 -@pytest.mark.parametrize( - ("legacy", "deprecation", "modern", "expected"), - [ +# NOTE: The parametrize values below use the deprecated legacy interface of +# ModernTarget (e.g. ModernTarget("t", "MAX")), which emits DeprecationWarning. +# Since these are evaluated at module/collection time, we suppress the warning here +# to avoid failures when running with `-W error`. +with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + _target_transformation_params = [ param( LegacyTarget("t", "MAX"), ModernTarget("t", "MAX"), @@ -464,7 +471,12 @@ def test_constructor_equivalence_match(transformation): triangular_transform(sample_input(), 2, 6), id="match_triangular_scaled_shifted", ), - ], + ] + + +@pytest.mark.parametrize( + ("legacy", "deprecation", "modern", "expected"), + _target_transformation_params, ) def test_target_transformation( series, @@ -482,6 +494,7 @@ def test_target_transformation( assert_series_equal(modern.transform(series), expected) +@pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_deserialization_using_constructor(): """Deserialization using the 'constructor' field works despite having other deprecation mechanisms in place.""" # noqa diff --git a/tests/test_surrogate.py b/tests/test_surrogate.py index b9deedf153..5a4f617b0e 100644 --- a/tests/test_surrogate.py +++ b/tests/test_surrogate.py @@ -163,6 +163,10 @@ def test_invalid_model_params(model_cls, params): model_cls(model_params=params) +@pytest.mark.skipif( + os.environ.get("BAYBE_TEST_ENV") != "FULLTEST", + reason="Most surrogates are only available in FULLTEST environment.", +) @pytest.mark.parametrize( "target_names", [["Target_max"], ["Target_max_bounded", "Target_min_bounded"]], @@ -185,7 +189,7 @@ def test_invalid_model_params(model_cls, params): ) def test_continuous_incompatibility(campaign): """Using surrogates without gradients on continuous spaces fails expectedly.""" - data = create_fake_input(campaign.parameters, campaign.targets) + data = create_fake_input(campaign.parameters, campaign.targets, n_rows=3) campaign.add_measurements(data) skip = False