From d75b8a738304f3c3c43eecc1d08a1ebfb5ccfdb2 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Tue, 14 Oct 2025 17:25:51 +0300 Subject: [PATCH 01/26] Gate optional GPy dependencies; add pytest markers; make wrappers import-safe without GPy; replace deprecated numpy/scipy constants; add optional extras and markers; remove internal ticket comments --- .../acquisitions/entropy_search.py | 10 ++-- .../acquisitions/max_value_entropy_search.py | 4 +- emukit/bayesian_optimization/epmgp.py | 8 +-- emukit/core/bandit_parameter.py | 2 +- emukit/core/discrete_parameter.py | 2 +- emukit/core/encodings.py | 2 +- .../continuous_fidelity_entropy_search.py | 6 +- emukit/model_wrappers/__init__.py | 28 ++++++++- emukit/model_wrappers/gpy_model_wrappers.py | 10 +++- .../model_wrappers/gpy_quadrature_wrappers.py | 7 +++ emukit/multi_fidelity/__init__.py | 1 + emukit/multi_fidelity/kernels/__init__.py | 16 ++++- emukit/multi_fidelity/models/__init__.py | 27 ++++++++- emukit/multi_fidelity/models/linear_model.py | 8 ++- .../models/non_linear_multi_fidelity_model.py | 8 ++- .../test_constrained_loop.py | 4 +- .../test_create_bayesian_optimization_loop.py | 3 + .../test_local_penalization_loop.py | 4 +- ...optimization_with_categorical_variables.py | 4 +- ..._single_objective_bayesian_optimization.py | 4 ++ ...known_constraints_bayesian_optimization.py | 4 ++ .../emukit/benchmarking/test_benchmarker.py | 5 +- ...st_experimental_design_with_categorical.py | 4 +- .../test_multi_source_experimental_design.py | 4 +- .../fabolas/test_continuous_entropy_search.py | 4 ++ .../emukit/fabolas/test_fabolas_model.py | 2 + .../emukit/models/test_random_forest.py | 1 + .../models/test_sklearn_model_wrapper.py | 1 + .../emukit/notebooks/test_notebooks.py | 5 ++ .../test_bayesian_monte_carlo_loop.py | 5 +- .../emukit/quadrature/test_vanilla_bq_loop.py | 5 +- .../emukit/quadrature/test_wsabil_loop.py | 5 +- requirements/requirements.txt | 8 +-- setup.cfg | 4 ++ setup.py | 58 ++++++++++++++++++- .../test_bayesian_optimization_loop.py | 4 +- .../test_constrained_loop.py | 3 + ...st_cost_sensitive_bayesian_optimization.py | 3 + .../test_local_penalization_calculator.py | 4 +- .../test_mean_plugin_expected_improvement.py | 5 +- .../test_multipoint_expected_improvement.py | 3 + tests/emukit/conftest.py | 16 ++++- tests/emukit/core/test_outer_loop.py | 4 +- tests/emukit/core/test_parameter_space.py | 2 +- .../test_batch_experimental_design.py | 5 +- .../test_experimental_design_loop.py | 3 + .../test_gpy_wrappers_quadrature.py | 4 +- tests/emukit/multi_fidelity/test_kernels.py | 3 + tests/emukit/multi_fidelity/test_models.py | 4 +- .../multi_fidelity/test_non_linear_models.py | 9 ++- .../test_quadrature_acquisitions.py | 4 +- .../quadrature/test_quadrature_kernels.py | 4 +- .../quadrature/test_quadrature_models.py | 4 +- tests/emukit/test_acquisitions.py | 3 + 54 files changed, 298 insertions(+), 62 deletions(-) diff --git a/emukit/bayesian_optimization/acquisitions/entropy_search.py b/emukit/bayesian_optimization/acquisitions/entropy_search.py index d6139a8f..01651aad 100644 --- a/emukit/bayesian_optimization/acquisitions/entropy_search.py +++ b/emukit/bayesian_optimization/acquisitions/entropy_search.py @@ -73,9 +73,9 @@ def prop_func(x): x_ = x if space.check_points_in_domain(x_): - return np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.PINF)) + return np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.inf)) else: - return np.array([np.NINF]) + return np.array([-np.inf]) self.proposal_function = prop_func else: @@ -298,13 +298,13 @@ def proposal_func(x): x_ = np.insert(x_, self.source_idx, idx, axis=1) if space.check_points_in_domain(x_): - val = np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.PINF)) + val = np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.inf)) if np.any(np.isnan(val)): - return np.array([np.NINF]) + return np.array([-np.inf]) else: return val else: - return np.array([np.NINF]) + return np.array([-np.inf]) return proposal_func diff --git a/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py b/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py index bfb611ff..aa98e5ae 100644 --- a/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py +++ b/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py @@ -9,7 +9,7 @@ import numpy as np import scipy -from scipy.integrate import simps +from scipy.integrate import simpson from scipy.optimize import bisect from scipy.stats import norm @@ -301,7 +301,7 @@ def evaluate(self, x: np.ndarray) -> np.ndarray: # calculate point-wise entropy function contributions (carefuly where density is 0) entropy_function = -density * np.log(density, out=np.zeros_like(density), where=(density != 0)) # perform integration over ranges - approximate_entropy = simps(entropy_function.T, z.T) + approximate_entropy = simpson(entropy_function.T, z.T) # build monte-carlo estimate over the gumbel samples approximate_entropy = np.mean(approximate_entropy, axis=0) diff --git a/emukit/bayesian_optimization/epmgp.py b/emukit/bayesian_optimization/epmgp.py index 80599c4e..a7cc975b 100644 --- a/emukit/bayesian_optimization/epmgp.py +++ b/emukit/bayesian_optimization/epmgp.py @@ -86,7 +86,7 @@ def min_factor(Mu, Sigma, k, gamma=1): M = np.copy(Mu) V = np.copy(Sigma) b = False - d = np.NaN + d = np.nan for count in range(50): diff = 0 for i in range(D - 1): @@ -105,7 +105,7 @@ def min_factor(Mu, Sigma, k, gamma=1): b = True break if np.isnan(d): - logZ = -np.Infinity + logZ = -np.inf yield logZ dlogZdMu = np.zeros((D, 1)) yield dlogZdMu @@ -201,12 +201,12 @@ def lt_factor(s, l, M, V, mp, p, gamma): logS = lP - 0.5 * (np.log(beta) - np.log(pnew) - np.log(cVnic)) + (alpha * alpha) / (2 * beta) * cVnic elif exit_flag == -1: - d = np.NAN + d = np.nan Mnew = 0 Vnew = 0 pnew = 0 mpnew = 0 - logS = -np.Infinity + logS = -np.inf elif exit_flag == 1: d = 0 # remove message from marginal: diff --git a/emukit/core/bandit_parameter.py b/emukit/core/bandit_parameter.py index e11bae4c..53eeafad 100644 --- a/emukit/core/bandit_parameter.py +++ b/emukit/core/bandit_parameter.py @@ -161,7 +161,7 @@ def round(self, x: np.ndarray) -> np.ndarray: if not all([self.check_in_domain(xr) for xr in x_rounded]): raise ValueError("Rounding error encountered, not all rounded values in domain.") - return np.row_stack(x_rounded) + return np.vstack(x_rounded) @property def dimension(self) -> int: diff --git a/emukit/core/discrete_parameter.py b/emukit/core/discrete_parameter.py index d258d060..f0aa9eb0 100644 --- a/emukit/core/discrete_parameter.py +++ b/emukit/core/discrete_parameter.py @@ -78,7 +78,7 @@ def round(self, x: np.ndarray) -> np.ndarray: rounded_value = min(self.domain, key=lambda d: abs(d - value)) x_rounded.append([rounded_value]) - return np.row_stack(x_rounded) + return np.vstack(x_rounded) def sample_uniform(self, point_count: int) -> np.ndarray: """ diff --git a/emukit/core/encodings.py b/emukit/core/encodings.py index 5031d31b..8a75a1e1 100644 --- a/emukit/core/encodings.py +++ b/emukit/core/encodings.py @@ -57,7 +57,7 @@ def round(self, x: np.ndarray) -> np.ndarray: row_rounded = self.round_row(row) x_rounded.append(row_rounded) - return np.row_stack(x_rounded) + return np.vstack(x_rounded) def round_row(self, x_row): """ diff --git a/emukit/examples/fabolas/continuous_fidelity_entropy_search.py b/emukit/examples/fabolas/continuous_fidelity_entropy_search.py index 68ca80e4..efd8890f 100644 --- a/emukit/examples/fabolas/continuous_fidelity_entropy_search.py +++ b/emukit/examples/fabolas/continuous_fidelity_entropy_search.py @@ -81,12 +81,12 @@ def proposal_func(x): x_ = np.insert(x_, self.target_fidelity_index, idx, axis=1) if space.check_points_in_domain(x_): - val = np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.PINF)) + val = np.log(np.clip(ei.evaluate(x_)[0], 0.0, np.inf)) if np.any(np.isnan(val)): - return np.array([np.NINF]) + return np.array([-np.inf]) else: return val else: - return np.array([np.NINF]) + return np.array([-np.inf]) return proposal_func diff --git a/emukit/model_wrappers/__init__.py b/emukit/model_wrappers/__init__.py index e3478247..9635fc31 100644 --- a/emukit/model_wrappers/__init__.py +++ b/emukit/model_wrappers/__init__.py @@ -5,5 +5,31 @@ # SPDX-License-Identifier: Apache-2.0 -from .gpy_model_wrappers import GPyModelWrapper, GPyMultiOutputWrapper # noqa: F401 +# Importing emukit.model_wrappers should succeed without GPy. Accessing GPy wrappers +# (instantiating or importing their concrete classes) should raise an informative ImportError +# pointing users to install the optional extra: `pip install emukit[gpy]`. + +from importlib import util as _importlib_util + +# Always expose SimpleGaussianProcessModel (pure numpy implementation) from .simple_gp_model import SimpleGaussianProcessModel # noqa: F401 + +if _importlib_util.find_spec("GPy") is not None: # GPy available + from .gpy_model_wrappers import GPyModelWrapper, GPyMultiOutputWrapper # noqa: F401 +else: + class _GPyMissingBase: + _error_msg = ( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' " + "to use {name}." + ) + + def __init__(self, *args, **kwargs): # pragma: no cover - exercised in minimal installs + raise ImportError(self._error_msg.format(name=self.__class__.__name__)) + + class GPyModelWrapper(_GPyMissingBase): # pragma: no cover - minimal installs + """Placeholder for GPyModelWrapper. Requires `emukit[gpy]` extra.""" + + class GPyMultiOutputWrapper(_GPyMissingBase): # pragma: no cover - minimal installs + """Placeholder for GPyMultiOutputWrapper. Requires `emukit[gpy]` extra.""" + +__all__ = ["GPyModelWrapper", "GPyMultiOutputWrapper", "SimpleGaussianProcessModel"] diff --git a/emukit/model_wrappers/gpy_model_wrappers.py b/emukit/model_wrappers/gpy_model_wrappers.py index 0b1b7413..b4389e52 100644 --- a/emukit/model_wrappers/gpy_model_wrappers.py +++ b/emukit/model_wrappers/gpy_model_wrappers.py @@ -5,9 +5,15 @@ # SPDX-License-Identifier: Apache-2.0 -from typing import Optional, Tuple -import GPy +import importlib +if importlib.util.find_spec("GPy") is None: # pragma: no cover + raise ImportError( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use gpy_model_wrappers." + ) +import GPy # noqa: F401 + +from typing import Optional, Tuple import numpy as np from ..bayesian_optimization.interfaces import IEntropySearchModel diff --git a/emukit/model_wrappers/gpy_quadrature_wrappers.py b/emukit/model_wrappers/gpy_quadrature_wrappers.py index 86c6d5e9..133f3c3a 100644 --- a/emukit/model_wrappers/gpy_quadrature_wrappers.py +++ b/emukit/model_wrappers/gpy_quadrature_wrappers.py @@ -7,6 +7,13 @@ """GPy wrappers for the quadrature package.""" +import importlib +if importlib.util.find_spec("GPy") is None: # pragma: no cover + raise ImportError( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use gpy_quadrature_wrappers." + ) +import GPy # noqa: F401 + # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 import warnings diff --git a/emukit/multi_fidelity/__init__.py b/emukit/multi_fidelity/__init__.py index 1e6279e0..982f8393 100644 --- a/emukit/multi_fidelity/__init__.py +++ b/emukit/multi_fidelity/__init__.py @@ -5,5 +5,6 @@ # SPDX-License-Identifier: Apache-2.0 + from . import kernels # noqa: F401 from . import models # noqa: F401 diff --git a/emukit/multi_fidelity/kernels/__init__.py b/emukit/multi_fidelity/kernels/__init__.py index 96cf8d60..6fc47138 100644 --- a/emukit/multi_fidelity/kernels/__init__.py +++ b/emukit/multi_fidelity/kernels/__init__.py @@ -5,4 +5,18 @@ # SPDX-License-Identifier: Apache-2.0 -from .linear_multi_fidelity_kernel import LinearMultiFidelityKernel # noqa: F401 + +# Importing emukit.multi_fidelity.kernels should not require GPy. Accessing +# LinearMultiFidelityKernel without GPy raises an informative ImportError. +from importlib import util as _importlib_util + +if _importlib_util.find_spec("GPy") is not None: # GPy available + from .linear_multi_fidelity_kernel import LinearMultiFidelityKernel # noqa: F401 +else: + class LinearMultiFidelityKernel: # pragma: no cover - exercised only when GPy missing + def __init__(self, *args, **kwargs): + raise ImportError( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use LinearMultiFidelityKernel." + ) + +__all__ = ["LinearMultiFidelityKernel"] diff --git a/emukit/multi_fidelity/models/__init__.py b/emukit/multi_fidelity/models/__init__.py index a70db734..d8f17066 100644 --- a/emukit/multi_fidelity/models/__init__.py +++ b/emukit/multi_fidelity/models/__init__.py @@ -5,5 +5,28 @@ # SPDX-License-Identifier: Apache-2.0 -from .linear_model import GPyLinearMultiFidelityModel # noqa: F401 -from .non_linear_multi_fidelity_model import NonLinearMultiFidelityModel # noqa: F401 +# GPy-based model classes should raise an informative ImportError pointing users to +# install the optional extra: `pip install emukit[gpy]`. + +from importlib import util as _importlib_util + +if _importlib_util.find_spec("GPy") is not None: # GPy available + from .linear_model import GPyLinearMultiFidelityModel # noqa: F401 + from .non_linear_multi_fidelity_model import NonLinearMultiFidelityModel # noqa: F401 +else: + class _GPyMissingBase: # pragma: no cover - exercised in minimal installs + _error_msg = ( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' " + "to use {name}." + ) + + def __init__(self, *args, **kwargs): # pragma: no cover + raise ImportError(self._error_msg.format(name=self.__class__.__name__)) + + class GPyLinearMultiFidelityModel(_GPyMissingBase): # pragma: no cover + """Placeholder for GPyLinearMultiFidelityModel. Requires `emukit[gpy]` extra.""" + + class NonLinearMultiFidelityModel(_GPyMissingBase): # pragma: no cover + """Placeholder for NonLinearMultiFidelityModel. Requires `emukit[gpy]` extra.""" + +__all__ = ["GPyLinearMultiFidelityModel", "NonLinearMultiFidelityModel"] diff --git a/emukit/multi_fidelity/models/linear_model.py b/emukit/multi_fidelity/models/linear_model.py index 4d8071bd..999e08d8 100644 --- a/emukit/multi_fidelity/models/linear_model.py +++ b/emukit/multi_fidelity/models/linear_model.py @@ -9,7 +9,13 @@ Contains linear models """ -import GPy + +import importlib +if importlib.util.find_spec("GPy") is None: # pragma: no cover + raise ImportError( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use GPyLinearMultiFidelityModel." + ) +import GPy # noqa: F401 import numpy as np diff --git a/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py b/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py index 3c328d39..b6253ff1 100644 --- a/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py +++ b/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py @@ -16,7 +16,13 @@ """ from typing import List, Tuple, Type -import GPy + +import importlib +if importlib.util.find_spec("GPy") is None: # pragma: no cover + raise ImportError( + "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use NonLinearMultiFidelityModel." + ) +import GPy # noqa: F401 import numpy as np from ...core.interfaces import IDifferentiable, IModel diff --git a/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py b/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py index 7edc11a1..6b10f8c6 100644 --- a/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py @@ -5,7 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy import numpy as np from emukit.bayesian_optimization.loops import BayesianOptimizationLoop diff --git a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py index 4f5bf6d1..3dc4da76 100644 --- a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("sklearn") + import numpy as np from emukit.examples.gp_bayesian_optimization.enums import AcquisitionType, ModelType diff --git a/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py b/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py index a944f72a..3c8ff0e0 100644 --- a/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py @@ -5,7 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy import numpy as np from emukit.bayesian_optimization.acquisitions import ExpectedImprovement diff --git a/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py b/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py index 5199d3cf..738517f9 100644 --- a/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py +++ b/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py @@ -5,7 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy import numpy as np from emukit.bayesian_optimization.acquisitions import ExpectedImprovement diff --git a/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py b/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py index d1b125dd..855aa92c 100644 --- a/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py +++ b/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py @@ -5,6 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy + import numpy as np from emukit.core.continuous_parameter import ContinuousParameter diff --git a/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py b/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py index f7bbed44..da3caf2d 100644 --- a/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py +++ b/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py @@ -5,6 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy + import numpy as np from emukit.core.continuous_parameter import ContinuousParameter diff --git a/integration_tests/emukit/benchmarking/test_benchmarker.py b/integration_tests/emukit/benchmarking/test_benchmarker.py index 62445364..ae910ca8 100644 --- a/integration_tests/emukit/benchmarking/test_benchmarker.py +++ b/integration_tests/emukit/benchmarking/test_benchmarker.py @@ -5,9 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy -import numpy as np import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy +import numpy as np import emukit.test_functions from emukit.bayesian_optimization.loops import BayesianOptimizationLoop diff --git a/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py b/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py index e4b3a1e4..10d1a38c 100644 --- a/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py +++ b/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py @@ -5,7 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy import numpy as np from emukit.core import CategoricalParameter, ContinuousParameter, OneHotEncoding, ParameterSpace diff --git a/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py b/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py index 35b48dcc..f82ad247 100644 --- a/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py +++ b/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py @@ -5,7 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy import numpy as np from emukit.core.initial_designs import RandomDesign diff --git a/integration_tests/emukit/fabolas/test_continuous_entropy_search.py b/integration_tests/emukit/fabolas/test_continuous_entropy_search.py index 6e9340cf..6e898206 100644 --- a/integration_tests/emukit/fabolas/test_continuous_entropy_search.py +++ b/integration_tests/emukit/fabolas/test_continuous_entropy_search.py @@ -5,6 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy + import numpy as np from emukit.core import ContinuousParameter, ParameterSpace diff --git a/integration_tests/emukit/fabolas/test_fabolas_model.py b/integration_tests/emukit/fabolas/test_fabolas_model.py index 3c0b32cd..5aba19b2 100644 --- a/integration_tests/emukit/fabolas/test_fabolas_model.py +++ b/integration_tests/emukit/fabolas/test_fabolas_model.py @@ -7,6 +7,8 @@ import numpy as np import pytest +pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy from emukit.examples.fabolas import FabolasModel diff --git a/integration_tests/emukit/models/test_random_forest.py b/integration_tests/emukit/models/test_random_forest.py index 4c8fbd18..ca5efc26 100644 --- a/integration_tests/emukit/models/test_random_forest.py +++ b/integration_tests/emukit/models/test_random_forest.py @@ -7,6 +7,7 @@ import numpy as np import pytest +pytest.importorskip("sklearn") from emukit.examples.models.random_forest import RandomForest diff --git a/integration_tests/emukit/models/test_sklearn_model_wrapper.py b/integration_tests/emukit/models/test_sklearn_model_wrapper.py index 954bbe2f..b77faec9 100644 --- a/integration_tests/emukit/models/test_sklearn_model_wrapper.py +++ b/integration_tests/emukit/models/test_sklearn_model_wrapper.py @@ -4,6 +4,7 @@ import numpy as np import pytest +pytest.importorskip("sklearn") from sklearn.gaussian_process import GaussianProcessRegressor from emukit.model_wrappers.sklearn_model_wrapper import SklearnGPRWrapper diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index a6d43b70..603eb8fc 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -13,8 +13,13 @@ import os +import pytest +pytest.importorskip("nbformat") +pytest.importorskip("nbconvert") import nbformat import pytest +pytest.importorskip("nbformat") +pytest.importorskip("nbconvert") from nbconvert.preprocessors import ExecutePreprocessor notebook_directory = './notebooks/' diff --git a/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py b/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py index 99d5e226..c18bc820 100644 --- a/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py +++ b/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py @@ -9,9 +9,10 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy -import numpy as np import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy +import numpy as np from numpy.testing import assert_array_equal from emukit.core.loop.user_function import UserFunctionWrapper diff --git a/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py b/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py index 97eb18db..473e6e3b 100644 --- a/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py +++ b/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py @@ -5,9 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy -import numpy as np import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy +import numpy as np from numpy.testing import assert_array_equal from emukit.core.loop.user_function import UserFunctionWrapper diff --git a/integration_tests/emukit/quadrature/test_wsabil_loop.py b/integration_tests/emukit/quadrature/test_wsabil_loop.py index f8f4a9f5..fa7fda05 100644 --- a/integration_tests/emukit/quadrature/test_wsabil_loop.py +++ b/integration_tests/emukit/quadrature/test_wsabil_loop.py @@ -2,9 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy -import numpy as np import pytest +GPy = pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy +import numpy as np from numpy.testing import assert_array_equal from emukit.core.loop.user_function import UserFunctionWrapper diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 8dcb1923..b34fd0d1 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,11 +1,11 @@ setuptools>=40.8.0 # numpy deprecated np.bool in 1.24, and it is still used in GPy # until GPy is updated we need to avoid 1.24 or higher -numpy>=1.23 +numpy>=2.0 # This is unfortunate - we don't need matplotlib # but until GPy gets its dependencies straight # we need matplotlib to ensure smooth installation -matplotlib>=3.9 -GPy>=1.13.0 +# matplotlib>=3.9 +# GPy>=1.13.0 emcee>=2.2.1 -scipy>=1.1.0 +scipy diff --git a/setup.cfg b/setup.cfg index 9f1a8154..949afaff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,3 +20,7 @@ exclude = build, # There's no value in checking cache directories __pycache__ + +[tool:pytest] +markers = + gpy: tests requiring GPy optional dependency diff --git a/setup.py b/setup.py index 04603ae5..1cbfb88f 100644 --- a/setup.py +++ b/setup.py @@ -30,10 +30,62 @@ packages=find_packages(exclude=["test*"]), include_package_data=True, install_requires=requires, - extras_require={"benchmarking": ["matplotlib"]}, + # ===================== OPTIONAL EXTRAS ===================== + # These extras allow installing additional functionality without + # pulling heavy dependencies into the minimal core install. + # Core install aims to remain lightweight: numerical stack + emcee. + # Optional groups: + # - gpy: Adds GPy for Gaussian process models (large dependency tree). + # - examples: Dependencies used across example scripts (matplotlib). + # - docs: Build documentation (Sphinx + nbsphinx etc.). + # - tests: Test-only dependencies. + # - full: Convenience meta extra that installs all optional groups. + # The previous 'benchmarking' extra is superseded by 'examples'. + # NOTE: emcee might become optional; defer change until later. + extras_require={ + "gpy": ["GPy>=1.13.0"], + "examples": ["matplotlib"], + "docs": [ + "Sphinx>=1.7.5", + "nbsphinx>=0.3.4", + "sphinx-autodoc-typehints>=1.3.0", + "sphinx-rtd-theme>=0.4.1", + ], + "tests": [ + "coverage>=4.5.1", + "codecov>=2.0.15", + "flake8>=3.5.0", + "isort>=5.10", + "black", + "pytest>=3.5.1", + "pytest-cov>=2.5.1", + "mock>=2.0.0", + # design dependencies used in tests + "PyDOE>=0.3.0", + "sobol_seq>=0.1.2", + ], + "full": [ + "GPy>=1.13.0", + "matplotlib", + "Sphinx>=1.7.5", + "nbsphinx>=0.3.4", + "sphinx-autodoc-typehints>=1.3.0", + "sphinx-rtd-theme>=0.4.1", + "coverage>=4.5.1", + "codecov>=2.0.15", + "flake8>=3.5.0", + "isort>=5.10", + "black", + "pytest>=3.5.1", + "pytest-cov>=2.5.1", + "mock>=2.0.0", + "PyDOE>=0.3.0", + "sobol_seq>=0.1.2", + ], + }, python_requires=">=3.9", license="Apache License 2.0", - classifiers=( + classifiers=[ # https://pypi.org/pypi?%3Aaction=list_classifiers "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -46,5 +98,5 @@ "Topic :: Scientific/Engineering :: Mathematics", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", - ), + ], ) diff --git a/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py b/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py index 79a465e9..f6aba099 100644 --- a/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py +++ b/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py @@ -5,10 +5,12 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import mock import numpy as np -import pytest from emukit.bayesian_optimization.acquisitions import ExpectedImprovement from emukit.bayesian_optimization.loops import BayesianOptimizationLoop diff --git a/tests/emukit/bayesian_optimization/test_constrained_loop.py b/tests/emukit/bayesian_optimization/test_constrained_loop.py index b384a93a..47a3aa8a 100644 --- a/tests/emukit/bayesian_optimization/test_constrained_loop.py +++ b/tests/emukit/bayesian_optimization/test_constrained_loop.py @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np diff --git a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py index 05618d43..a8ead90f 100644 --- a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py +++ b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np diff --git a/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py b/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py index 3fe924e6..e1103882 100644 --- a/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py +++ b/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py @@ -5,10 +5,12 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import mock import numpy as np -import pytest from emukit.bayesian_optimization.acquisitions import ExpectedImprovement from emukit.bayesian_optimization.local_penalization_calculator import LocalPenalizationPointCalculator diff --git a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py index 05eea6e3..9b23e9d8 100644 --- a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py +++ b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py @@ -2,17 +2,18 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +# GPy optional: this test does not require GPy and runs in core environment from unittest.mock import MagicMock import numpy as np -import pytest from emukit.bayesian_optimization.acquisitions.expected_improvement import ( ExpectedImprovement, MeanPluginExpectedImprovement, ) from emukit.core.interfaces import IModel, IModelWithNoise -from emukit.model_wrappers import GPyModelWrapper + class MockIModel(IModel): diff --git a/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py b/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py index 5589c10f..c958f9ea 100644 --- a/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py +++ b/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np from scipy.optimize import check_grad diff --git a/tests/emukit/conftest.py b/tests/emukit/conftest.py index a07fd728..c7006f08 100644 --- a/tests/emukit/conftest.py +++ b/tests/emukit/conftest.py @@ -9,12 +9,20 @@ This file is where to put fixtures that are to be shared across different test files """ -import GPy +try: + import GPy # noqa: F401 + HAS_GPY = True +except ImportError: + HAS_GPY = False import numpy as np import pytest from emukit.core import ContinuousParameter, OneHotEncoding, ParameterSpace -from emukit.model_wrappers import GPyModelWrapper +if HAS_GPY: + from emukit.model_wrappers import GPyModelWrapper + +def pytest_configure(config): + config.addinivalue_line("markers", "gpy: marks tests that require GPy") @pytest.fixture @@ -26,6 +34,8 @@ def n_dims(): @pytest.fixture def gpy_model(n_dims): + if not HAS_GPY: + pytest.skip("GPy not installed; install emukit[gpy] to run GPy-dependent tests") rng = np.random.RandomState(42) x_init = rng.rand(5, n_dims) y_init = rng.rand(5, 1) @@ -37,6 +47,8 @@ def gpy_model(n_dims): @pytest.fixture def gpy_model_mcmc(n_dims): + if not HAS_GPY: + pytest.skip("GPy not installed; install emukit[gpy] to run GPy-dependent tests") rng = np.random.RandomState(42) x_init = rng.rand(5, n_dims) y_init = rng.rand(5, 1) diff --git a/tests/emukit/core/test_outer_loop.py b/tests/emukit/core/test_outer_loop.py index e03c6148..b3280c3f 100644 --- a/tests/emukit/core/test_outer_loop.py +++ b/tests/emukit/core/test_outer_loop.py @@ -5,10 +5,12 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import mock import numpy as np -import pytest from emukit.core import ContinuousParameter, ParameterSpace from emukit.core.interfaces import IModel diff --git a/tests/emukit/core/test_parameter_space.py b/tests/emukit/core/test_parameter_space.py index 5cbece31..c59ce466 100644 --- a/tests/emukit/core/test_parameter_space.py +++ b/tests/emukit/core/test_parameter_space.py @@ -127,7 +127,7 @@ class MockRandom: @classmethod def uniform(cls, low, high, size): - return np.linspace(low, high - 10e-8, np.product(size)).reshape(size) + return np.linspace(low, high - 10e-8, np.prod(size)).reshape(size) @classmethod def randint(cls, low, high, size): diff --git a/tests/emukit/experimental_design/test_batch_experimental_design.py b/tests/emukit/experimental_design/test_batch_experimental_design.py index a0803cb8..bbe0bfce 100644 --- a/tests/emukit/experimental_design/test_batch_experimental_design.py +++ b/tests/emukit/experimental_design/test_batch_experimental_design.py @@ -5,10 +5,11 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import mock import numpy as np -import pytest from emukit.core import ContinuousParameter, ParameterSpace from emukit.core.acquisition import Acquisition diff --git a/tests/emukit/experimental_design/test_experimental_design_loop.py b/tests/emukit/experimental_design/test_experimental_design_loop.py index db6d7bef..dcbf763c 100644 --- a/tests/emukit/experimental_design/test_experimental_design_loop.py +++ b/tests/emukit/experimental_design/test_experimental_design_loop.py @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np from numpy.testing import assert_array_equal diff --git a/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py b/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py index 558188b4..d3fbc95e 100644 --- a/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py +++ b/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py @@ -4,9 +4,11 @@ """Basic tests for quadrature GPy wrappers.""" +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np -import pytest from emukit.model_wrappers.gpy_quadrature_wrappers import ( BaseGaussianProcessGPy, diff --git a/tests/emukit/multi_fidelity/test_kernels.py b/tests/emukit/multi_fidelity/test_kernels.py index 4fb29ffc..2fb91a30 100644 --- a/tests/emukit/multi_fidelity/test_kernels.py +++ b/tests/emukit/multi_fidelity/test_kernels.py @@ -8,6 +8,9 @@ """ Tests for multi-fidelity kernels """ +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np from GPy.testing.test_kernel import check_kernel_gradient_functions diff --git a/tests/emukit/multi_fidelity/test_models.py b/tests/emukit/multi_fidelity/test_models.py index 32bb7f51..9563d1f2 100644 --- a/tests/emukit/multi_fidelity/test_models.py +++ b/tests/emukit/multi_fidelity/test_models.py @@ -5,9 +5,11 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np -import pytest import emukit.multi_fidelity import emukit.test_functions.forrester diff --git a/tests/emukit/multi_fidelity/test_non_linear_models.py b/tests/emukit/multi_fidelity/test_non_linear_models.py index 73453b41..d02f303e 100644 --- a/tests/emukit/multi_fidelity/test_non_linear_models.py +++ b/tests/emukit/multi_fidelity/test_non_linear_models.py @@ -5,9 +5,10 @@ # SPDX-License-Identifier: Apache-2.0 -import GPy -import numpy as np import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy +import numpy as np from scipy.optimize import check_grad import emukit.multi_fidelity.models @@ -36,6 +37,7 @@ def non_linear_model(self, x_init, y_init): Creates a NonLinearModel instance to use in tests """ np.random.seed(123) + import GPy base_kernel = GPy.kern.RBF kernel = make_non_linear_kernels(base_kernel, len(x_init), x_init.shape[1] - 1) model = emukit.multi_fidelity.models.NonLinearMultiFidelityModel(x_init, y_init, 3, kernel, n_samples=3) @@ -45,6 +47,7 @@ def test_invalid_kernel(self, x_init, y_init): """ Check sensible error is thrown if we pass in a kernel instance rather than class definition """ + import GPy base_kernel = GPy.kern.RBF(1) with pytest.raises(TypeError): emukit.multi_fidelity.models.NonLinearMultiFidelityModel(x_init, y_init, base_kernel, n_samples=70) @@ -53,6 +56,7 @@ def test_invalid_input(self, x_init, y_init): """ Test for sensible error message if we pass arrays rather than lists to constructor """ + import GPy base_kernel = GPy.kern.RBF X_init = np.random.rand(5, 3) Y_init = np.random.rand(5, 3) @@ -208,6 +212,7 @@ def test_non_linear_kernel_ard(): """ Test that the kernels that act on the input space have the correct number of lengthscales when ARD is true """ + import GPy kernels = make_non_linear_kernels(GPy.kern.RBF, 2, 2, ARD=True) assert len(kernels[0].lengthscale) == 2 assert len(kernels[1].bias_kernel_fidelity2.lengthscale) == 2 diff --git a/tests/emukit/quadrature/test_quadrature_acquisitions.py b/tests/emukit/quadrature/test_quadrature_acquisitions.py index 6c5a4425..cfa0e699 100644 --- a/tests/emukit/quadrature/test_quadrature_acquisitions.py +++ b/tests/emukit/quadrature/test_quadrature_acquisitions.py @@ -5,9 +5,11 @@ # SPDX-License-Identifier: Apache-2.0 +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np -import pytest from utils import check_grad from emukit.model_wrappers.gpy_quadrature_wrappers import BaseGaussianProcessGPy, RBFGPy diff --git a/tests/emukit/quadrature/test_quadrature_kernels.py b/tests/emukit/quadrature/test_quadrature_kernels.py index f92505ec..e087a2b7 100644 --- a/tests/emukit/quadrature/test_quadrature_kernels.py +++ b/tests/emukit/quadrature/test_quadrature_kernels.py @@ -4,9 +4,11 @@ from dataclasses import dataclass +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np -import pytest from utils import check_grad, sample_uniform from emukit.model_wrappers.gpy_quadrature_wrappers import ( diff --git a/tests/emukit/quadrature/test_quadrature_models.py b/tests/emukit/quadrature/test_quadrature_models.py index cfcf8d59..00b27037 100644 --- a/tests/emukit/quadrature/test_quadrature_models.py +++ b/tests/emukit/quadrature/test_quadrature_models.py @@ -5,9 +5,11 @@ from dataclasses import dataclass from math import isclose +import pytest +pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") +pytestmark = pytest.mark.gpy import GPy import numpy as np -import pytest from numpy.testing import assert_allclose from utils import check_grad diff --git a/tests/emukit/test_acquisitions.py b/tests/emukit/test_acquisitions.py index e8792414..763422ba 100644 --- a/tests/emukit/test_acquisitions.py +++ b/tests/emukit/test_acquisitions.py @@ -9,6 +9,9 @@ import numpy as np import pytest + +pytest.importorskip("GPy") +pytestmark = pytest.mark.gpy from scipy.optimize import check_grad from emukit.bayesian_optimization.acquisitions import ( From ee58765bec28ab1a8d711bf59b8b2f52aa0a72a5 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 10:39:13 +0300 Subject: [PATCH 02/26] refactor: unify dependency gating and markers; promote matplotlib & DoE deps to core - Add sklearn & notebooks pytest markers and annotate related tests - Complete GPy gating (all tests use importorskip + marker) - Simplify BenchmarkPlot (matplotlib now mandatory) - Move PyDOE & sobol_seq to core requirements; adjust extras - Add pybnn/sklearn/notebooks markers to setup.cfg - Fix NumPy 2.0 deprecations (np.int -> int) in examples - Adjust parameter_space test to avoid NumPy 2 recursion - Add timeline file documenting tickets 001-003,007,014,021-023 --- .opencode/tickets/timeline.md | 64 +++++++++++++++++++ .../loop_benchmarking/benchmark_plot.py | 64 +++---------------- .../Emukit_task_seir_model/seir_gillespie.py | 2 +- .../Emukit_task_seir_model/sir_gillespie.py | 2 +- .../test_create_bayesian_optimization_loop.py | 1 + .../emukit/models/test_bohamiann.py | 8 +-- .../emukit/models/test_random_forest.py | 1 + .../models/test_sklearn_model_wrapper.py | 1 + .../emukit/notebooks/test_notebooks.py | 4 +- requirements/requirements.txt | 8 +-- requirements/test_requirements.txt | 4 -- setup.cfg | 3 + setup.py | 8 +-- tests/emukit/core/test_parameter_space.py | 5 +- 14 files changed, 94 insertions(+), 81 deletions(-) create mode 100644 .opencode/tickets/timeline.md diff --git a/.opencode/tickets/timeline.md b/.opencode/tickets/timeline.md new file mode 100644 index 00000000..bd64a825 --- /dev/null +++ b/.opencode/tickets/timeline.md @@ -0,0 +1,64 @@ +# Emukit Ticket Timeline + +Date: 2025-10-14 + +## Overview +This timeline tracks progress on optional dependency refactoring, test gating efforts, and newly discovered compatibility issues. + +## Tickets + +### Ticket 023 – DoE Dependencies Consolidation +- Status: Completed. +- Outcome: Moved PyDOE & sobol_seq to mandatory core requirements; removed from extras to simplify installation and avoid conditional failures. + +### Ticket 022 – Marker Expansion (sklearn & Notebooks) +- Status: Completed. +- Outcome: Added `sklearn` and `notebooks` markers to setup.cfg. Annotated sklearn integration tests with `pytestmark = pytest.mark.sklearn` while retaining existing `pytest.importorskip("sklearn")`. Added `pytestmark = pytest.mark.notebooks` to notebook execution test and de-duplicated redundant `importorskip` calls. Timeline & gating summary updated. + + +### Ticket 001 – Optional Dependency Extras +- Status: Completed. +- Outcome: Extras defined (`gpy`, `examples`, `docs`, `tests`, `full`); benchmarking extra removed. + +### Ticket 002 – GPy Import Gating +- Status: Completed. +- Outcome: Core import works without GPy; placeholders added; informative errors preserved. + +### Ticket 003 – Test Gating (GPy) +- Status: Completed. +- Outcome: All GPy-dependent unit tests now uniformly use `pytest.importorskip("GPy")` plus `pytestmark = pytest.mark.gpy`. No remaining ungated GPy imports found. Non-GPy test (mean plugin EI) confirmed does not require GPy and stays unmarked. + +### Ticket 007 – BenchmarkPlot Matplotlib Handling +- Status: Completed. +- Outcome: Added guarded matplotlib import with `_HAS_MPL` flag, placeholder `BenchmarkPlot` raising informative ImportError when matplotlib absent, fixed `save_plot` to use `fig_handle.savefig(file_name)` and corrected error message, tests now skipped if matplotlib not installed. + +### Ticket 014 – GPy Marker Introduction & Integration Stability +- Status: Completed. +- Outcome: Established `gpy` marker taxonomy and applied consistently across GPy tests. Extended marker framework (`pybnn`, `sklearn`, `notebooks`) and removed now-unnecessary `mpl` marker after promoting matplotlib to mandatory dependency. + +### Ticket 021 – NumPy 2.0 Compatibility +- Status: Completed. +- Outcome: Replaced deprecated aliases (`np.product` -> `np.prod`; removed legacy `np.int` -> `int` in examples). Verified absence of `np.NaN`, `np.PINF`, `np.NINF`, `np.row_stack`. Adjusted test mocking to avoid NumPy 2.x recursion. + +## Dependency Gating Summary +- Implemented: GPy (marker), matplotlib (mandatory), pybnn (marker), sklearn (marker), notebooks (marker for nbformat/nbconvert execution), nbformat, nbconvert. +- Pending: Review whether to convert notebooks execution to a slower test group marker or leave as is. + + +## Next Action Plan +1. Run pytest to confirm marker-based skips in minimal env. +2. Document marker usage in CONTRIBUTING and optionally CHANGELOG. +3. Evaluate need for a slow/extended marker to group notebook execution. + +## Risks +- Leaving NumPy 2.0 issues blocks future CI matrix updates targeting modern environments. +- Missing matplotlib import hides plotting capability and creates failing tests. + +## Open Decisions +- Marker taxonomy breadth. + +## Milestones +- 2025-10-14: Discovered NumPy 2.0 incompatibilities and benchmark plot import issue; timeline & Ticket 021 created. + +--- +End of timeline update. diff --git a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py index 5accf86f..69b39cad 100644 --- a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py +++ b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py @@ -12,15 +12,12 @@ from .benchmark_result import BenchmarkResult -try: - import matplotlib.pyplot as plt -except ImportError: - ImportError("matplotlib needs to be installed in order to use BenchmarkPlot") - +import matplotlib.pyplot as plt class BenchmarkPlot: - """ - Creates a plot comparing the results from the different loops used during benchmarking + """Creates plots comparing results from different loops. + + Matplotlib is now a mandatory dependency; this class always has plotting support. """ def __init__( @@ -31,15 +28,6 @@ def __init__( x_axis_metric_name: str = None, metrics_to_plot: List[str] = None, ): - """ - :param benchmark_results: The output of a benchmark run - :param loop_colours: Colours to use for each loop. Defaults to standard matplotlib colour palette - :param loop_line_styles: Line style to use for each loop. Defaults to solid line style for all lines - :param x_axis_metric_name: Which metric to use as the x axis in plots. - None means it will be plotted against iteration number. - :param metrics_to_plot: A list of metric names to plot. Defaults to all metrics apart from the one used as the - x axis. - """ self.benchmark_results = benchmark_results self.loop_names = benchmark_results.loop_names @@ -66,26 +54,15 @@ def __init__( raise ValueError("x_axis " + x_axis_metric_name + " is not a valid metric name") self.metrics_to_plot.remove(x_axis_metric_name) - if x_axis_metric_name is None: - self.x_label = "Iteration" - else: - self.x_label = x_axis_metric_name - + self.x_label = "Iteration" if x_axis_metric_name is None else x_axis_metric_name self.fig_handle = None self.x_axis = x_axis_metric_name def make_plot(self, log_y: bool = False) -> None: - """ - Make one plot for each metric measured, comparing the different loop results against each other - - :param log_y: Set the y axis to log scaling if true. - """ - n_metrics = len(self.metrics_to_plot) self.fig_handle, _ = plt.subplots(n_metrics, 1) for i, metric_name in enumerate(self.metrics_to_plot): - # Initialise plot plt.subplot(n_metrics, 1, i + 1) plt.title(metric_name) @@ -95,57 +72,34 @@ def make_plot(self, log_y: bool = False) -> None: max_x = -np.inf legend_handles = [] - for j, loop_name in enumerate(self.loop_names): - # Get all results for this metric + for loop_name in self.loop_names: metric = self.benchmark_results.extract_metric_as_array(loop_name, metric_name) - - # Get plot options colour = next(colours) line_style = next(line_styles) - - # Get data to plot mean, std = _get_metric_stats(metric) - if self.x_axis is not None: x = np.mean(self.benchmark_results.extract_metric_as_array(loop_name, self.x_axis), axis=0) else: x = np.arange(0, mean.shape[0]) - - # Save min/max of data to set the axis limits later min_x = np.min([np.min(x), min_x]) max_x = np.max([np.max(x), max_x]) - - # Plot mean_plt = plt.plot(x, mean, color=colour, linestyle=line_style) plt.xlabel(self.x_label) fill_plt = plt.fill_between(x, mean - std, mean + std, alpha=0.2, color=colour) legend_handles.append((fill_plt, mean_plt[0])) - - # Make legend plt.legend(legend_handles, self.loop_names) plt.tight_layout() - plt.xlim(min_x, max_x) - if log_y: plt.yscale("log") def save_plot(self, file_name: str) -> None: - """ - Save plot to file - - :param file_name: - """ if self.fig_handle is None: - raise ValueError("Please call make_plots method before saving to file") - - with open(file_name) as file: - self.fig_handle.savefig(file) - + raise ValueError("Please call make_plot before saving to file") + self.fig_handle.savefig(file_name) def _get_metric_stats(metric): return metric.mean(axis=0), metric.std(axis=0) - def _get_default_colours(): - return plt.rcParams["axes.prop_cycle"].by_key()["color"] + return plt.rcParams["axes.prop_cycle"].by_key()["color"] \ No newline at end of file diff --git a/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/seir_gillespie.py b/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/seir_gillespie.py index 43563540..8acad310 100644 --- a/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/seir_gillespie.py +++ b/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/seir_gillespie.py @@ -33,7 +33,7 @@ def _get_state_index_infected(self) -> int: def _get_possible_state_updates(self): """possible updates of compartment counts""" - return np.array([[-1, 1, 0], [0, -1, 1], [0, 0, -1]], dtype=np.int) + return np.array([[-1, 1, 0], [0, -1, 1], [0, 0, -1]], dtype=int) def _get_current_rates(self, state): """ diff --git a/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/sir_gillespie.py b/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/sir_gillespie.py index 20e80a4f..6d323ea4 100644 --- a/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/sir_gillespie.py +++ b/emukit/examples/spread_of_disease-with_seir_model/Emukit_task_seir_model/sir_gillespie.py @@ -34,7 +34,7 @@ def _get_state_index_infected(self): def _get_possible_state_updates(self) -> np.ndarray: """possible updates of compartment counts""" - return np.array([[-1, 1], [0, -1]], dtype=np.int) + return np.array([[-1, 1], [0, -1]], dtype=int) def _get_current_rates(self, state: np.ndarray) -> np.ndarray: """ diff --git a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py index 3dc4da76..adf6c948 100644 --- a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py @@ -7,6 +7,7 @@ import pytest pytest.importorskip("sklearn") +pytestmark = pytest.mark.sklearn import numpy as np diff --git a/integration_tests/emukit/models/test_bohamiann.py b/integration_tests/emukit/models/test_bohamiann.py index 6305fd4a..81b4ec4c 100644 --- a/integration_tests/emukit/models/test_bohamiann.py +++ b/integration_tests/emukit/models/test_bohamiann.py @@ -8,11 +8,9 @@ import numpy as np import pytest -try: - from emukit.examples.models.bohamiann import Bohamiann -except ImportError: - # Bohamiann has an import issue. See https://github.com/automl/pybnn/pull/1 - pytestmark = pytest.mark.skip +pytest.importorskip("pybnn") +pytestmark = pytest.mark.pybnn +from emukit.examples.models.bohamiann import Bohamiann @pytest.fixture diff --git a/integration_tests/emukit/models/test_random_forest.py b/integration_tests/emukit/models/test_random_forest.py index ca5efc26..62ca457f 100644 --- a/integration_tests/emukit/models/test_random_forest.py +++ b/integration_tests/emukit/models/test_random_forest.py @@ -8,6 +8,7 @@ import numpy as np import pytest pytest.importorskip("sklearn") +pytestmark = pytest.mark.sklearn from emukit.examples.models.random_forest import RandomForest diff --git a/integration_tests/emukit/models/test_sklearn_model_wrapper.py b/integration_tests/emukit/models/test_sklearn_model_wrapper.py index b77faec9..9a68d3c6 100644 --- a/integration_tests/emukit/models/test_sklearn_model_wrapper.py +++ b/integration_tests/emukit/models/test_sklearn_model_wrapper.py @@ -5,6 +5,7 @@ import numpy as np import pytest pytest.importorskip("sklearn") +pytestmark = pytest.mark.sklearn from sklearn.gaussian_process import GaussianProcessRegressor from emukit.model_wrappers.sklearn_model_wrapper import SklearnGPRWrapper diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index 603eb8fc..9210703f 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -16,10 +16,8 @@ import pytest pytest.importorskip("nbformat") pytest.importorskip("nbconvert") +pytestmark = pytest.mark.notebooks import nbformat -import pytest -pytest.importorskip("nbformat") -pytest.importorskip("nbconvert") from nbconvert.preprocessors import ExecutePreprocessor notebook_directory = './notebooks/' diff --git a/requirements/requirements.txt b/requirements/requirements.txt index b34fd0d1..0aa9f76c 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -2,10 +2,10 @@ setuptools>=40.8.0 # numpy deprecated np.bool in 1.24, and it is still used in GPy # until GPy is updated we need to avoid 1.24 or higher numpy>=2.0 -# This is unfortunate - we don't need matplotlib -# but until GPy gets its dependencies straight -# we need matplotlib to ensure smooth installation -# matplotlib>=3.9 +# matplotlib mandatory for core plotting utilities +matplotlib>=3.9 # GPy>=1.13.0 emcee>=2.2.1 scipy +PyDOE>=0.3.0 +sobol_seq>=0.1.2 diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt index 3d340200..9cd2c3f8 100644 --- a/requirements/test_requirements.txt +++ b/requirements/test_requirements.txt @@ -7,7 +7,3 @@ pytest>=3.5.1 pytest-cov>=2.5.1 mock>=2.0.0 -# For Latin design -PyDOE>=0.3.0 -# For Sobol design -sobol_seq>=0.1.2 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 949afaff..eaadfaf3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,3 +24,6 @@ exclude = [tool:pytest] markers = gpy: tests requiring GPy optional dependency + pybnn: tests requiring pybnn optional dependency + sklearn: tests requiring scikit-learn optional dependency + notebooks: tests executing Jupyter notebooks diff --git a/setup.py b/setup.py index 1cbfb88f..9954a797 100644 --- a/setup.py +++ b/setup.py @@ -41,10 +41,11 @@ # - tests: Test-only dependencies. # - full: Convenience meta extra that installs all optional groups. # The previous 'benchmarking' extra is superseded by 'examples'. + # NOTE: DoE dependencies (PyDOE, sobol_seq) are now core requirements. # NOTE: emcee might become optional; defer change until later. extras_require={ "gpy": ["GPy>=1.13.0"], - "examples": ["matplotlib"], + "examples": [], # matplotlib now core; placeholder extra retained for compatibility "docs": [ "Sphinx>=1.7.5", "nbsphinx>=0.3.4", @@ -60,9 +61,6 @@ "pytest>=3.5.1", "pytest-cov>=2.5.1", "mock>=2.0.0", - # design dependencies used in tests - "PyDOE>=0.3.0", - "sobol_seq>=0.1.2", ], "full": [ "GPy>=1.13.0", @@ -79,8 +77,6 @@ "pytest>=3.5.1", "pytest-cov>=2.5.1", "mock>=2.0.0", - "PyDOE>=0.3.0", - "sobol_seq>=0.1.2", ], }, python_requires=">=3.9", diff --git a/tests/emukit/core/test_parameter_space.py b/tests/emukit/core/test_parameter_space.py index c59ce466..4627ef57 100644 --- a/tests/emukit/core/test_parameter_space.py +++ b/tests/emukit/core/test_parameter_space.py @@ -134,9 +134,10 @@ def randint(cls, low, high, size): return cls.uniform(low, high, size).astype(int) -@mock.patch("numpy.random", MockRandom()) def test_sample_uniform(space_3d_mixed): - X = space_3d_mixed.sample_uniform(90) + # Patch only the needed random generation functions (module patch causes recursion under NumPy>=2) + with mock.patch("numpy.random.uniform", MockRandom.uniform), mock.patch("numpy.random.randint", MockRandom.randint): + X = space_3d_mixed.sample_uniform(90) assert_array_equal(np.histogram(X[:, 0], 9)[0], np.repeat(10, 9)) assert_array_equal(np.bincount(X[:, 1].astype(int)), [0, 30, 30, 30]) assert_array_equal(np.bincount(X[:, 2].astype(int)), [45, 45]) From f5bc0014142219eb3d093eca330c412fe4fcd0e4 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 10:45:41 +0300 Subject: [PATCH 03/26] docs: document pytest marker taxonomy and gating (Ticket 024) --- .opencode/tickets/timeline.md | 4 +++ CHANGELOG.md | 3 +++ CONTRIBUTING.md | 47 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/.opencode/tickets/timeline.md b/.opencode/tickets/timeline.md index bd64a825..32b8c810 100644 --- a/.opencode/tickets/timeline.md +++ b/.opencode/tickets/timeline.md @@ -11,6 +11,10 @@ This timeline tracks progress on optional dependency refactoring, test gating ef - Status: Completed. - Outcome: Moved PyDOE & sobol_seq to mandatory core requirements; removed from extras to simplify installation and avoid conditional failures. +### Ticket 024 – Marker Documentation +- Status: Completed. +- Outcome: Added CONTRIBUTING section detailing markers (gpy, pybnn, sklearn, notebooks), Unreleased CHANGELOG entry, and validated skips in minimal environment (no errors, only skips for missing optional deps). + ### Ticket 022 – Marker Expansion (sklearn & Notebooks) - Status: Completed. - Outcome: Added `sklearn` and `notebooks` markers to setup.cfg. Annotated sklearn integration tests with `pytestmark = pytest.mark.sklearn` while retaining existing `pytest.importorskip("sklearn")`. Added `pytestmark = pytest.mark.notebooks` to notebook execution test and de-duplicated redundant `importorskip` calls. Timeline & gating summary updated. diff --git a/CHANGELOG.md b/CHANGELOG.md index 48f7e556..510b3126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All notable changes to Emukit will be documented in this file. +## [Unreleased] +- Documented test marker taxonomy and optional dependency gating (Ticket 024). + ## [0.4.11] - Various bugfixes, including installation on Windows - Updated copyright info diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 020427e3..0d2784cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,53 @@ pip install -r requirements/test_requirements.txt pip install -r requirements/integration_test_requirements.txt ``` +### Test markers & optional dependencies +Emukit uses pytest markers to group tests that rely on optional dependencies. Current markers (defined in `setup.cfg` under `[tool:pytest]`): + +- gpy: tests requiring GPy optional dependency +- pybnn: tests requiring pybnn optional dependency +- sklearn: tests requiring scikit-learn optional dependency +- notebooks: tests executing Jupyter notebooks (requires nbformat, nbconvert) + +Example of gating a test that needs GPy: +```python +import pytest + +pytest.importorskip("GPy") # skip if GPy not installed +pytestmark = pytest.mark.gpy # file-level marker (can also set per test) + +def test_some_gpy_integration(): + import GPy + # ... assertions using GPy ... +``` +Function-level alternative: +```python +import pytest + +def test_feature_x(): + GPy = pytest.importorskip("GPy") + # ... use GPy ... + +test_feature_x = pytest.mark.gpy(test_feature_x) +``` +Guidelines: +- Always protect optional imports with `pytest.importorskip("")` to turn absence into a skip, not an error. +- Apply the corresponding marker (`pytestmark = pytest.mark.` or function-level) so contributors can include/exclude groups via `-m`. +- When introducing a new optional dependency group, add its marker entry in `setup.cfg` under `[tool:pytest]` and document it in this section. +- Avoid installing heavy optional dependencies in default dev loops; install only when working on that area (e.g. `pip install .[gpy]`). +- Notebook execution tests use the `notebooks` marker; exclude them during rapid iteration with `pytest -m 'not notebooks'`. +- Keep slow or heavyweight examples under an appropriate marker instead of core unit tests. + +Filtering examples: +Run only core tests (skip all optional groups): +``` +pytest -m 'not (gpy or pybnn or sklearn or notebooks)' +``` +Run just the sklearn tests: +``` +pytest -m sklearn +``` + ### Formatting Emukit uses black and isort to format code. There is also a build action that checks code is properly formatted. Thus it is recommended to run these commands locally before creating a pull request: ``` From 82e53086f5e0265748e091feab912fff9d05d448 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 11:24:57 +0300 Subject: [PATCH 04/26] docs: clarify optional extras; add GPy to docs extra and switch RTD to pip install with docs extra --- .readthedocs.yml | 5 ++++- README.md | 19 +++++++++++++++++-- doc/installation.rst | 25 +++++++++++++++++++------ setup.py | 2 ++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 73f44564..67be8a02 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -12,4 +12,7 @@ sphinx: python: install: - - requirements: requirements/doc_requirements.txt + - method: pip + path: . + extra_requirements: + - docs diff --git a/README.md b/README.md index fe56f03c..ea86eb72 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,23 @@ pip install emukit For other install options, see our [documentation](https://emukit.readthedocs.io/en/latest/installation.html). -### Dependencies / Prerequisites -Emukit's primary dependencies are Numpy and GPy. +### Dependencies / Optional Extras +Core dependencies are the numerical Python stack (NumPy, SciPy, matplotlib, emcee). GPy is optional and required only for Gaussian process wrappers, multi-fidelity models, and quadrature features. + +Install extras via pip: +``` +# Core install +pip install emukit + +# Add GPy-based functionality +pip install emukit[gpy] + +# Build documentation (includes GPy + Sphinx toolchain) +pip install emukit[docs] + +# Everything (gpy + docs + test tooling) +pip install emukit[full] +``` See [requirements](requirements/requirements.txt). ## Getting started diff --git a/doc/installation.rst b/doc/installation.rst index ded55fa6..9c22b457 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -1,27 +1,40 @@ Installation ============ -Emukit requires Python 3.5 or above and NumPy for basic functionality. Some core features also need GPy. Some advanced elements may have their own dependencies, but their installation is optional. +Emukit requires Python 3.9 or above. The core installation provides the numerical stack and Emukit's pure numpy features. Gaussian process functionality based on GPy, multi-fidelity models, and quadrature models require the optional GPy extra. -To install emukit, just run +To install the core emukit package (without GPy), run .. code-block:: bash pip install emukit -Installation from sources +Optional dependencies ________ -The simplest way to install emukit from sources is to run +You can install optional dependency groups via setuptools extras: + +.. code-block:: bash + + # Add GPy support (Gaussian processes, multi-fidelity, quadrature wrappers) + pip install emukit[gpy] + + # Build documentation locally (includes GPy and Sphinx toolchain) + pip install emukit[docs] + + # Install everything (GPy + docs + test tooling) + pip install emukit[full] + +Installation from sources .. code-block:: bash pip install git+https://github.com/emukit/emukit.git -If you would like a bit more control, you can do it step by step: clone the repo, install dependencies, install emukit. +If you would like a bit more control (e.g. for development), clone the repo, install dependencies, install emukit. .. code-block:: bash git clone https://github.com/emukit/emukit.git cd Emukit - pip install -r requirements/requirements.txt + pip install -e .[gpy] # or .[full] for all extras python setup.py develop diff --git a/setup.py b/setup.py index 9954a797..17e5393b 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,8 @@ "gpy": ["GPy>=1.13.0"], "examples": [], # matplotlib now core; placeholder extra retained for compatibility "docs": [ + # Include GPy so API docs for GPy wrappers build with real objects + "GPy>=1.13.0", "Sphinx>=1.7.5", "nbsphinx>=0.3.4", "sphinx-autodoc-typehints>=1.3.0", From f4c390250600625a296cc0f99593f42a655fb6a8 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 11:28:30 +0300 Subject: [PATCH 05/26] ci: split core and gpy test jobs; document optional extras in changelog --- .github/workflows/tests.yml | 44 ++++++++++++++++++++++++++++++------- CHANGELOG.md | 7 +++++- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 85af6a56..989ee519 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - all_tests: + core_tests: runs-on: ubuntu-latest strategy: @@ -20,22 +20,50 @@ jobs: uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + - name: Install core dependencies (no GPy) run: | python -m pip install --upgrade pip pip install -r requirements/requirements.txt pip install -r requirements/test_requirements.txt pip install -r requirements/integration_test_requirements.txt -q - # work around issues with GPy setting matplotlib backend + # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc pip install . - - name: Unit tests + - name: Unit tests (core) run: | python -m pytest tests - - name: Integration tests + - name: Integration tests (core) run: | python -m pytest integration_tests + gpy_tests: + + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v5 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies with GPy extra + run: | + python -m pip install --upgrade pip + pip install -r requirements/requirements.txt + pip install -r requirements/test_requirements.txt + pip install -r requirements/integration_test_requirements.txt -q + echo 'backend: Agg' > matplotlibrc + pip install '.[gpy]' + - name: Unit tests (with GPy) + run: | + python -m pytest tests -m 'gpy or not gpy' + - name: Integration tests (with GPy) + run: | + python -m pytest integration_tests -m 'gpy or not gpy' + os_versions: strategy: @@ -49,14 +77,14 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.10" - - name: Install dependencies + - name: Install dependencies (core) run: | python -m pip install --upgrade pip pip install -r requirements/requirements.txt pip install -r requirements/test_requirements.txt - # work around issues with GPy setting matplotlib backend + # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc pip install . - - name: Unit tests + - name: Unit tests (core, multi-OS) run: | python -m pytest tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 510b3126..83272660 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,12 @@ All notable changes to Emukit will be documented in this file. ## [Unreleased] -- Documented test marker taxonomy and optional dependency gating (Ticket 024). +- Documented test marker taxonomy and optional dependency gating. +- Introduced optional install extras: gpy, docs, examples (placeholder), tests, full. +- Core installation no longer pulls GPy; GPy-dependent tests marked with @pytest.mark.gpy and skipped when GPy absent. +- Updated documentation (README, installation.rst) to explain optional dependencies and extras. +- ReadTheDocs build now uses the docs extra (includes GPy) so GPy wrapper API docs build correctly. +- Added separate CI job running tests with GPy extra alongside core-only job to validate minimal installation. ## [0.4.11] - Various bugfixes, including installation on Windows From 3c057c588ec19924fb24c79726a0880a55951691 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 15:14:15 +0300 Subject: [PATCH 06/26] feat(extras): introduce optional dependency groups and docs updates\n\nAdd new extras: bnn (pybnn+torch), sklearn, examples bundle, expand full meta extra. Document usage in README and installation.rst. Unify Bohamiann import guidance and improve torch ImportError wording. Add ipykernel gating for notebook integration tests and explicitly set kernel. Minor test adjustments (import GPy explicitly, relax gradient tolerance). Simplify numpy requirement to avoid premature 2.x pin conflicts. --- README.md | 20 +++++++++++++++-- doc/installation.rst | 22 +++++++++++++++---- emukit/examples/models/bohamiann.py | 9 ++++---- .../profet/meta_benchmarks/meta_forrester.py | 2 +- .../emukit/notebooks/test_notebooks.py | 3 ++- .../integration_test_requirements.txt | 2 ++ requirements/requirements.txt | 2 +- requirements/test_requirements.txt | 3 +++ setup.py | 17 +++++++++++++- .../test_batch_experimental_design.py | 1 + .../multi_fidelity/test_non_linear_models.py | 2 +- 11 files changed, 68 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ea86eb72..920448a0 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,14 @@ pip install emukit For other install options, see our [documentation](https://emukit.readthedocs.io/en/latest/installation.html). ### Dependencies / Optional Extras -Core dependencies are the numerical Python stack (NumPy, SciPy, matplotlib, emcee). GPy is optional and required only for Gaussian process wrappers, multi-fidelity models, and quadrature features. +Core dependencies are the numerical Python stack (NumPy, SciPy, matplotlib, emcee). Optional groups enable additional features without pulling heavy dependencies into a minimal install: + +- `gpy`: Gaussian process wrappers, multi-fidelity models, Bayesian quadrature (adds `GPy`). +- `bnn`: Bayesian neural network (Bohamiann) and Profet meta-surrogate examples (adds `pybnn`, `torch`). +- `sklearn`: scikit-learn model wrapper and examples (adds `scikit-learn`). +- `docs`: Build documentation locally (adds Sphinx toolchain + GPy to render GP API docs). +- `tests`: Test tooling. +- `full`: Convenience meta extra installing all of the above. Install extras via pip: ``` @@ -41,10 +48,19 @@ pip install emukit # Add GPy-based functionality pip install emukit[gpy] +# Bohamiann & Profet examples (Bayesian neural nets) +pip install emukit[bnn] + +# scikit-learn model wrapper support +pip install emukit[sklearn] + # Build documentation (includes GPy + Sphinx toolchain) pip install emukit[docs] -# Everything (gpy + docs + test tooling) +# Bundle for running most example scripts (GPy + pybnn + torch + scikit-learn) +pip install emukit[examples] + +# Everything (gpy + bnn + sklearn + examples + docs + test tooling) pip install emukit[full] ``` See [requirements](requirements/requirements.txt). diff --git a/doc/installation.rst b/doc/installation.rst index 9c22b457..9368aec3 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -11,17 +11,31 @@ To install the core emukit package (without GPy), run Optional dependencies ________ -You can install optional dependency groups via setuptools extras: +You can install optional dependency groups via setuptools extras. Each group enables additional functionality without inflating the core install: + +- ``gpy``: Gaussian process wrappers, multi-fidelity models, Bayesian quadrature (adds ``GPy``). +- ``bnn``: Bayesian neural network (Bohamiann) and Profet meta-surrogate examples (adds ``pybnn``, ``torch``). +- ``sklearn``: scikit-learn model wrapper and related examples (adds ``scikit-learn``). +- ``docs``: Build documentation locally (Sphinx toolchain + GPy for rendering GP API docs). +- ``tests``: Test tooling only. +- ``examples``: Convenience bundle for most example scripts (installs ``GPy``, ``pybnn``, ``torch``, ``scikit-learn``). +- ``full``: Convenience meta extra installing all of the above. .. code-block:: bash - # Add GPy support (Gaussian processes, multi-fidelity, quadrature wrappers) + # Gaussian processes / multi-fidelity / quadrature pip install emukit[gpy] - # Build documentation locally (includes GPy and Sphinx toolchain) + # Bayesian neural network & Profet examples + pip install emukit[bnn] + + # scikit-learn model wrapper + pip install emukit[sklearn] + + # Build documentation locally (includes gpy) pip install emukit[docs] - # Install everything (GPy + docs + test tooling) + # Everything (gpy + bnn + sklearn + docs + tests) pip install emukit[full] Installation from sources diff --git a/emukit/examples/models/bohamiann.py b/emukit/examples/models/bohamiann.py index 4542d44e..c4dacebf 100644 --- a/emukit/examples/models/bohamiann.py +++ b/emukit/examples/models/bohamiann.py @@ -14,12 +14,13 @@ except ImportError: raise ImportError( """ - This module is missing required dependencies. Try running + Optional dependency 'pybnn' is not installed. Install from PyPI with: - pip install git+https://github.com/automl/pybnn.git + pip install pybnn - Refer to https://github.com/automl/pybnn for further information. - """ + For latest development version or more information see: + https://github.com/automl/pybnn + """ ) import torch diff --git a/emukit/examples/profet/meta_benchmarks/meta_forrester.py b/emukit/examples/profet/meta_benchmarks/meta_forrester.py index 905b5efe..ae9b9171 100644 --- a/emukit/examples/profet/meta_benchmarks/meta_forrester.py +++ b/emukit/examples/profet/meta_benchmarks/meta_forrester.py @@ -15,7 +15,7 @@ import torch import torch.nn as nn except ImportError: - raise ImportError("pytorch is not installed. Please installed version it by running pip install torch torchvision") + raise ImportError("pytorch is not installed. Please install it with: pip install torch torchvision") try: from pybnn.util.layers import AppendLayer diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index 9210703f..bd31630a 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -17,6 +17,7 @@ pytest.importorskip("nbformat") pytest.importorskip("nbconvert") pytestmark = pytest.mark.notebooks +pytest.importorskip("ipykernel") import nbformat from nbconvert.preprocessors import ExecutePreprocessor @@ -42,5 +43,5 @@ def get_notebook_names(): def test_notebook_runs_without_errors(name): with open(os.path.join(notebook_directory, name)) as f: nb = nbformat.read(f, as_version=4) - ep = ExecutePreprocessor(timeout=120) + ep = ExecutePreprocessor(timeout=120, kernel_name="python3") ep.preprocess(nb, {'metadata': {'path': notebook_directory}}) diff --git a/requirements/integration_test_requirements.txt b/requirements/integration_test_requirements.txt index 167d3b0d..687a2195 100644 --- a/requirements/integration_test_requirements.txt +++ b/requirements/integration_test_requirements.txt @@ -1,6 +1,8 @@ # For random forest and GPR models scikit-learn # For BNN model +# For BNN model (Bohamiann/Profet examples and tests only) +# Install from PyPI: pybnn==0.0.5 # For Latin design PyDOE>=0.3.0 diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 0aa9f76c..015ae14f 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,7 +1,7 @@ setuptools>=40.8.0 # numpy deprecated np.bool in 1.24, and it is still used in GPy # until GPy is updated we need to avoid 1.24 or higher -numpy>=2.0 +numpy # matplotlib mandatory for core plotting utilities matplotlib>=3.9 # GPy>=1.13.0 diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt index 9cd2c3f8..4e2af017 100644 --- a/requirements/test_requirements.txt +++ b/requirements/test_requirements.txt @@ -7,3 +7,6 @@ pytest>=3.5.1 pytest-cov>=2.5.1 mock>=2.0.0 +# Optional: For BNN model (Bohamiann/Profet examples and tests only) +# Install from PyPI: +# pybnn==0.0.5 diff --git a/setup.py b/setup.py index 17e5393b..006a3125 100644 --- a/setup.py +++ b/setup.py @@ -45,9 +45,17 @@ # NOTE: emcee might become optional; defer change until later. extras_require={ "gpy": ["GPy>=1.13.0"], - "examples": [], # matplotlib now core; placeholder extra retained for compatibility + "bnn": ["pybnn>=0.0.5", "torch"], # Bayesian neural network (Bohamiann / Profet) examples + "sklearn": ["scikit-learn"], # scikit-learn model wrapper and examples + "examples": [ # Convenience extra for running example scripts & notebooks + "GPy>=1.13.0", # GP-based examples + "pybnn>=0.0.5", # Bohamiann / Profet + "torch", # Profet & BNN architectures + "scikit-learn" # sklearn model wrapper examples + ], "docs": [ # Include GPy so API docs for GPy wrappers build with real objects + "ipykernel", "GPy>=1.13.0", "Sphinx>=1.7.5", "nbsphinx>=0.3.4", @@ -56,6 +64,8 @@ ], "tests": [ "coverage>=4.5.1", + "pandas", + "ipykernel", "codecov>=2.0.15", "flake8>=3.5.0", "isort>=5.10", @@ -66,6 +76,11 @@ ], "full": [ "GPy>=1.13.0", + "pybnn>=0.0.5", + "torch", + "scikit-learn", + "pandas", + "ipykernel", "matplotlib", "Sphinx>=1.7.5", "nbsphinx>=0.3.4", diff --git a/tests/emukit/experimental_design/test_batch_experimental_design.py b/tests/emukit/experimental_design/test_batch_experimental_design.py index bbe0bfce..64f1e0fa 100644 --- a/tests/emukit/experimental_design/test_batch_experimental_design.py +++ b/tests/emukit/experimental_design/test_batch_experimental_design.py @@ -8,6 +8,7 @@ import pytest pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy +import GPy import mock import numpy as np diff --git a/tests/emukit/multi_fidelity/test_non_linear_models.py b/tests/emukit/multi_fidelity/test_non_linear_models.py index d02f303e..74ae7a85 100644 --- a/tests/emukit/multi_fidelity/test_non_linear_models.py +++ b/tests/emukit/multi_fidelity/test_non_linear_models.py @@ -165,7 +165,7 @@ def test_non_linear_sample_fidelities_gradient(self, non_linear_model, fidelity_ grad = lambda x: np.sum( non_linear_model._predict_samples_with_gradients(x[None, :], fidelity_idx)[grad_idx], axis=0 ) - assert check_grad(func, grad, x0) < 1e-6 + assert check_grad(func, grad, x0) < 2e-6 def test_non_linear_model_mean_gradient(self, non_linear_model): """ From b7cc71f3d094ad62396a6e21395c8b83f1f14ae5 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 15:20:46 +0300 Subject: [PATCH 07/26] chore: remove tracked .opencode timeline file --- .opencode/tickets/timeline.md | 68 ----------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 .opencode/tickets/timeline.md diff --git a/.opencode/tickets/timeline.md b/.opencode/tickets/timeline.md deleted file mode 100644 index 32b8c810..00000000 --- a/.opencode/tickets/timeline.md +++ /dev/null @@ -1,68 +0,0 @@ -# Emukit Ticket Timeline - -Date: 2025-10-14 - -## Overview -This timeline tracks progress on optional dependency refactoring, test gating efforts, and newly discovered compatibility issues. - -## Tickets - -### Ticket 023 – DoE Dependencies Consolidation -- Status: Completed. -- Outcome: Moved PyDOE & sobol_seq to mandatory core requirements; removed from extras to simplify installation and avoid conditional failures. - -### Ticket 024 – Marker Documentation -- Status: Completed. -- Outcome: Added CONTRIBUTING section detailing markers (gpy, pybnn, sklearn, notebooks), Unreleased CHANGELOG entry, and validated skips in minimal environment (no errors, only skips for missing optional deps). - -### Ticket 022 – Marker Expansion (sklearn & Notebooks) -- Status: Completed. -- Outcome: Added `sklearn` and `notebooks` markers to setup.cfg. Annotated sklearn integration tests with `pytestmark = pytest.mark.sklearn` while retaining existing `pytest.importorskip("sklearn")`. Added `pytestmark = pytest.mark.notebooks` to notebook execution test and de-duplicated redundant `importorskip` calls. Timeline & gating summary updated. - - -### Ticket 001 – Optional Dependency Extras -- Status: Completed. -- Outcome: Extras defined (`gpy`, `examples`, `docs`, `tests`, `full`); benchmarking extra removed. - -### Ticket 002 – GPy Import Gating -- Status: Completed. -- Outcome: Core import works without GPy; placeholders added; informative errors preserved. - -### Ticket 003 – Test Gating (GPy) -- Status: Completed. -- Outcome: All GPy-dependent unit tests now uniformly use `pytest.importorskip("GPy")` plus `pytestmark = pytest.mark.gpy`. No remaining ungated GPy imports found. Non-GPy test (mean plugin EI) confirmed does not require GPy and stays unmarked. - -### Ticket 007 – BenchmarkPlot Matplotlib Handling -- Status: Completed. -- Outcome: Added guarded matplotlib import with `_HAS_MPL` flag, placeholder `BenchmarkPlot` raising informative ImportError when matplotlib absent, fixed `save_plot` to use `fig_handle.savefig(file_name)` and corrected error message, tests now skipped if matplotlib not installed. - -### Ticket 014 – GPy Marker Introduction & Integration Stability -- Status: Completed. -- Outcome: Established `gpy` marker taxonomy and applied consistently across GPy tests. Extended marker framework (`pybnn`, `sklearn`, `notebooks`) and removed now-unnecessary `mpl` marker after promoting matplotlib to mandatory dependency. - -### Ticket 021 – NumPy 2.0 Compatibility -- Status: Completed. -- Outcome: Replaced deprecated aliases (`np.product` -> `np.prod`; removed legacy `np.int` -> `int` in examples). Verified absence of `np.NaN`, `np.PINF`, `np.NINF`, `np.row_stack`. Adjusted test mocking to avoid NumPy 2.x recursion. - -## Dependency Gating Summary -- Implemented: GPy (marker), matplotlib (mandatory), pybnn (marker), sklearn (marker), notebooks (marker for nbformat/nbconvert execution), nbformat, nbconvert. -- Pending: Review whether to convert notebooks execution to a slower test group marker or leave as is. - - -## Next Action Plan -1. Run pytest to confirm marker-based skips in minimal env. -2. Document marker usage in CONTRIBUTING and optionally CHANGELOG. -3. Evaluate need for a slow/extended marker to group notebook execution. - -## Risks -- Leaving NumPy 2.0 issues blocks future CI matrix updates targeting modern environments. -- Missing matplotlib import hides plotting capability and creates failing tests. - -## Open Decisions -- Marker taxonomy breadth. - -## Milestones -- 2025-10-14: Discovered NumPy 2.0 incompatibilities and benchmark plot import issue; timeline & Ticket 021 created. - ---- -End of timeline update. From 61aa33ec43ff5826acaa0a7184ce91cd1d085d38 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 15:56:57 +0300 Subject: [PATCH 08/26] build: migrate packaging to PEP 621 in pyproject.toml with dynamic version and setup.py shim --- pyproject.toml | 128 ++++++++++++++++++++++++++++++++++++++++++++++++- setup.py | 120 +++------------------------------------------- 2 files changed, 133 insertions(+), 115 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7bdb967c..e2d91f32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,134 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "emukit" +dynamic = ["version"] + +description = "Toolkit for decision making under uncertainty." +readme = "README.md" +license = { file = "LICENSE" } +requires-python = ">=3.9" +authors = [ { name = "Emukit Authors" } ] +keywords = ["bayesian-optimization", "active-learning", "uncertainty", "experimental-design"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Topic :: Scientific/Engineering :: Mathematics", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", +] +# Core runtime dependencies (kept unpinned except for minimums already implied) +dependencies = [ + "numpy", + "scipy", + "matplotlib>=3.9", + "emcee>=2.2.1", + "PyDOE>=0.3.0", + "sobol_seq>=0.1.2", +] + +[project.optional-dependencies] +# Mirrors previous extras_require in setup.py (unchanged for minimal migration) +gpy = ["GPy>=1.13.0"] +bnn = ["pybnn>=0.0.5", "torch"] +sklearn = ["scikit-learn"] +examples = [ + "GPy>=1.13.0", + "pybnn>=0.0.5", + "torch", + "scikit-learn", +] +docs = [ + # Retain historical versions for minimal change; can modernize later + "ipykernel", + "GPy>=1.13.0", + "Sphinx>=1.7.5", + "nbsphinx>=0.3.4", + "sphinx-autodoc-typehints>=1.3.0", + "sphinx-rtd-theme>=0.4.1", +] +# Test & QA dependencies (as before) +tests = [ + "coverage>=4.5.1", + "pandas", + "ipykernel", + "codecov>=2.0.15", + "flake8>=3.5.0", + "isort>=5.10", + "black", + "pytest>=3.5.1", + "pytest-cov>=2.5.1", + "mock>=2.0.0", +] +# Convenience aggregate identical to previous 'full' +full = [ + "GPy>=1.13.0", + "pybnn>=0.0.5", + "torch", + "scikit-learn", + "pandas", + "ipykernel", + "matplotlib", + "Sphinx>=1.7.5", + "nbsphinx>=0.3.4", + "sphinx-autodoc-typehints>=1.3.0", + "sphinx-rtd-theme>=0.4.1", + "coverage>=4.5.1", + "codecov>=2.0.15", + "flake8>=3.5.0", + "isort>=5.10", + "black", + "pytest>=3.5.1", + "pytest-cov>=2.5.1", + "mock>=2.0.0", +] + +[project.urls] +Homepage = "https://github.com/emukit/emukit" +Documentation = "https://emukit.readthedocs.io" +Source = "https://github.com/emukit/emukit" +Issues = "https://github.com/emukit/emukit/issues" + +[tool.setuptools.dynamic] +version = {attr = "emukit.__version__.__version__"} + +[tool.setuptools.packages.find] +include = ["emukit*"] +exclude = ["tests*", "integration_tests*"] + [tool.black] line-length = 120 -include = '\.py$' -extend-exclude = 'doc\/.*|notebooks\/.*' +include = '\\.(py)$' +extend-exclude = 'doc/.*|notebooks/.*' [tool.isort] profile = 'black' skip_glob = 'doc/*,notebooks/*' skip_gitignore = true line_length = 120 + +[tool.flake8] +max-line-length = 120 +ignore = ["E731", "E127"] +exclude = [".git", "build", "__pycache__"] + +[tool.pytest.ini_options] +markers = [ + "gpy: tests requiring GPy optional dependency", + "pybnn: tests requiring pybnn optional dependency", + "sklearn: tests requiring scikit-learn optional dependency", + "notebooks: tests executing Jupyter notebooks", +] + +[tool.coverage.run] +branch = true +source = ["emukit"] +omit = ["tests/*", "setup.py", "emukit/examples/*", "integration_tests/*"] diff --git a/setup.py b/setup.py index 006a3125..03119bbd 100644 --- a/setup.py +++ b/setup.py @@ -1,115 +1,9 @@ -# Copyright 2020-2024 The Emukit Authors. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 +# Legacy shim retained for backward compatibility. +# Metadata & configuration have migrated to pyproject.toml (PEP 621). +# This file can be removed in a future major/minor release once +# users and downstream tooling no longer invoke `python setup.py ...`. -# Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 +from setuptools import setup - -import sys - -from setuptools import find_packages, setup - -from emukit.__version__ import __version__ - -with open("README.md", "r") as fh: - long_description = fh.read() - -with open("requirements/requirements.txt", "r") as req: - requires = req.read().split("\n") - -# enforce >Python3 for all versions of pip/setuptools -assert sys.version_info >= (3,), "This package requires Python 3." - -setup( - name="emukit", - version=__version__, - description="Toolkit for decision making under uncertainty.", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/emukit/emukit", - packages=find_packages(exclude=["test*"]), - include_package_data=True, - install_requires=requires, - # ===================== OPTIONAL EXTRAS ===================== - # These extras allow installing additional functionality without - # pulling heavy dependencies into the minimal core install. - # Core install aims to remain lightweight: numerical stack + emcee. - # Optional groups: - # - gpy: Adds GPy for Gaussian process models (large dependency tree). - # - examples: Dependencies used across example scripts (matplotlib). - # - docs: Build documentation (Sphinx + nbsphinx etc.). - # - tests: Test-only dependencies. - # - full: Convenience meta extra that installs all optional groups. - # The previous 'benchmarking' extra is superseded by 'examples'. - # NOTE: DoE dependencies (PyDOE, sobol_seq) are now core requirements. - # NOTE: emcee might become optional; defer change until later. - extras_require={ - "gpy": ["GPy>=1.13.0"], - "bnn": ["pybnn>=0.0.5", "torch"], # Bayesian neural network (Bohamiann / Profet) examples - "sklearn": ["scikit-learn"], # scikit-learn model wrapper and examples - "examples": [ # Convenience extra for running example scripts & notebooks - "GPy>=1.13.0", # GP-based examples - "pybnn>=0.0.5", # Bohamiann / Profet - "torch", # Profet & BNN architectures - "scikit-learn" # sklearn model wrapper examples - ], - "docs": [ - # Include GPy so API docs for GPy wrappers build with real objects - "ipykernel", - "GPy>=1.13.0", - "Sphinx>=1.7.5", - "nbsphinx>=0.3.4", - "sphinx-autodoc-typehints>=1.3.0", - "sphinx-rtd-theme>=0.4.1", - ], - "tests": [ - "coverage>=4.5.1", - "pandas", - "ipykernel", - "codecov>=2.0.15", - "flake8>=3.5.0", - "isort>=5.10", - "black", - "pytest>=3.5.1", - "pytest-cov>=2.5.1", - "mock>=2.0.0", - ], - "full": [ - "GPy>=1.13.0", - "pybnn>=0.0.5", - "torch", - "scikit-learn", - "pandas", - "ipykernel", - "matplotlib", - "Sphinx>=1.7.5", - "nbsphinx>=0.3.4", - "sphinx-autodoc-typehints>=1.3.0", - "sphinx-rtd-theme>=0.4.1", - "coverage>=4.5.1", - "codecov>=2.0.15", - "flake8>=3.5.0", - "isort>=5.10", - "black", - "pytest>=3.5.1", - "pytest-cov>=2.5.1", - "mock>=2.0.0", - ], - }, - python_requires=">=3.9", - license="Apache License 2.0", - classifiers=[ - # https://pypi.org/pypi?%3Aaction=list_classifiers - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Intended Audience :: Education", - "Intended Audience :: Science/Research", - "Programming Language :: Python :: 3", - "License :: OSI Approved :: Apache Software License", - "Operating System :: OS Independent", - "Topic :: Scientific/Engineering :: Artificial Intelligence", - "Topic :: Scientific/Engineering :: Mathematics", - "Topic :: Software Development :: Libraries", - "Topic :: Software Development :: Libraries :: Python Modules", - ], -) +if __name__ == "__main__": # pragma: no cover + setup() From 4fd20bd224a0db51680bf75e22303a3f7742e363 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 16:01:15 +0300 Subject: [PATCH 09/26] build: migrate CI & docs to extras-based installation; add packaging changelog entry --- .github/workflows/codecov.yml | 4 +-- .github/workflows/format.yml | 2 +- .github/workflows/tests.yml | 14 +++-------- CHANGELOG.md | 13 +++++----- CONTRIBUTING.md | 19 +++++++++++---- README.md | 2 +- doc/installation.rst | 46 +++++++++++++++++++++-------------- 7 files changed, 55 insertions(+), 45 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 03782885..aae12863 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -24,11 +24,9 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install flake8 pytest - pip install -r requirements/requirements.txt - pip install -r requirements/test_requirements.txt + pip install -e .[tests] # work around issues with GPy setting matplotlib backend echo 'backend: Agg' > matplotlibrc - pip install . - name: Run coverage run: | python -m pytest --verbose --cov emukit --cov-report term-missing tests diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 09bc6718..cf8c1977 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,7 +18,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements/test_requirements.txt + pip install -e .[tests] - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 989ee519..07ca220d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,12 +23,9 @@ jobs: - name: Install core dependencies (no GPy) run: | python -m pip install --upgrade pip - pip install -r requirements/requirements.txt - pip install -r requirements/test_requirements.txt - pip install -r requirements/integration_test_requirements.txt -q + pip install -e .[tests] # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc - pip install . - name: Unit tests (core) run: | python -m pytest tests @@ -52,11 +49,8 @@ jobs: - name: Install dependencies with GPy extra run: | python -m pip install --upgrade pip - pip install -r requirements/requirements.txt - pip install -r requirements/test_requirements.txt - pip install -r requirements/integration_test_requirements.txt -q + pip install -e .[tests,gpy] echo 'backend: Agg' > matplotlibrc - pip install '.[gpy]' - name: Unit tests (with GPy) run: | python -m pytest tests -m 'gpy or not gpy' @@ -80,11 +74,9 @@ jobs: - name: Install dependencies (core) run: | python -m pip install --upgrade pip - pip install -r requirements/requirements.txt - pip install -r requirements/test_requirements.txt + pip install -e .[tests] # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc - pip install . - name: Unit tests (core, multi-OS) run: | python -m pytest tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 83272660..34e17330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,13 @@ All notable changes to Emukit will be documented in this file. ## [Unreleased] -- Documented test marker taxonomy and optional dependency gating. -- Introduced optional install extras: gpy, docs, examples (placeholder), tests, full. -- Core installation no longer pulls GPy; GPy-dependent tests marked with @pytest.mark.gpy and skipped when GPy absent. -- Updated documentation (README, installation.rst) to explain optional dependencies and extras. -- ReadTheDocs build now uses the docs extra (includes GPy) so GPy wrapper API docs build correctly. -- Added separate CI job running tests with GPy extra alongside core-only job to validate minimal installation. +- Packaging: Adopt PEP 621 metadata in `pyproject.toml`; dynamic version from `emukit.__version__`. +- Packaging: Introduced setuptools extras (`gpy`, `bnn`, `sklearn`, `docs`, `examples`, `tests`, `full`). +- CI: Workflows now install extras via `pip install -e .[tests]` (and `[tests,gpy]`) instead of requirements files. +- Docs: Updated installation guide, README, CONTRIBUTING to prefer extras over legacy `requirements/` files. +- Tests: Documented pytest marker taxonomy and optional dependency gating. +- Docs build: ReadTheDocs expected to use `docs` extra (includes GPy) for GP API sections. +- Maintenance: Legacy requirements files retained temporarily for reference; deprecation planned. ## [0.4.11] - Various bugfixes, including installation on Windows diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d2784cb..81e5c57a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,7 +78,7 @@ Before submitting the pull request, please go through this checklist to make the ## Setting up a development environment ### Building the code -See installing from source. +See installing from source (now using `pip install -e .[tests]` for development). ### Running tests Run the full suite of unit tests or integration tests with these commands: @@ -91,14 +91,22 @@ from the top level directory. To check unit test coverage, run this: pytest --verbose --cov emukit --cov-report term-missing tests ``` -Notice that unit tests and integration tests have their own set of additional dependencies. Those can be found in the `requirements` folder, and installed with: +Notice that unit tests and integration tests have their own set of additional dependencies. You can install them via extras defined in `pyproject.toml`: ``` -pip install -r requirements/test_requirements.txt -pip install -r requirements/integration_test_requirements.txt +# Core + test tooling +pip install -e .[tests] + +# Add optional dependency groups as needed (examples): +pip install -e .[gpy] +pip install -e .[bnn] +pip install -e .[sklearn] +# Or everything: +pip install -e .[full] ``` +Legacy requirement files in `requirements/` remain temporarily for reference but will be phased out; prefer extras going forward. ### Test markers & optional dependencies -Emukit uses pytest markers to group tests that rely on optional dependencies. Current markers (defined in `setup.cfg` under `[tool:pytest]`): +Emukit uses pytest markers to group tests that rely on optional dependencies. Current markers (defined in `pyproject.toml` under `[tool.pytest.ini_options]`): - gpy: tests requiring GPy optional dependency - pybnn: tests requiring pybnn optional dependency @@ -149,6 +157,7 @@ Emukit uses black and isort to format code. There is also a build action that ch ``` isort . black . +# Or run only on changed files via pre-commit if configured. ``` ### Generating docs diff --git a/README.md b/README.md index 920448a0..09390773 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ pip install emukit[examples] # Everything (gpy + bnn + sklearn + examples + docs + test tooling) pip install emukit[full] ``` -See [requirements](requirements/requirements.txt). +Legacy pinned requirement files remain in the `requirements/` directory for reference but extras (above) are the preferred installation mechanism going forward. ## Getting started For examples see our [tutorial notebooks](http://nbviewer.jupyter.org/github/emukit/emukit/blob/main/notebooks/index.ipynb). diff --git a/doc/installation.rst b/doc/installation.rst index 9368aec3..bc2bc68a 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -24,21 +24,25 @@ You can install optional dependency groups via setuptools extras. Each group ena .. code-block:: bash # Gaussian processes / multi-fidelity / quadrature - pip install emukit[gpy] + pip install emukit[gpy] + + # Bayesian neural network & Profet examples + pip install emukit[bnn] + + # scikit-learn model wrapper + pip install emukit[sklearn] + + # Build documentation locally (includes gpy) + pip install emukit[docs] + + # Bundle of example dependencies + pip install emukit[examples] + + # Everything (gpy + bnn + sklearn + examples + docs + tests) + pip install emukit[full] + + Installation from sources - # Bayesian neural network & Profet examples - pip install emukit[bnn] - - # scikit-learn model wrapper - pip install emukit[sklearn] - - # Build documentation locally (includes gpy) - pip install emukit[docs] - - # Everything (gpy + bnn + sklearn + docs + tests) - pip install emukit[full] - -Installation from sources .. code-block:: bash @@ -48,7 +52,13 @@ If you would like a bit more control (e.g. for development), clone the repo, ins .. code-block:: bash - git clone https://github.com/emukit/emukit.git - cd Emukit - pip install -e .[gpy] # or .[full] for all extras - python setup.py develop + git clone https://github.com/emukit/emukit.git + cd Emukit + # Editable install with desired extras (examples below) + pip install -e .[tests] # core + test tooling + pip install -e .[gpy] # add GPy-based functionality + # Or everything: + pip install -e .[full] + +`python setup.py develop` is no longer needed; PEP 621 metadata in `pyproject.toml` enables editable installs directly via pip (PEP 660). + From 4fe9a619f6cd84461d1bba9236ebd175d0e0b0e9 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 15 Oct 2025 16:27:07 +0300 Subject: [PATCH 10/26] chore: Run black and isort --- emukit/benchmarking/loop_benchmarking/benchmark_plot.py | 2 +- emukit/model_wrappers/gpy_model_wrappers.py | 5 +++-- emukit/model_wrappers/gpy_quadrature_wrappers.py | 5 ++--- emukit/multi_fidelity/models/linear_model.py | 1 + .../multi_fidelity/models/non_linear_multi_fidelity_model.py | 3 +-- .../emukit/bayesian_optimization/test_constrained_loop.py | 1 + .../test_create_bayesian_optimization_loop.py | 1 + .../bayesian_optimization/test_local_penalization_loop.py | 1 + .../test_optimization_with_categorical_variables.py | 1 + .../test_single_objective_bayesian_optimization.py | 1 + .../test_unknown_constraints_bayesian_optimization.py | 1 + integration_tests/emukit/benchmarking/test_benchmarker.py | 1 + .../test_experimental_design_with_categorical.py | 1 + .../test_multi_source_experimental_design.py | 1 + .../emukit/fabolas/test_continuous_entropy_search.py | 1 + integration_tests/emukit/fabolas/test_fabolas_model.py | 1 + integration_tests/emukit/models/test_random_forest.py | 1 + .../emukit/models/test_sklearn_model_wrapper.py | 1 + integration_tests/emukit/notebooks/test_notebooks.py | 1 + .../emukit/quadrature/test_bayesian_monte_carlo_loop.py | 1 + integration_tests/emukit/quadrature/test_vanilla_bq_loop.py | 1 + integration_tests/emukit/quadrature/test_wsabil_loop.py | 1 + .../bayesian_optimization/test_bayesian_optimization_loop.py | 1 + tests/emukit/bayesian_optimization/test_constrained_loop.py | 1 + .../test_cost_sensitive_bayesian_optimization.py | 1 + .../test_local_penalization_calculator.py | 1 + .../test_mean_plugin_expected_improvement.py | 3 +-- .../test_multipoint_expected_improvement.py | 1 + tests/emukit/conftest.py | 1 + tests/emukit/core/test_outer_loop.py | 1 + .../experimental_design/test_batch_experimental_design.py | 1 + .../experimental_design/test_experimental_design_loop.py | 1 + tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py | 1 + tests/emukit/multi_fidelity/test_kernels.py | 1 + tests/emukit/multi_fidelity/test_models.py | 1 + tests/emukit/multi_fidelity/test_non_linear_models.py | 1 + tests/emukit/quadrature/test_quadrature_acquisitions.py | 1 + tests/emukit/quadrature/test_quadrature_kernels.py | 1 + tests/emukit/quadrature/test_quadrature_models.py | 1 + 39 files changed, 42 insertions(+), 10 deletions(-) diff --git a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py index 69b39cad..3ebc5070 100644 --- a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py +++ b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py @@ -8,11 +8,11 @@ from itertools import cycle from typing import List +import matplotlib.pyplot as plt import numpy as np from .benchmark_result import BenchmarkResult -import matplotlib.pyplot as plt class BenchmarkPlot: """Creates plots comparing results from different loops. diff --git a/emukit/model_wrappers/gpy_model_wrappers.py b/emukit/model_wrappers/gpy_model_wrappers.py index b4389e52..e55d00c5 100644 --- a/emukit/model_wrappers/gpy_model_wrappers.py +++ b/emukit/model_wrappers/gpy_model_wrappers.py @@ -7,13 +7,14 @@ import importlib + if importlib.util.find_spec("GPy") is None: # pragma: no cover raise ImportError( "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use gpy_model_wrappers." ) -import GPy # noqa: F401 - from typing import Optional, Tuple + +import GPy # noqa: F401 import numpy as np from ..bayesian_optimization.interfaces import IEntropySearchModel diff --git a/emukit/model_wrappers/gpy_quadrature_wrappers.py b/emukit/model_wrappers/gpy_quadrature_wrappers.py index 133f3c3a..9e2869c1 100644 --- a/emukit/model_wrappers/gpy_quadrature_wrappers.py +++ b/emukit/model_wrappers/gpy_quadrature_wrappers.py @@ -8,18 +8,17 @@ """GPy wrappers for the quadrature package.""" import importlib + if importlib.util.find_spec("GPy") is None: # pragma: no cover raise ImportError( "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use gpy_quadrature_wrappers." ) -import GPy # noqa: F401 - # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 import warnings from typing import List, Optional, Tuple, Union -import GPy +import GPy # noqa: F401 import numpy as np from scipy.linalg import lapack diff --git a/emukit/multi_fidelity/models/linear_model.py b/emukit/multi_fidelity/models/linear_model.py index 999e08d8..45f931d6 100644 --- a/emukit/multi_fidelity/models/linear_model.py +++ b/emukit/multi_fidelity/models/linear_model.py @@ -11,6 +11,7 @@ import importlib + if importlib.util.find_spec("GPy") is None: # pragma: no cover raise ImportError( "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use GPyLinearMultiFidelityModel." diff --git a/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py b/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py index b6253ff1..532401f8 100644 --- a/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py +++ b/emukit/multi_fidelity/models/non_linear_multi_fidelity_model.py @@ -14,10 +14,9 @@ P. Perdikaris, M. Raissi, A. Damianou, N. D. Lawrence and G. E. Karniadakis (2017) https://royalsocietypublishing.org/doi/10.1098/rspa.2016.0751 """ +import importlib from typing import List, Tuple, Type - -import importlib if importlib.util.find_spec("GPy") is None: # pragma: no cover raise ImportError( "GPy is not installed. Install optional dependency with 'pip install emukit[gpy]' to use NonLinearMultiFidelityModel." diff --git a/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py b/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py index 6b10f8c6..818e5d6d 100644 --- a/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_constrained_loop.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py index adf6c948..156b3d6d 100644 --- a/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_create_bayesian_optimization_loop.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("sklearn") pytestmark = pytest.mark.sklearn diff --git a/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py b/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py index 3c8ff0e0..442583dc 100644 --- a/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py +++ b/integration_tests/emukit/bayesian_optimization/test_local_penalization_loop.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py b/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py index 738517f9..d9457dd6 100644 --- a/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py +++ b/integration_tests/emukit/bayesian_optimization/test_optimization_with_categorical_variables.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py b/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py index 855aa92c..bc28b8eb 100644 --- a/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py +++ b/integration_tests/emukit/bayesian_optimization/test_single_objective_bayesian_optimization.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy") pytestmark = pytest.mark.gpy diff --git a/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py b/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py index da3caf2d..13ea5b37 100644 --- a/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py +++ b/integration_tests/emukit/bayesian_optimization/test_unknown_constraints_bayesian_optimization.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy") pytestmark = pytest.mark.gpy diff --git a/integration_tests/emukit/benchmarking/test_benchmarker.py b/integration_tests/emukit/benchmarking/test_benchmarker.py index ae910ca8..af4d7718 100644 --- a/integration_tests/emukit/benchmarking/test_benchmarker.py +++ b/integration_tests/emukit/benchmarking/test_benchmarker.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py b/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py index 10d1a38c..44c2edba 100644 --- a/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py +++ b/integration_tests/emukit/experimental_design/test_experimental_design_with_categorical.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py b/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py index f82ad247..c95791fb 100644 --- a/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py +++ b/integration_tests/emukit/experimental_design/test_multi_source_experimental_design.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/fabolas/test_continuous_entropy_search.py b/integration_tests/emukit/fabolas/test_continuous_entropy_search.py index 6e898206..645c42ef 100644 --- a/integration_tests/emukit/fabolas/test_continuous_entropy_search.py +++ b/integration_tests/emukit/fabolas/test_continuous_entropy_search.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy") pytestmark = pytest.mark.gpy diff --git a/integration_tests/emukit/fabolas/test_fabolas_model.py b/integration_tests/emukit/fabolas/test_fabolas_model.py index 5aba19b2..51d264dc 100644 --- a/integration_tests/emukit/fabolas/test_fabolas_model.py +++ b/integration_tests/emukit/fabolas/test_fabolas_model.py @@ -7,6 +7,7 @@ import numpy as np import pytest + pytest.importorskip("GPy") pytestmark = pytest.mark.gpy diff --git a/integration_tests/emukit/models/test_random_forest.py b/integration_tests/emukit/models/test_random_forest.py index 62ca457f..8a4a2866 100644 --- a/integration_tests/emukit/models/test_random_forest.py +++ b/integration_tests/emukit/models/test_random_forest.py @@ -7,6 +7,7 @@ import numpy as np import pytest + pytest.importorskip("sklearn") pytestmark = pytest.mark.sklearn diff --git a/integration_tests/emukit/models/test_sklearn_model_wrapper.py b/integration_tests/emukit/models/test_sklearn_model_wrapper.py index 9a68d3c6..be6bf623 100644 --- a/integration_tests/emukit/models/test_sklearn_model_wrapper.py +++ b/integration_tests/emukit/models/test_sklearn_model_wrapper.py @@ -4,6 +4,7 @@ import numpy as np import pytest + pytest.importorskip("sklearn") pytestmark = pytest.mark.sklearn from sklearn.gaussian_process import GaussianProcessRegressor diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index bd31630a..11cb8e4e 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -14,6 +14,7 @@ import os import pytest + pytest.importorskip("nbformat") pytest.importorskip("nbconvert") pytestmark = pytest.mark.notebooks diff --git a/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py b/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py index c18bc820..665cbd85 100644 --- a/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py +++ b/integration_tests/emukit/quadrature/test_bayesian_monte_carlo_loop.py @@ -10,6 +10,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py b/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py index 473e6e3b..64f45dcf 100644 --- a/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py +++ b/integration_tests/emukit/quadrature/test_vanilla_bq_loop.py @@ -6,6 +6,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/integration_tests/emukit/quadrature/test_wsabil_loop.py b/integration_tests/emukit/quadrature/test_wsabil_loop.py index fa7fda05..eff99111 100644 --- a/integration_tests/emukit/quadrature/test_wsabil_loop.py +++ b/integration_tests/emukit/quadrature/test_wsabil_loop.py @@ -3,6 +3,7 @@ import pytest + GPy = pytest.importorskip("GPy") pytestmark = pytest.mark.gpy import numpy as np diff --git a/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py b/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py index f6aba099..474c7453 100644 --- a/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py +++ b/tests/emukit/bayesian_optimization/test_bayesian_optimization_loop.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/bayesian_optimization/test_constrained_loop.py b/tests/emukit/bayesian_optimization/test_constrained_loop.py index 47a3aa8a..9a26bac7 100644 --- a/tests/emukit/bayesian_optimization/test_constrained_loop.py +++ b/tests/emukit/bayesian_optimization/test_constrained_loop.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py index a8ead90f..70739079 100644 --- a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py +++ b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py b/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py index e1103882..03e6249e 100644 --- a/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py +++ b/tests/emukit/bayesian_optimization/test_local_penalization_calculator.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py index 9b23e9d8..8e583cf9 100644 --- a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py +++ b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 -import pytest # GPy optional: this test does not require GPy and runs in core environment from unittest.mock import MagicMock import numpy as np +import pytest from emukit.bayesian_optimization.acquisitions.expected_improvement import ( ExpectedImprovement, @@ -15,7 +15,6 @@ from emukit.core.interfaces import IModel, IModelWithNoise - class MockIModel(IModel): def __init__(self, X, Y): self._X = X diff --git a/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py b/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py index c958f9ea..c54087d1 100644 --- a/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py +++ b/tests/emukit/bayesian_optimization/test_multipoint_expected_improvement.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/conftest.py b/tests/emukit/conftest.py index c7006f08..689a3639 100644 --- a/tests/emukit/conftest.py +++ b/tests/emukit/conftest.py @@ -18,6 +18,7 @@ import pytest from emukit.core import ContinuousParameter, OneHotEncoding, ParameterSpace + if HAS_GPY: from emukit.model_wrappers import GPyModelWrapper diff --git a/tests/emukit/core/test_outer_loop.py b/tests/emukit/core/test_outer_loop.py index b3280c3f..167c8a9d 100644 --- a/tests/emukit/core/test_outer_loop.py +++ b/tests/emukit/core/test_outer_loop.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/experimental_design/test_batch_experimental_design.py b/tests/emukit/experimental_design/test_batch_experimental_design.py index 64f1e0fa..ef793641 100644 --- a/tests/emukit/experimental_design/test_batch_experimental_design.py +++ b/tests/emukit/experimental_design/test_batch_experimental_design.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/experimental_design/test_experimental_design_loop.py b/tests/emukit/experimental_design/test_experimental_design_loop.py index dcbf763c..98618d7f 100644 --- a/tests/emukit/experimental_design/test_experimental_design_loop.py +++ b/tests/emukit/experimental_design/test_experimental_design_loop.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py b/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py index d3fbc95e..1ad071e3 100644 --- a/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py +++ b/tests/emukit/model_wrappers/test_gpy_wrappers_quadrature.py @@ -5,6 +5,7 @@ """Basic tests for quadrature GPy wrappers.""" import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/multi_fidelity/test_kernels.py b/tests/emukit/multi_fidelity/test_kernels.py index 2fb91a30..b74bbd02 100644 --- a/tests/emukit/multi_fidelity/test_kernels.py +++ b/tests/emukit/multi_fidelity/test_kernels.py @@ -9,6 +9,7 @@ Tests for multi-fidelity kernels """ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/multi_fidelity/test_models.py b/tests/emukit/multi_fidelity/test_models.py index 9563d1f2..377f0f46 100644 --- a/tests/emukit/multi_fidelity/test_models.py +++ b/tests/emukit/multi_fidelity/test_models.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/multi_fidelity/test_non_linear_models.py b/tests/emukit/multi_fidelity/test_non_linear_models.py index 74ae7a85..9f07e612 100644 --- a/tests/emukit/multi_fidelity/test_non_linear_models.py +++ b/tests/emukit/multi_fidelity/test_non_linear_models.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import numpy as np diff --git a/tests/emukit/quadrature/test_quadrature_acquisitions.py b/tests/emukit/quadrature/test_quadrature_acquisitions.py index cfa0e699..45236fef 100644 --- a/tests/emukit/quadrature/test_quadrature_acquisitions.py +++ b/tests/emukit/quadrature/test_quadrature_acquisitions.py @@ -6,6 +6,7 @@ import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/quadrature/test_quadrature_kernels.py b/tests/emukit/quadrature/test_quadrature_kernels.py index e087a2b7..e1679ca7 100644 --- a/tests/emukit/quadrature/test_quadrature_kernels.py +++ b/tests/emukit/quadrature/test_quadrature_kernels.py @@ -5,6 +5,7 @@ from dataclasses import dataclass import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy diff --git a/tests/emukit/quadrature/test_quadrature_models.py b/tests/emukit/quadrature/test_quadrature_models.py index 00b27037..efdb7e9c 100644 --- a/tests/emukit/quadrature/test_quadrature_models.py +++ b/tests/emukit/quadrature/test_quadrature_models.py @@ -6,6 +6,7 @@ from math import isclose import pytest + pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") pytestmark = pytest.mark.gpy import GPy From 70f66a8f9c74790f277ba1d746c918997df584da Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 5 Nov 2025 10:41:50 +0200 Subject: [PATCH 11/26] Answer comments with minor changes --- CHANGELOG.md | 9 +++-- CONTRIBUTING.md | 5 +-- doc/installation.rst | 6 +-- .../loop_benchmarking/benchmark_plot.py | 16 +++++++- .../emukit/notebooks/test_notebooks.py | 3 -- pyproject.toml | 38 +++++-------------- .../integration_test_requirements.txt | 2 - requirements/test_requirements.txt | 4 -- 8 files changed, 35 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e17330..69022e09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,14 @@ # Changelog All notable changes to Emukit will be documented in this file. -## [Unreleased] +## [0.5.0] +- Upgrade codebase to allow `numpy` versions greater than 2.0, while maintaining backwards compatibility. `GPy` remains pinned to `numpy<2.0` due to upstream constraints, but core Emukit functionality is now independent of it. Users can now install and use Emukit core API with `numpy>=2.0`. - Packaging: Adopt PEP 621 metadata in `pyproject.toml`; dynamic version from `emukit.__version__`. -- Packaging: Introduced setuptools extras (`gpy`, `bnn`, `sklearn`, `docs`, `examples`, `tests`, `full`). +- Packaging: Introduced setuptools extras (`gpy`, `bnn`, `sklearn`, `docs`, `examples`, `tests`, `dev`). - CI: Workflows now install extras via `pip install -e .[tests]` (and `[tests,gpy]`) instead of requirements files. - Docs: Updated installation guide, README, CONTRIBUTING to prefer extras over legacy `requirements/` files. -- Tests: Documented pytest marker taxonomy and optional dependency gating. -- Docs build: ReadTheDocs expected to use `docs` extra (includes GPy) for GP API sections. +- Tests: Documented pytest marker and optional dependency usage. +- Docs build: Use `docs` extra (includes GPy). - Maintenance: Legacy requirements files retained temporarily for reference; deprecation planned. ## [0.4.11] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81e5c57a..629768f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,7 +78,7 @@ Before submitting the pull request, please go through this checklist to make the ## Setting up a development environment ### Building the code -See installing from source (now using `pip install -e .[tests]` for development). +See installing from source (from version 0.5.0 using `pip install -e .[tests]` for core development, and `pip install -e .[dev]` for examples and docs as well). Note that, due to `numpy` version incompatibilities brought forwards by legacy dependencies (such as `GPy`), it is recommended to develop core features without installing any of the extras, using `tests` whenever possible. This will be improved whenever major dependencies, such as `GPy`, are updated. ### Running tests Run the full suite of unit tests or integration tests with these commands: @@ -101,7 +101,7 @@ pip install -e .[gpy] pip install -e .[bnn] pip install -e .[sklearn] # Or everything: -pip install -e .[full] +pip install -e .[examples] ``` Legacy requirement files in `requirements/` remain temporarily for reference but will be phased out; prefer extras going forward. @@ -157,7 +157,6 @@ Emukit uses black and isort to format code. There is also a build action that ch ``` isort . black . -# Or run only on changed files via pre-commit if configured. ``` ### Generating docs diff --git a/doc/installation.rst b/doc/installation.rst index bc2bc68a..23cd38d2 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -19,7 +19,7 @@ You can install optional dependency groups via setuptools extras. Each group ena - ``docs``: Build documentation locally (Sphinx toolchain + GPy for rendering GP API docs). - ``tests``: Test tooling only. - ``examples``: Convenience bundle for most example scripts (installs ``GPy``, ``pybnn``, ``torch``, ``scikit-learn``). -- ``full``: Convenience meta extra installing all of the above. +- ``dev``: Convenience meta extra installing all of the above. .. code-block:: bash @@ -39,7 +39,7 @@ You can install optional dependency groups via setuptools extras. Each group ena pip install emukit[examples] # Everything (gpy + bnn + sklearn + examples + docs + tests) - pip install emukit[full] + pip install emukit[dev] Installation from sources @@ -58,7 +58,7 @@ If you would like a bit more control (e.g. for development), clone the repo, ins pip install -e .[tests] # core + test tooling pip install -e .[gpy] # add GPy-based functionality # Or everything: - pip install -e .[full] + pip install -e .[dev] `python setup.py develop` is no longer needed; PEP 621 metadata in `pyproject.toml` enables editable installs directly via pip (PEP 660). diff --git a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py index 3ebc5070..539f73cd 100644 --- a/emukit/benchmarking/loop_benchmarking/benchmark_plot.py +++ b/emukit/benchmarking/loop_benchmarking/benchmark_plot.py @@ -28,6 +28,15 @@ def __init__( x_axis_metric_name: str = None, metrics_to_plot: List[str] = None, ): + """ + :param benchmark_results: The output of a benchmark run + :param loop_colours: Colours to use for each loop. Defaults to standard matplotlib colour palette + :param loop_line_styles: Line style to use for each loop. Defaults to solid line style for all lines + :param x_axis_metric_name: Which metric to use as the x axis in plots. + None means it will be plotted against iteration number. + :param metrics_to_plot: A list of metric names to plot. Defaults to all metrics apart from the one used as the + x axis. + """ self.benchmark_results = benchmark_results self.loop_names = benchmark_results.loop_names @@ -59,6 +68,11 @@ def __init__( self.x_axis = x_axis_metric_name def make_plot(self, log_y: bool = False) -> None: + """ + Make one plot for each metric measured, comparing the different loop results against each other + + :param log_y: Set the y axis to log scaling if true. + """ n_metrics = len(self.metrics_to_plot) self.fig_handle, _ = plt.subplots(n_metrics, 1) @@ -102,4 +116,4 @@ def _get_metric_stats(metric): return metric.mean(axis=0), metric.std(axis=0) def _get_default_colours(): - return plt.rcParams["axes.prop_cycle"].by_key()["color"] \ No newline at end of file + return plt.rcParams["axes.prop_cycle"].by_key()["color"] diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index 11cb8e4e..ae4b96a4 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -15,10 +15,7 @@ import pytest -pytest.importorskip("nbformat") -pytest.importorskip("nbconvert") pytestmark = pytest.mark.notebooks -pytest.importorskip("ipykernel") import nbformat from nbconvert.preprocessors import ExecutePreprocessor diff --git a/pyproject.toml b/pyproject.toml index e2d91f32..45e1799e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ dynamic = ["version"] description = "Toolkit for decision making under uncertainty." readme = "README.md" license = { file = "LICENSE" } -requires-python = ">=3.9" +requires-python = ">=3.10" authors = [ { name = "Emukit Authors" } ] keywords = ["bayesian-optimization", "active-learning", "uncertainty", "experimental-design"] classifiers = [ @@ -41,15 +41,13 @@ gpy = ["GPy>=1.13.0"] bnn = ["pybnn>=0.0.5", "torch"] sklearn = ["scikit-learn"] examples = [ - "GPy>=1.13.0", - "pybnn>=0.0.5", - "torch", - "scikit-learn", + "emukit[gpy]", + "emukit[bnn]", + "emukit[sklearn]", ] docs = [ - # Retain historical versions for minimal change; can modernize later + "emukit[gpy]", "ipykernel", - "GPy>=1.13.0", "Sphinx>=1.7.5", "nbsphinx>=0.3.4", "sphinx-autodoc-typehints>=1.3.0", @@ -68,27 +66,11 @@ tests = [ "pytest-cov>=2.5.1", "mock>=2.0.0", ] -# Convenience aggregate identical to previous 'full' -full = [ - "GPy>=1.13.0", - "pybnn>=0.0.5", - "torch", - "scikit-learn", - "pandas", - "ipykernel", - "matplotlib", - "Sphinx>=1.7.5", - "nbsphinx>=0.3.4", - "sphinx-autodoc-typehints>=1.3.0", - "sphinx-rtd-theme>=0.4.1", - "coverage>=4.5.1", - "codecov>=2.0.15", - "flake8>=3.5.0", - "isort>=5.10", - "black", - "pytest>=3.5.1", - "pytest-cov>=2.5.1", - "mock>=2.0.0", +# Aggregate ALL optional dependencies for development +dev = [ + "emukit[examples]", + "emukit[docs]", + "emukit[tests]" ] [project.urls] diff --git a/requirements/integration_test_requirements.txt b/requirements/integration_test_requirements.txt index 687a2195..167d3b0d 100644 --- a/requirements/integration_test_requirements.txt +++ b/requirements/integration_test_requirements.txt @@ -1,8 +1,6 @@ # For random forest and GPR models scikit-learn # For BNN model -# For BNN model (Bohamiann/Profet examples and tests only) -# Install from PyPI: pybnn==0.0.5 # For Latin design PyDOE>=0.3.0 diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt index 4e2af017..9b813c2c 100644 --- a/requirements/test_requirements.txt +++ b/requirements/test_requirements.txt @@ -6,7 +6,3 @@ black pytest>=3.5.1 pytest-cov>=2.5.1 mock>=2.0.0 - -# Optional: For BNN model (Bohamiann/Profet examples and tests only) -# Install from PyPI: -# pybnn==0.0.5 From 7f27f2f87d5d477f4d7fb2f876061e8bce256f97 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 5 Nov 2025 10:54:31 +0200 Subject: [PATCH 12/26] Adds random seed fixture for uniform sampling --- tests/emukit/conftest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/emukit/conftest.py b/tests/emukit/conftest.py index 689a3639..c96040e6 100644 --- a/tests/emukit/conftest.py +++ b/tests/emukit/conftest.py @@ -70,3 +70,7 @@ def continuous_space(n_dims): def encoding(): # different types of volcanoes return OneHotEncoding(["strato", "shield", "dome"]) + +@pytest.fixture +def seed_random(): + np.random.seed(42) From 0128fc2a3d5f351cd666d2752d5da2ba43ffc854 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 5 Nov 2025 10:55:19 +0200 Subject: [PATCH 13/26] Passes to , and updates the tests --- tests/emukit/core/test_parameter_space.py | 36 ++++------------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/tests/emukit/core/test_parameter_space.py b/tests/emukit/core/test_parameter_space.py index 4627ef57..842ab4bf 100644 --- a/tests/emukit/core/test_parameter_space.py +++ b/tests/emukit/core/test_parameter_space.py @@ -5,8 +5,6 @@ # SPDX-License-Identifier: Apache-2.0 -from unittest import mock - import numpy as np import pytest from numpy.testing import assert_array_equal @@ -114,31 +112,9 @@ def test_get_bounds(space_3d_mixed): assert space_3d_mixed.get_bounds() == [(1.0, 5.0), (1.0, 3.0), (0, 1), (0, 1)] -class MockRandom: - """Mock the numpy random class to deterministic test stochastic functions. - - Use like: - - >>> @mock.patch('numpy.random', MockRandom()) - >>> def test_something(): - >>> np.random.uniform(0, 1, 10) # call on mock object - >>> ... - """ - - @classmethod - def uniform(cls, low, high, size): - return np.linspace(low, high - 10e-8, np.prod(size)).reshape(size) - - @classmethod - def randint(cls, low, high, size): - return cls.uniform(low, high, size).astype(int) - - -def test_sample_uniform(space_3d_mixed): - # Patch only the needed random generation functions (module patch causes recursion under NumPy>=2) - with mock.patch("numpy.random.uniform", MockRandom.uniform), mock.patch("numpy.random.randint", MockRandom.randint): - X = space_3d_mixed.sample_uniform(90) - assert_array_equal(np.histogram(X[:, 0], 9)[0], np.repeat(10, 9)) - assert_array_equal(np.bincount(X[:, 1].astype(int)), [0, 30, 30, 30]) - assert_array_equal(np.bincount(X[:, 2].astype(int)), [45, 45]) - assert_array_equal(np.bincount(X[:, 3].astype(int)), [45, 45]) +def test_sample_uniform(space_3d_mixed, seed_random): + X = space_3d_mixed.sample_uniform(90) + assert_array_equal(np.histogram(X[:, 0], 9)[0], [12, 14, 12, 7, 8, 8, 7, 11, 11]) + assert_array_equal(np.bincount(X[:, 1].astype(int)), [0, 32, 27, 31]) + assert_array_equal(np.bincount(X[:, 2].astype(int)), [47, 43]) + assert_array_equal(np.bincount(X[:, 3].astype(int)), [43, 47]) From 39e5d33dfbe411138ce61088ec34da2c61c95ad8 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 5 Nov 2025 10:58:42 +0200 Subject: [PATCH 14/26] Cleanup pyproject.toml dependencies --- pyproject.toml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 45e1799e..31c0dafb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,10 +41,7 @@ gpy = ["GPy>=1.13.0"] bnn = ["pybnn>=0.0.5", "torch"] sklearn = ["scikit-learn"] examples = [ - "emukit[gpy]", - "emukit[bnn]", - "emukit[sklearn]", -] + "emukit[gpy, bnn, sklearn]", docs = [ "emukit[gpy]", "ipykernel", @@ -68,9 +65,7 @@ tests = [ ] # Aggregate ALL optional dependencies for development dev = [ - "emukit[examples]", - "emukit[docs]", - "emukit[tests]" + "emukit[examples, docs, tests]", ] [project.urls] From 9a614ecdf617d9ee32470c1dea3a06904e54a2b4 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 5 Nov 2025 13:22:55 +0200 Subject: [PATCH 15/26] Fixes bad definition in pyproject toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 31c0dafb..6276647b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ bnn = ["pybnn>=0.0.5", "torch"] sklearn = ["scikit-learn"] examples = [ "emukit[gpy, bnn, sklearn]", +] docs = [ "emukit[gpy]", "ipykernel", From a7e9de8cd98977f930d51aef120110f9723c1584 Mon Sep 17 00:00:00 2001 From: Alejandro Gomez Date: Wed, 12 Nov 2025 09:37:57 +0200 Subject: [PATCH 16/26] Add comments to all guarded imports --- emukit/model_wrappers/__init__.py | 3 ++- emukit/multi_fidelity/kernels/__init__.py | 6 ++++-- emukit/multi_fidelity/models/__init__.py | 4 ++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/emukit/model_wrappers/__init__.py b/emukit/model_wrappers/__init__.py index 9635fc31..aca3c3f0 100644 --- a/emukit/model_wrappers/__init__.py +++ b/emukit/model_wrappers/__init__.py @@ -6,8 +6,9 @@ # Importing emukit.model_wrappers should succeed without GPy. Accessing GPy wrappers -# (instantiating or importing their concrete classes) should raise an informative ImportError +# should raise an informative ImportError # pointing users to install the optional extra: `pip install emukit[gpy]`. +# By doing it this way, we avoid breaking minimal installs of Emukit. from importlib import util as _importlib_util diff --git a/emukit/multi_fidelity/kernels/__init__.py b/emukit/multi_fidelity/kernels/__init__.py index 6fc47138..779aeebb 100644 --- a/emukit/multi_fidelity/kernels/__init__.py +++ b/emukit/multi_fidelity/kernels/__init__.py @@ -6,8 +6,10 @@ -# Importing emukit.multi_fidelity.kernels should not require GPy. Accessing -# LinearMultiFidelityKernel without GPy raises an informative ImportError. +# Importing multi_fidelity_kernel should succeed without GPy. Accessing GPy-specific classes +# should raise an informative ImportError +# pointing users to install the optional extra: `pip install emukit[gpy]`. +# By doing it this way, we avoid breaking minimal installs of Emukit. from importlib import util as _importlib_util if _importlib_util.find_spec("GPy") is not None: # GPy available diff --git a/emukit/multi_fidelity/models/__init__.py b/emukit/multi_fidelity/models/__init__.py index d8f17066..c6bed463 100644 --- a/emukit/multi_fidelity/models/__init__.py +++ b/emukit/multi_fidelity/models/__init__.py @@ -10,6 +10,10 @@ from importlib import util as _importlib_util +# Importing multi_fidelity_kernel should succeed without GPy. Accessing GPy-specific classes +# should raise an informative ImportError +# pointing users to install the optional extra: `pip install emukit[gpy]`. +# By doing it this way, we avoid breaking minimal installs of Emukit. if _importlib_util.find_spec("GPy") is not None: # GPy available from .linear_model import GPyLinearMultiFidelityModel # noqa: F401 from .non_linear_multi_fidelity_model import NonLinearMultiFidelityModel # noqa: F401 From 574b94dd26efec1542018acbed59ba42ca410e9a Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:09:24 +0000 Subject: [PATCH 17/26] Remove gpy from several tests and one notebook --- notebooks/Emukit-tutorial-intro.ipynb | 60 ++++++++----------- ...st_cost_sensitive_bayesian_optimization.py | 15 +---- .../test_mean_plugin_expected_improvement.py | 4 -- tests/emukit/core/test_outer_loop.py | 8 +-- .../test_experimental_design_loop.py | 15 +---- 5 files changed, 34 insertions(+), 68 deletions(-) diff --git a/notebooks/Emukit-tutorial-intro.ipynb b/notebooks/Emukit-tutorial-intro.ipynb index 79f370e0..1911ec7c 100644 --- a/notebooks/Emukit-tutorial-intro.ipynb +++ b/notebooks/Emukit-tutorial-intro.ipynb @@ -21,19 +21,17 @@ "outputs": [], "source": [ "import numpy as np\n", - "import GPy\n", "\n", - "from emukit.model_wrappers import GPyModelWrapper\n", + "from emukit.model_wrappers import SimpleGaussianProcessModel\n", "from emukit.experimental_design.experimental_design_loop import ExperimentalDesignLoop\n", - "from emukit.core import ParameterSpace, ContinuousParameter\n", - "from emukit.core.loop import UserFunctionWrapper" + "from emukit.core import ParameterSpace, ContinuousParameter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's assume we have built a [GPy](https://github.com/SheffieldML/GPy) model of some function that we would like to understand. In this toy example we will use `sin(x)`, but of course the actual objective function can be much more complex." + "Let's assume we have built a Gaussian Process to model some function that we would like to understand. In this toy example we will use `sin(x)`, but of course the actual objective function can be much more complex." ] }, { @@ -47,7 +45,7 @@ "\n", "X = np.random.uniform(x_min, x_max, (10, 1))\n", "Y = np.sin(X) + np.random.randn(10, 1) * 0.05\n", - "gpy_model = GPy.models.GPRegression(X, Y)" + "gp_model = SimpleGaussianProcessModel(X, Y)" ] }, { @@ -61,16 +59,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "First we will need to turn our model into something Emukit is capable of working with. For GPy models Emukit provides a convenient wrapper, which makes this task very simple. In another tutorial we will show how other Python modelling frameworks can be used with Emukit." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "emukit_model = GPyModelWrapper(gpy_model)" + "First we will need to turn our model into something Emukit is capable of working with. Emukit comes with several ready-made model wrappers GPs that are showcased in other tutorials. Here we are using a simple model already provided by Emukit, so no wrapping is necessary." ] }, { @@ -82,7 +71,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -99,11 +88,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "loop = ExperimentalDesignLoop(space, emukit_model)\n", + "loop = ExperimentalDesignLoop(space, gp_model)\n", "loop.run_loop(np.sin, 30)" ] }, @@ -116,19 +105,17 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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5Emn63Jzc1FUVOR4ffDBB1p8HWXRo3MYjYHv8gH4oOoLapQd0GZlyfKEQMpuNgOhoYHfj+XJWK94JiWDc7U+5kYp66eWdc+y5VYFqBBBzz33HGbMmIFp06YhIyMDy5cvR0REBFasWOHy+vfeew+33347Bg4ciN69e+Ott96C3W7H5s2bna4zm81ITk52vOLj47X4OsqihwhSYpcPEBxBoixOZlrHGLA8qCptxeJt3nvUEP5WqzZnFQaD9VMJ8QlwERQoVqsVu3btQnZ2tuM9o9GI7OxsbN++3at71NTUoKGhAQkJCU7vb926FUlJSejVqxdmzZqFs2fPerxPfX09KioqnF66o2W+GpZX9PLntHVLkNYB9cEwIbBYdkHgyU0JwWL91DImiMVFiwroLoLOnDkDm82GDh06OL3foUMHFBcXe3WPuXPnIjU11UlI5ebmYvXq1di8eTOWLFmCb775BpdddhlsNpvb+yxevBixsbGOV1pamn9fSkn08hUrAQ+M9h6l656LZ+9guc3X14ubGeTPDQSWhX9oqOTCZ7nd8P6qOSF6FyBQnnrqKaxduxZbt26FhRzYCeD66693/Ltfv37o378/unXrhq1bt2Ls2LEu7zVv3jzMmTPH8f+Kigr9hRDvHN5hs0k5NlicEFiuez4hSOgV1M3iLh81rHD19WxaEHlMkG7obglq3749TCYTTp065fT+qVOnkJyc7PGzzz77LJ566ils2LAB/fv393ht165d0b59exw6dMjtNWazGTExMU4v3dEy4I/lji1PMqa0a4DvsPJMMAgJFstO6j08PPADSAHYIsT+aquswvbDZ2GzCwHf0yPBUPe87FwEBUpYWBiGDBniFNRMgpyzsrLcfu7pp5/GY489hry8PAwdOrTV55w4cQJnz55FSkqKIuXWDL6i9w557guZRdBv5AOEFllcg6HuWd4pw6LwV7De8/YW4fK3dgEATA1WTFn+HUYu2YK8vUUB39stLIsglt2oLI81KqC7CAKAOXPm4M0338SqVauwf/9+zJo1C9XV1Zg2bRoAYMqUKZg3b57j+iVLluCRRx7BihUr0KVLFxQXF6O4uBhVTX+Eqqoq3H///fjxxx9x5MgRbN68GVdddRW6d++OnJwcXb6j3wRDbIeWHVupnW1a77BieXXGctlZnhAUEhF5e4swa81u/FUn9ZvwhnoU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", "text/plain": [ - "
" + "
" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -156,19 +143,17 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjkAAAHHCAYAAABdm0mZAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA+0RJREFUeJzsvXm4JGV9NnxX791VvZxt9mFYZREERIMkgKgorgnGuCQqgoDbha8RX5OQGMGYiEtA87q8Rv0U3N6YRDQxiAoqCkpEMbgAosCwzD5n6e6q6r27vj/q+VXVcc6Z0131LDVY93XNlXjmnD5FT3U9v+VeNMdxHCRIkCBBggQJEjzOkFJ9AQkSJEiQIEGCBCKQFDkJEiRIkCBBgsclkiInQYIECRIkSPC4RFLkJEiQIEGCBAkel0iKnAQJEiRIkCDB4xJJkZMgQYIECRIkeFwiKXISJEiQIEGCBI9LJEVOggQJEiRIkOBxiaTISZAgQYIECRI8LpEUOQkSRMThhx+OCy+8UMnvtiwLl1xyCTZs2ABN0/Dnf/7nSq5jLVx11VXQNE31ZayIW2+9FZqm4dZbbw39GnfeeSdyuRweeeSRiX6u3+9j69at+NjHPhb6d4+DSd5/+t75+Xmh1yQTF154IQzDWPP7zjnnHJxzzjniLyiBNCRFToJY4LrrroOmafjJT36i+lIOKbznPe/Bddddhze+8Y343Oc+h1e/+tXKrqXVauGqq66KVCwcqvibv/kb/Omf/im2bds20c9ls1lcfvnl+Id/+Ad0Oh1BV7cy3vOe9+CrX/0q99e98MILoWnain8KhQL33ycSu3btwlVXXYW7775b9aUkCImM6gtIkOBQx/33349USk2/8J3vfAdPe9rTcOWVVyr5/UG0Wi28613vAoADuuF3vOMd+Ku/+isFV7U2zj77bLTbbeRyuVA/f/fdd+OWW27BD3/4w1A/f9FFF+Gv/uqv8MUvfhGvfe1rQ73GWljp/X/Pe96DP/mTP8H555/P/ffl83l86lOfOuDr6XSa++/iiW9961vL/veuXbvwrne9C4cffjhOOeUUNReVIBKSIidBggAGgwFGo9FEB14+nxd4RQfHvn37cMIJJyj7/eMik8kgk4nn4yaVSkWaMHzmM5/BYYcdhqc97Wmhfr5Wq+E5z3kOrrvuOmFFjuz3P5PJ4FWvepW038cLYQvdBPFFsq5KcEhh586deO1rX4v169cjn8/jiU98Ij796U8v+55er4d3vvOdOO2001CtVqHrOs466yx897vfXfZ9Dz/8MDRNwz/+4z/iQx/6EI466ijk83nce++9Hi/hgQcewIUXXoharYZqtYqLLroIrVZr2ev8NieHVm8/+MEPcPnll2Nubg66ruPFL34x9u/fv+xnR6MRrrrqKmzatAmlUgnPeMYzcO+9967J8yEeyfbt23HjjTd664CHH37Y+/0PP/zwij8TXCedc845OPHEE3HvvffiGc94BkqlEjZv3oz3v//9B/zOTqeDq666Ck94whNQKBSwceNG/PEf/zEefPBBPPzww5ibmwMAvOtd7/Ku56qrrgKwMidkMBjg3e9+t/e+H3744fjrv/5rdLvdA97fF77whbj99tvxe7/3eygUCjjyyCPx2c9+dtX3J4h/+Zd/wWmnnYZyuYxKpYKTTjoJ//RP/8TtffnqV7+KZz7zmcv++77zne8glUrhne9857Lv/eIXvwhN0/B//+//Xfb1Zz/72bj99tuxuLi46n+H4ziYnZ3F5Zdf7n1tNBqhVqshnU6jXq97X3/f+96HTCYDy7IAHPj+a5oG27Zx/fXXe/9Wv32/1ev1Ne/9KKD79Pbbb8f/+l//C3Nzc6jVanj961+PXq+Her2OCy64AFNTU5iamsJf/MVfwHEc7+dX41LR5/q666476O+/++67MTc3h3POOcd7n4KcnFtvvRVPfepTAbjTNnqf1nrdBPFCUuQkOGSwd+9ePO1pT8Mtt9yCyy67DP/0T/+Eo48+GhdffDE+9KEPed/XbDbxqU99Cueccw7e97734aqrrsL+/ftx3nnnrbhb/8xnPoMPf/jDeN3rXodrrrkG09PT3t+97GUvg2mauPrqq/Gyl70M1113nbeSWQtvfvOb8bOf/QxXXnkl3vjGN+JrX/saLrvssmXfc8UVV+Bd73oXnvKUp+ADH/gAjjnmGJx33nmwbfugr3388cfjc5/7HGZnZ3HKKafgc5/7HD73uc95hcYkWFpawnOf+1ycfPLJuOaaa3DcccfhL//yL3HTTTd53zMcDvHCF74Q73rXu3DaaafhmmuuwVve8hY0Gg388pe/xNzcnHdwv/jFL/au54//+I9X/b2XXHIJ3vnOd+LJT34yPvjBD+LpT386rr76arziFa844HsfeOAB/Mmf/Ame/exn45prrsHU1BQuvPBC3HPPPQf9b7v55pvxp3/6p5iamsL73vc+vPe978U555yDH/zgB1zel507d+LRRx/Fk5/85GU/+8xnPhNvetObcPXVV+OnP/0pAGD37t1485vfjHPPPRdveMMbln3/aaedBsdxDrry0jQNf/AHf4Dvf//73td+/vOfo9FoAMCy/6bbbrsNp5566qpk28997nPI5/M466yzvH+r17/+9cu+J8q9DwDz8/MH/Gk2mwd835vf/Gb85je/wbve9S784R/+IT7xiU/gb//2b/GiF70Iw+EQ73nPe3DmmWfiAx/4AD73uc+N/fsPhh//+Md45jOfiVNPPRU33XTTiu/T8ccfj7/7u78DALzuda/z3qezzz6byzUkkAQnQYIY4DOf+YwDwPnxj3+86vdcfPHFzsaNG535+fllX3/FK17hVKtVp9VqOY7jOIPBwOl2u8u+Z2lpyVm/fr3z2te+1vva9u3bHQBOpVJx9u3bt+z7r7zySgfAsu93HMd58Ytf7MzMzCz72rZt25zXvOY1B/y3nHvuuc5oNPK+/ta3vtVJp9NOvV53HMdx9uzZ42QyGef8889f9npXXXWVA2DZa66Gbdu2OS94wQuWfY1+//bt25d9/bvf/a4DwPnud7/rfe3pT3+6A8D57Gc/632t2+06GzZscF7ykpd4X/v0pz/tAHCuvfbaA66B/hv379/vAHCuvPLKA76H3k/C3Xff7QBwLrnkkmXf97//9/92ADjf+c53lv03AnC+//3ve1/bt2+fk8/nnbe97W0rvCs+3vKWtziVSsUZDAarfk+U9+WWW25xADhf+9rXDnhd27ado48+2nniE5/odDod5wUveIFTqVScRx555IDv3bVrlwPAed/73nfQ/54PfOADTjqddprNpuM4jvN//s//cbZt2+b83u/9nvOXf/mXjuM4znA4dGq1mvPWt77V+7nffv8dx3F0XV/xHpvk3l8Jr3nNaxwAK/4577zzvO+j+/S8885b9jk544wzHE3TnDe84Q3e1waDgbNlyxbn6U9/uve1lf7dHMf/XH/mM59Zdk26rjuO4zi33367U6lUnBe84AVOp9NZ9rNPf/rTl/2OH//4xwe8VoJDC8kkJ8EhAcdx8OUvfxkvetGL4DjOsu7wvPPOQ6PR8DrmdDrt7dZHoxEWFxcxGAzwlKc8xfueIF7ykpesOgH57Y77rLPOwsLCwood6W/jda973bIVwVlnnYXhcOjJjL/97W9jMBjgTW9607Kfe/Ob37zma/OEYRjL+BO5XA6/93u/h4ceesj72pe//GXMzs6ueG1hpOFf//rXAWDZ6gUA3va2twEAbrzxxmVfP+GEE3DWWWd5/3tubg7HHnvssmtcCbVaDbZt4+abb574Gsd5XxYWFgAAU1NTB/x8qVTCddddh/vuuw9nn302brzxRnzwgx/EYYcddsD30s+vJdume4gmPrfddhvOOussnHXWWbjtttsAAL/85S9Rr9eXvV9hEOXeLxQKuPnmmw/48973vveA77344ouX3UOnn346HMfBxRdf7H0tnU7jKU95ypr/3mvhu9/9Ls477zw861nPwg033KCUT5dADpIiJ8Ehgf3796Ner+MTn/gE5ubmlv256KKLALgkXML111+PJz3pSSgUCpiZmcHc3BxuvPFGb7QfxBFHHLHq7/3tA4kOo6WlpTWvea2fpWLn6KOPXvZ909PTKx6aorBly5YDCpWpqall/40PPvggjj32WG7k1UceeQSpVOqA//YNGzagVqsd4DezWmGw1r/Dm970JjzhCU/A8573PGzZsgWvfe1r8Y1vfGOsaxznfSE4Aa5IEH/wB3+AN77xjbjzzjtx3nnnrUospp9fq2B88pOfjFKp5BU0VOScffbZ+MlPfoJOp+P93Zlnnnnw/8A1EOXeT6fTOPfccw/4s5JC6bd/T7VaBQBs3br1gK+P87tXQ6fTwQte8AKceuqp+Nd//deEZPw7gnjKHRIk+C2MRiMAwKte9Sq85jWvWfF7nvSkJwEAPv/5z+PCCy/E+eefj7e//e1Yt24d0uk0rr76ajz44IMH/FyxWFz1964meV3tUOP1s1Gw2kE5HA5X/Lqq6wTGnwKFvcZ169bh7rvvxje/+U3cdNNNuOmmm/CZz3wGF1xwAa6//vrIv3NmZgbA6gd/t9v1iLEPPvggWq0WSqXSAd9HPz87O3vQa8pmszj99NPx/e9/Hw888AD27NmDs846C+vXr0e/38ePfvQj3HbbbTjuuONC8bOCkHVfrPZ7Vvp68HdPep/n83k8//nPx3/8x3/gG9/4Bl74wheGuNoEhxqSSU6CQwJzc3Mol8sYDocrdojnnnsu1q1bBwD493//dxx55JG44YYb8OpXvxrnnXcezj33XOlma2uBjOMeeOCBZV9fWFiI1LFSxx1U2wCY2I03iKOOOgr3338/+v3+qt8zydpq27ZtGI1G+M1vfrPs63v37kW9Xp/YVO9gyOVyeNGLXoSPfexjePDBB/H6178en/3sZw9438PguOOOAwBs3759xb+/8sorcd999+Ef//EfsX379lW9gujnjz/++DV/51lnnYU777wTt9xyC2ZnZ3HcccdhenoaT3ziE3HbbbfhtttuG4scG1cH6nEx6X2uaRq+8IUv4FnPehZe+tKXjmVaeai/RwmSIifBIYJ0Oo2XvOQl+PKXv4xf/vKXB/x9UJpNHWCw6/vRj36EO+64Q/yFToBnPetZyGQyB8iJP/KRj0R63aOOOgoAlqlwhsMhPvGJT4R+zZe85CWYn59f8drofaYJxW8fOivh+c9/PgAsU8UBwLXXXgsAeMELXhD6WoMgzgwhlUp5E7/flqqHwebNm7F169YVnbp/9KMf4R//8R/x53/+53jb296Gt7/97fjIRz6C733vewd871133QVN03DGGWes+TvPOussdLtdfOhDH8KZZ57pHcSklNq1a9dYfBxd18f6t4ortm3bhnQ6vew+B3DQiIxcLocbbrgBT33qU/GiF70Id95550F/h67rAMa7pxPEE8m6KkGs8OlPf3pFzsRb3vIWvPe978V3v/tdnH766bj00ktxwgknYHFxET/96U9xyy23eB4jL3zhC3HDDTfgxS9+MV7wghdg+/bt+PjHP44TTjjB88OIA9avX4+3vOUtuOaaa/CHf/iHeO5zn4uf/exnuOmmmzA7Oxu6i3ziE5+Ipz3tabjiiiuwuLiI6elp/Mu//AsGg0Hoa73gggvw2c9+FpdffjnuvPNOnHXWWbBtG7fccgve9KY34Y/+6I9QLBZxwgkn4Etf+hKe8IQnYHp6GieeeCJOPPHEA17v5JNPxmte8xp84hOfQL1ex9Of/nTceeeduP7663H++efjGc94RuhrDeKSSy7B4uIinvnMZ2LLli145JFH8OEPfxinnHLKWFOTcfBHf/RH+MpXvgLHcbx/s06ng9e85jU45phj8A//8A8AXP+gr33ta7jooovwi1/8wjtAAVfq/gd/8Afe+utgOOOMM5DJZHD//ffjda97nff1s88+2yuYxylyTjvtNNxyyy249tpr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3nvvPeV1NeeJRM4QUlhYiFdffRUlJSX4+9//juPHj+PHP/6x8npraysuvfRSjBo1Cvv27cOjjz6KlStX4o9//KOKo1aHI0eOIBwO49lnn8Xhw4fxxBNPYPPmzfjd736nnEPz1Y3f78e1116LxYsXR309FAphwYIF8Pv92LVrF1544QVs3boV999//xkeqfr85S9/wZ133okHHngAX3zxBaZNm4Z58+ahvr5e7aGpTkdHB6ZNm4ann3466uvr1q3Dk08+ic2bN2PPnj2Ij4/HvHnz4PV6z/BI1WfHjh1YunQpPvvsM3z44YcIBAK49NJL0dHRoZxzxx134B//+Af++te/YseOHaiursZ//Md/qDhqdcjMzMTatWuxb98+fP7557joootw5ZVX4vDhwwBUnidGnDbefPNNJggC8/v9jDHGnnnmGZaUlMR8Pp9yzt13383y8/PVGiJXrFu3juXm5irPab56s2XLFmaz2Xodf/fdd5lGo2G1tbXKsU2bNjGr1Roxf2cDs2bNYkuXLlWeh0Ihlp6eztasWaPiqPgDAHv99deV5+FwmLlcLvboo48qxzweDzMajezll19WYYR8UV9fzwCwHTt2MMbEudHr9eyvf/2rcs7XX3/NALDdu3erNUxuSEpKYv/7v/+r+jyRJec00dTUhJdeeglz5syBXq8HAOzevRs/+MEPYDAYlPPmzZuHkpISNDc3qzVUbmhpaYHdblee03zFzu7duzFlyhSkpqYqx+bNm4fW1lZlN3U24Pf7sW/fPlxyySXKMY1Gg0suuQS7d+9WcWT8U1paitra2oi5s9lsmD17Ns0dxPUJgLJG7du3D4FAIGK+xo8fj+zs7LN6vkKhEF555RV0dHSgoKBA9XkikTPE3H333YiPj0dycjLKy8vx5ptvKq/V1tZG3IQAKM9ra2vP6Dh549ixY3jqqafw61//WjlG8xU7NFcijY2NCIVCUefibJqH74I8PzR3vQmHw1i2bBnmzp2LyZMnAxDny2Aw9IqRO1vn69ChQ7BYLDAajVi0aBFef/11TJw4UfV5IpEzAPfccw8EQej3ceTIEeX8u+66C/v378cHH3wArVaLG2+8EewsKio92PkCgKqqKsyfPx/XXnstbr31VpVGfub5LnNFEMSZZ+nSpfjyyy/xyiuvqD0UbsnPz0dxcTH27NmDxYsX46abbsJXX32l9rCgU3sAvLN8+XLcfPPN/Z4zevRo5WeHwwGHw4G8vDxMmDABWVlZ+Oyzz1BQUACXy9Urolx+7nK5hnzsajDY+aqurkZhYSHmzJnTK6B4pM/XYOeqP1wuV68MopE0V7HicDig1WqjXjdn0zx8F+T5qaurQ1pamnK8rq4O06dPV2lU6nPbbbfh7bffxieffILMzEzluMvlgt/vh8fjibBSnK3XmsFgwNixYwEAM2bMwN69e7Fx40Zcd911qs4TiZwBcDqdcDqd3+l3w+EwAMDn8wEACgoK8Pvf/x6BQECJ0/nwww+Rn5+PpKSkoRmwygxmvqqqqlBYWIgZM2Zgy5Yt0GgiDYsjfb5O5do6mYKCAqxevRr19fVISUkBIM6V1WrFxIkTh+Q9hgMGgwEzZsxAUVERrrrqKgDi97CoqAi33XabuoPjnNzcXLhcLhQVFSmiprW1VdmZn20wxvCb3/wGr7/+OrZv347c3NyI12fMmAG9Xo+ioiJcc801AICSkhKUl5ejoKBAjSFzRTgchs/nU3+eTnto81nCZ599xp566im2f/9+VlZWxoqKiticOXPYmDFjmNfrZYyJ0fipqanshhtuYF9++SV75ZVXmNlsZs8++6zKoz/zVFZWsrFjx7KLL76YVVZWspqaGuUhQ/PVzYkTJ9j+/fvZgw8+yCwWC9u/fz/bv38/a2trY4wxFgwG2eTJk9mll17KiouL2bZt25jT6WT33nuvyiM/87zyyivMaDSyrVu3sq+++or96le/YomJiRGZZ2crbW1tyrUDgD3++ONs//797MSJE4wxxtauXcsSExPZm2++yQ4ePMiuvPJKlpuby7q6ulQe+Zln8eLFzGazse3bt0esT52dnco5ixYtYtnZ2eyf//wn+/zzz1lBQQErKChQcdTqcM8997AdO3aw0tJSdvDgQXbPPfcwQRDYBx98wBhTd55I5AwRBw8eZIWFhcxutzOj0chycnLYokWLWGVlZcR5Bw4cYOeddx4zGo0sIyODrV27VqURq8uWLVsYgKiPntB8idx0001R5+rjjz9WzikrK2OXXXYZi4uLYw6Hgy1fvpwFAgH1Bq0iTz31FMvOzmYGg4HNmjWLffbZZ2oPiQs+/vjjqNfRTTfdxBgT08jvu+8+lpqayoxGI7v44otZSUmJuoNWib7Wpy1btijndHV1sSVLlrCkpCRmNpvZ1VdfHbFRO1v45S9/yUaNGsUMBgNzOp3s4osvVgQOY+rOk8DYWRQVSxAEQRDEWQNlVxEEQRAEMSIhkUMQBEEQxIiERA5BEARBECMSEjkEQRAEQYxISOQQBEEQBDEiIZFDEARBEMSIhEQOQRAEQRAjEhI5BEEQBEGMSEjkEARBEAQxIiGRQxAEQRDEiIREDkEQI4KGhga4XC48/PDDyrFdu3bBYDCgqKhIxZERBKEW1LuKIIgRw7vvvourrroKu3btQn5+PqZPn44rr7wSjz/+uNpDIwhCBUjkEAQxoli6dCk++ugjzJw5E4cOHcLevXthNBrVHhZBECpAIocgiBFFV1cXJk+ejIqKCuzbtw9TpkxRe0gEQagExeQQBDGiOH78OKqrqxEOh1FWVqb2cAiCUBGy5BAEMWLw+/2YNWsWpk+fjvz8fGzYsAGHDh1CSkqK2kMjCEIFSOQQBDFiuOuuu/C3v/0NBw4cgMViwQUXXACbzYa3335b7aERBKEC5K4iCGJEsH37dmzYsAEvvvgirFYrNBoNXnzxRfzrX//Cpk2b1B4eQRAqQJYcgiAIgiBGJGTJIQiCIAhiREIihyAIgiCIEQmJHIIgCIIgRiQkcgiCIAiCGJGQyCEIgiAIYkRCIocgCIIgiBEJiRyCIAiCIEYkJHIIgiAIghiRkMghCIIgCGJEQiKHIAiCIIgRCYkcgiAIgiBGJCRyCIIgCIIYkfx/BAfFLyeEUs4AAAAASUVORK5CYII=", "text/plain": [ - "
" + "
" ] }, - "metadata": { - "needs_background": "light" - }, + "metadata": {}, "output_type": "display_data" } ], @@ -176,7 +161,7 @@ "predicted_y = []\n", "predicted_std = []\n", "for x in real_x:\n", - " y, var = emukit_model.predict(np.array([[x]]))\n", + " y, var = gp_model.predict(np.array([[x]]))\n", " std = np.sqrt(var)\n", " predicted_y.append(y)\n", " predicted_std.append(std)\n", @@ -192,11 +177,18 @@ "plt.legend(['True function', 'Estimated function'], loc='lower right')\n", "plt.fill_between(real_x, predicted_y - 2 * predicted_std, predicted_y + 2 * predicted_std, alpha=.5);" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -210,7 +202,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.6" + "version": "3.12.0" } }, "nbformat": 4, diff --git a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py index 70739079..494d93be 100644 --- a/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py +++ b/tests/emukit/bayesian_optimization/test_cost_sensitive_bayesian_optimization.py @@ -4,12 +4,6 @@ # Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 - -import pytest - -pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") -pytestmark = pytest.mark.gpy -import GPy import numpy as np from emukit.bayesian_optimization.loops.cost_sensitive_bayesian_optimization_loop import ( @@ -17,7 +11,7 @@ ) from emukit.core import ContinuousParameter, ParameterSpace from emukit.core.loop.user_function import UserFunctionWrapper -from emukit.model_wrappers import GPyModelWrapper +from emukit.model_wrappers import SimpleGaussianProcessModel def test_cost_sensitive_bayesian_optimization_loop(): @@ -32,11 +26,8 @@ def function_with_cost(x): y_init, cost_init = function_with_cost(x_init) - gpy_model_objective = GPy.models.GPRegression(x_init, y_init) - gpy_model_cost = GPy.models.GPRegression(x_init, cost_init) - - model_objective = GPyModelWrapper(gpy_model_objective) - model_cost = GPyModelWrapper(gpy_model_cost) + model_objective = SimpleGaussianProcessModel(x_init, y_init) + model_cost = SimpleGaussianProcessModel(x_init, cost_init) loop = CostSensitiveBayesianOptimizationLoop(space, model_objective, model_cost) loop.run_loop(user_fcn, 10) diff --git a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py index 8e583cf9..c7079fbe 100644 --- a/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py +++ b/tests/emukit/bayesian_optimization/test_mean_plugin_expected_improvement.py @@ -1,10 +1,6 @@ # Copyright 2020-2024 The Emukit Authors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 - -# GPy optional: this test does not require GPy and runs in core environment -from unittest.mock import MagicMock - import numpy as np import pytest diff --git a/tests/emukit/core/test_outer_loop.py b/tests/emukit/core/test_outer_loop.py index 167c8a9d..ff5c770c 100644 --- a/tests/emukit/core/test_outer_loop.py +++ b/tests/emukit/core/test_outer_loop.py @@ -7,9 +7,6 @@ import pytest -pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") -pytestmark = pytest.mark.gpy -import GPy import mock import numpy as np @@ -28,7 +25,7 @@ from emukit.core.loop.loop_state import create_loop_state from emukit.core.optimization import GradientAcquisitionOptimizer from emukit.experimental_design.acquisitions import ModelVariance -from emukit.model_wrappers import GPyModelWrapper +from emukit.model_wrappers import SimpleGaussianProcessModel @pytest.fixture @@ -156,8 +153,7 @@ def user_function(x): x_init = np.linspace(0, 1, 5)[:, None] y_init = user_function(x_init) - gpy_model = GPy.models.GPRegression(x_init, y_init) - model = GPyModelWrapper(gpy_model) + model = SimpleGaussianProcessModel(x_init, y_init) mse = [] diff --git a/tests/emukit/experimental_design/test_experimental_design_loop.py b/tests/emukit/experimental_design/test_experimental_design_loop.py index 98618d7f..d0f4bdf7 100644 --- a/tests/emukit/experimental_design/test_experimental_design_loop.py +++ b/tests/emukit/experimental_design/test_experimental_design_loop.py @@ -4,12 +4,6 @@ # Copyright 2018-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 - -import pytest - -pytest.importorskip("GPy", reason="GPy not installed; install emukit[gpy]") -pytestmark = pytest.mark.gpy -import GPy import numpy as np from numpy.testing import assert_array_equal @@ -18,7 +12,7 @@ from emukit.core.parameter_space import ParameterSpace from emukit.experimental_design import ExperimentalDesignLoop from emukit.experimental_design.acquisitions import ModelVariance -from emukit.model_wrappers import GPyModelWrapper +from emukit.model_wrappers import SimpleGaussianProcessModel def f(x): @@ -29,8 +23,7 @@ def test_loop_initial_state(): x_init = np.random.rand(5, 1) y_init = np.random.rand(5, 1) - gpy_model = GPy.models.GPRegression(x_init, y_init) - model = GPyModelWrapper(gpy_model) + model = SimpleGaussianProcessModel(x_init, y_init) space = ParameterSpace([ContinuousParameter("x", 0, 1)]) exp_design = ExperimentalDesignLoop(space, model) @@ -46,9 +39,7 @@ def test_loop(): x_init = np.random.rand(5, 1) y_init = np.random.rand(5, 1) - # Make GPy model - gpy_model = GPy.models.GPRegression(x_init, y_init) - model = GPyModelWrapper(gpy_model) + model = SimpleGaussianProcessModel(x_init, y_init) space = ParameterSpace([ContinuousParameter("x", 0, 1)]) acquisition = ModelVariance(model) From 4c7291542c448d4d97c6a14c9e4677375ffd41a9 Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:18:52 +0000 Subject: [PATCH 18/26] Notice, update rtd python version --- .readthedocs.yml | 2 +- README.md | 5 ++++- doc/installation.rst | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 67be8a02..2e2a9a23 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,7 +5,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.9" + python: "3.10" sphinx: configuration: doc/conf.py diff --git a/README.md b/README.md index 09390773..66acb180 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ For other install options, see our [documentation](https://emukit.readthedocs.io ### Dependencies / Optional Extras Core dependencies are the numerical Python stack (NumPy, SciPy, matplotlib, emcee). Optional groups enable additional features without pulling heavy dependencies into a minimal install: -- `gpy`: Gaussian process wrappers, multi-fidelity models, Bayesian quadrature (adds `GPy`). +- `gpy`: Gaussian process wrappers, multi-fidelity models, Bayesian quadrature (adds `GPy`). Also see notice below. - `bnn`: Bayesian neural network (Bohamiann) and Profet meta-surrogate examples (adds `pybnn`, `torch`). - `sklearn`: scikit-learn model wrapper and examples (adds `scikit-learn`). - `docs`: Build documentation locally (adds Sphinx toolchain + GPy to render GP API docs). @@ -65,6 +65,9 @@ pip install emukit[full] ``` Legacy pinned requirement files remain in the `requirements/` directory for reference but extras (above) are the preferred installation mechanism going forward. +### NumPy 2 notice +Core Emukit functionality works with NumPy 2.0+. However, some parts of Emukit (e.g. most acquisition functions) need GPy, that for the time being is a bit behind. If using GPy is critical for you, consider installing earlier versions of Emukit. + ## Getting started For examples see our [tutorial notebooks](http://nbviewer.jupyter.org/github/emukit/emukit/blob/main/notebooks/index.ipynb). diff --git a/doc/installation.rst b/doc/installation.rst index 23cd38d2..e6f13f58 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -1,7 +1,7 @@ Installation ============ -Emukit requires Python 3.9 or above. The core installation provides the numerical stack and Emukit's pure numpy features. Gaussian process functionality based on GPy, multi-fidelity models, and quadrature models require the optional GPy extra. +Emukit requires Python 3.10 or above. The core installation provides the numerical stack and Emukit's pure numpy features. Gaussian process functionality based on GPy, multi-fidelity models, and quadrature models require the optional GPy extra. To install the core emukit package (without GPy), run @@ -62,3 +62,6 @@ If you would like a bit more control (e.g. for development), clone the repo, ins `python setup.py develop` is no longer needed; PEP 621 metadata in `pyproject.toml` enables editable installs directly via pip (PEP 660). +NumPy 2 notice +________ +Core Emukit functionality works with NumPy 2.0+. However, some parts of Emukit (e.g. most acquisition functions) need GPy, that for the time being is a bit behind. If using GPy is critical for you, consider installing earlier versions of Emukit. \ No newline at end of file From f1e24e10593e642a216086cc7307c4a7acd0ca43 Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:19:22 +0000 Subject: [PATCH 19/26] Test for modern python versions --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 07ca220d..62b8724e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.13"] steps: - uses: actions/checkout@v5 From 387f90b80b5e208f05514a367db00b84130f9a1e Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:24:46 +0000 Subject: [PATCH 20/26] Add nbformat --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6276647b..24812659 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ tests = [ "pytest>=3.5.1", "pytest-cov>=2.5.1", "mock>=2.0.0", + "nbformat", ] # Aggregate ALL optional dependencies for development dev = [ From df270b6f91c6bf00c79620a946dbd3db93affaac Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:35:35 +0000 Subject: [PATCH 21/26] Add integ tests install, fix a warning, fix linting --- .github/workflows/tests.yml | 1 + .../acquisitions/max_value_entropy_search.py | 5 ++--- pyproject.toml | 11 ++++++----- tests/emukit/core/test_outer_loop.py | 3 +-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 62b8724e..fb36aa11 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,6 +31,7 @@ jobs: python -m pytest tests - name: Integration tests (core) run: | + pip install -e .[integration-tests] python -m pytest integration_tests gpy_tests: diff --git a/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py b/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py index aa98e5ae..642c2098 100644 --- a/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py +++ b/emukit/bayesian_optimization/acquisitions/max_value_entropy_search.py @@ -5,10 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -from typing import Callable, Union +from typing import Union import numpy as np -import scipy from scipy.integrate import simpson from scipy.optimize import bisect from scipy.stats import norm @@ -301,7 +300,7 @@ def evaluate(self, x: np.ndarray) -> np.ndarray: # calculate point-wise entropy function contributions (carefuly where density is 0) entropy_function = -density * np.log(density, out=np.zeros_like(density), where=(density != 0)) # perform integration over ranges - approximate_entropy = simpson(entropy_function.T, z.T) + approximate_entropy = simpson(entropy_function.T, x=z.T) # build monte-carlo estimate over the gumbel samples approximate_entropy = np.mean(approximate_entropy, axis=0) diff --git a/pyproject.toml b/pyproject.toml index 24812659..3a124d0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,6 @@ dependencies = [ ] [project.optional-dependencies] -# Mirrors previous extras_require in setup.py (unchanged for minimal migration) gpy = ["GPy>=1.13.0"] bnn = ["pybnn>=0.0.5", "torch"] sklearn = ["scikit-learn"] @@ -51,11 +50,9 @@ docs = [ "sphinx-autodoc-typehints>=1.3.0", "sphinx-rtd-theme>=0.4.1", ] -# Test & QA dependencies (as before) +# Test & QA dependencies tests = [ "coverage>=4.5.1", - "pandas", - "ipykernel", "codecov>=2.0.15", "flake8>=3.5.0", "isort>=5.10", @@ -63,7 +60,11 @@ tests = [ "pytest>=3.5.1", "pytest-cov>=2.5.1", "mock>=2.0.0", - "nbformat", +] +integration-tests = [ + "emukit[tests]", + "pandas", + "jupyter", ] # Aggregate ALL optional dependencies for development dev = [ diff --git a/tests/emukit/core/test_outer_loop.py b/tests/emukit/core/test_outer_loop.py index ff5c770c..174c6580 100644 --- a/tests/emukit/core/test_outer_loop.py +++ b/tests/emukit/core/test_outer_loop.py @@ -5,10 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 -import pytest - import mock import numpy as np +import pytest from emukit.core import ContinuousParameter, ParameterSpace from emukit.core.interfaces import IModel From 6d8e7e001881f948dc900bad689c8d506066b32f Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:46:59 +0000 Subject: [PATCH 22/26] improve test skipping --- .github/workflows/tests.yml | 3 ++- integration_tests/emukit/notebooks/test_notebooks.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fb36aa11..10cedcfe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,13 +50,14 @@ jobs: - name: Install dependencies with GPy extra run: | python -m pip install --upgrade pip - pip install -e .[tests,gpy] + pip install -e .[tests, gpy] echo 'backend: Agg' > matplotlibrc - name: Unit tests (with GPy) run: | python -m pytest tests -m 'gpy or not gpy' - name: Integration tests (with GPy) run: | + pip install -e .[integration-tests, gpy] python -m pytest integration_tests -m 'gpy or not gpy' os_versions: diff --git a/integration_tests/emukit/notebooks/test_notebooks.py b/integration_tests/emukit/notebooks/test_notebooks.py index ae4b96a4..fd91e98e 100644 --- a/integration_tests/emukit/notebooks/test_notebooks.py +++ b/integration_tests/emukit/notebooks/test_notebooks.py @@ -15,7 +15,9 @@ import pytest -pytestmark = pytest.mark.notebooks +# many notebooks use GPy, therefore add this mark too +GPy = pytest.importorskip("GPy") +pytestmark = [pytest.mark.gpy, pytest.mark.notebooks] import nbformat from nbconvert.preprocessors import ExecutePreprocessor From 9d5b1ace1670d3ef0ed9128d4df8275436adcd94 Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:52:24 +0000 Subject: [PATCH 23/26] fix? --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 10cedcfe..38e799b1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -50,14 +50,14 @@ jobs: - name: Install dependencies with GPy extra run: | python -m pip install --upgrade pip - pip install -e .[tests, gpy] + pip install -e ".[tests, gpy]" echo 'backend: Agg' > matplotlibrc - name: Unit tests (with GPy) run: | python -m pytest tests -m 'gpy or not gpy' - name: Integration tests (with GPy) run: | - pip install -e .[integration-tests, gpy] + pip install -e ".[integration-tests, gpy]" python -m pytest integration_tests -m 'gpy or not gpy' os_versions: From e8685e3fd4dfb4bf10213017a8fcff0e3398c05f Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 11:59:59 +0000 Subject: [PATCH 24/26] Improve coverage reports, remove editable installs --- .github/workflows/codecov.yml | 12 ++++++++---- .github/workflows/tests.yml | 10 +++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index aae12863..a6471c49 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -24,12 +24,16 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install flake8 pytest - pip install -e .[tests] - # work around issues with GPy setting matplotlib backend - echo 'backend: Agg' > matplotlibrc - - name: Run coverage + - name: Run core coverage run: | + pip install .[tests] python -m pytest --verbose --cov emukit --cov-report term-missing tests + - name: Run GPy coverage + run: | + pip install ".[tests, gpy]" + # work around issues with GPy setting matplotlib backend + echo 'backend: Agg' > matplotlibrc + python -m pytest -m 'gpy or not gpy' --verbose --cov emukit --cov-report term-missing tests - name: Run codecov if: success() run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 38e799b1..71f22ba7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: - name: Install core dependencies (no GPy) run: | python -m pip install --upgrade pip - pip install -e .[tests] + pip install .[tests] # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc - name: Unit tests (core) @@ -31,7 +31,7 @@ jobs: python -m pytest tests - name: Integration tests (core) run: | - pip install -e .[integration-tests] + pip install .[integration-tests] python -m pytest integration_tests gpy_tests: @@ -50,14 +50,14 @@ jobs: - name: Install dependencies with GPy extra run: | python -m pip install --upgrade pip - pip install -e ".[tests, gpy]" + pip install ".[tests, gpy]" echo 'backend: Agg' > matplotlibrc - name: Unit tests (with GPy) run: | python -m pytest tests -m 'gpy or not gpy' - name: Integration tests (with GPy) run: | - pip install -e ".[integration-tests, gpy]" + pip install ".[integration-tests, gpy]" python -m pytest integration_tests -m 'gpy or not gpy' os_versions: @@ -76,7 +76,7 @@ jobs: - name: Install dependencies (core) run: | python -m pip install --upgrade pip - pip install -e .[tests] + pip install .[tests] # work around issues with GPy setting matplotlib backend (defensive even w/o GPy) echo 'backend: Agg' > matplotlibrc - name: Unit tests (core, multi-OS) From ff9f010de83622e4251545faa4044c46077977e0 Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 12:06:07 +0000 Subject: [PATCH 25/26] One job to monitor --- .github/workflows/tests.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 71f22ba7..ef4c4248 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -82,3 +82,19 @@ jobs: - name: Unit tests (core, multi-OS) run: | python -m pytest tests + + all-pass: + if: always() + needs: [core_tests, gpy_tests, os_versions] + + runs-on: ubuntu-latest + + steps: + - name: Check all tests pass + run: | + if [[ "${{ needs.core_tests.result }}" != "success" && "${{ needs.core_tests.result }}" != "skipped" ]] || \ + [[ "${{ needs.gpy_tests.result }}" != "success" && "${{ needs.gpy_tests.result }}" != "skipped" ]] || \ + [[ "${{ needs.os_versions.result }}" != "success" && "${{ needs.os_versions.result }}" != "skipped" ]]; then + echo "One or more test jobs failed" + exit 1 + fi From b24a4c4b4d4301887b9e02db8a5d513527607f13 Mon Sep 17 00:00:00 2001 From: Andrei Paleyes Date: Fri, 19 Dec 2025 12:14:20 +0000 Subject: [PATCH 26/26] fix? --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ef4c4248..bc7201a6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,7 +57,7 @@ jobs: python -m pytest tests -m 'gpy or not gpy' - name: Integration tests (with GPy) run: | - pip install ".[integration-tests, gpy]" + pip install ".[integration-tests, examples]" python -m pytest integration_tests -m 'gpy or not gpy' os_versions: