From 70010501039535f4c60050e1f3209d106b331e22 Mon Sep 17 00:00:00 2001 From: Sait Cakmak Date: Fri, 5 Jun 2026 08:26:33 -0700 Subject: [PATCH] Add DeprecationError exception and migrate raise DeprecationWarning usages Summary: Introduce `DeprecationError(AxError)` in `ax/exceptions/core.py` for hard-break deprecations where accessing a removed/deprecated API should fail immediately with an actionable message. `raise DeprecationWarning(...)` is semantically incorrect: `DeprecationWarning` is a warning *category*, not an exception type. Raising it (a) does not interoperate with `warnings.catch_warnings()` / `simplefilter("ignore", DeprecationWarning)` -- it still crashes -- and (b) violates the Ax team rule that runtime errors should be raised from `ax/exceptions` types. This diff adds a dedicated error class for that purpose and migrates the existing in-repo `raise DeprecationWarning` sites to it: - `ax/service/utils/scheduler_options.py` (SchedulerOptions) - `ax/adapter/pairwise.py` (PairwiseAdapter) - `ax/core/batch_trial.py` (`_status_quo_weight_override`) - `ax/fb/service/ax_batch_client.py` (`attach_batch_trial`) For *soft* deprecations that should still work with a notice, continue to use `warnings.warn(..., DeprecationWarning)` -- this error is only for hard breaks. This is a prerequisite for migrating `RangeParameter.digits` (in a stacked diff) off `raise DeprecationWarning`. Differential Revision: D107660126 --- ax/adapter/pairwise.py | 3 ++- ax/core/batch_trial.py | 9 +++++++-- ax/exceptions/core.py | 16 ++++++++++++++++ ax/service/utils/scheduler_options.py | 4 +++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/ax/adapter/pairwise.py b/ax/adapter/pairwise.py index 20b0a5eeb35..039b485ef76 100644 --- a/ax/adapter/pairwise.py +++ b/ax/adapter/pairwise.py @@ -9,12 +9,13 @@ from typing import Any from ax.adapter.torch import TorchAdapter +from ax.exceptions.core import DeprecationError # PairwiseAdapter was deprecated in Ax 1.1.0, so it should be reaped in Ax # 1.2.0+ class PairwiseAdapter(TorchAdapter): def __init__(self, **kwargs: Any) -> None: - raise DeprecationWarning( + raise DeprecationError( "PairwiseAdapter is deprecated. Use TorchAdapter instead." ) diff --git a/ax/core/batch_trial.py b/ax/core/batch_trial.py index 2a7e7d99c1f..43d05839910 100644 --- a/ax/core/batch_trial.py +++ b/ax/core/batch_trial.py @@ -26,7 +26,12 @@ TEvaluationOutcome, validate_evaluation_outcome, ) -from ax.exceptions.core import AxError, UnsupportedError, UserInputError +from ax.exceptions.core import ( + AxError, + DeprecationError, + UnsupportedError, + UserInputError, +) from ax.utils.common.base import SortableBase from ax.utils.common.docutils import copy_doc from ax.utils.common.equality import datetime_equals, equality_typechecker @@ -183,7 +188,7 @@ def arm_weights(self) -> MutableMapping[Arm, float]: @property def _status_quo_weight_override(self) -> None: - raise DeprecationWarning( + raise DeprecationError( "Status quo weight override is no longer supported. Please " "contact the Ax developers for help adjusting your application." ) diff --git a/ax/exceptions/core.py b/ax/exceptions/core.py index ab1b12827f5..9d15d3cc8c7 100644 --- a/ax/exceptions/core.py +++ b/ax/exceptions/core.py @@ -41,6 +41,22 @@ class UnsupportedError(AxError): """ +class DeprecationError(AxError): + """Raised when deprecated functionality is accessed as a hard break. + + Use this for deprecations that have reached the point of removal, where + accessing the deprecated API (e.g. reading a removed property) should fail + immediately with an actionable message rather than silently returning a + wrong value. Prefer this over ``raise DeprecationWarning(...)``: + ``DeprecationWarning`` is a warning *category*, not an exception type, so + raising it is semantically incorrect and is not suppressible via + ``warnings.simplefilter("ignore", DeprecationWarning)``. + + For *soft* deprecations that should still work (just with a notice), use + ``warnings.warn(..., DeprecationWarning)`` instead of this error. + """ + + class UnsupportedPlotError(AxError): """Raised when plotting functionality is not supported for the given configurations. diff --git a/ax/service/utils/scheduler_options.py b/ax/service/utils/scheduler_options.py index aef9fa2a27f..19e6489b7bc 100644 --- a/ax/service/utils/scheduler_options.py +++ b/ax/service/utils/scheduler_options.py @@ -8,9 +8,11 @@ # Scheduler was deprecated in Ax 1.1.0, so it should be removed in Ax # Ax 1.2.0+. +from ax.exceptions.core import DeprecationError + class SchedulerOptions: - raise DeprecationWarning( + raise DeprecationError( "Scheduler is deprecated following renaming of the Scheduler to " "Orchestrator. Please use Orchestrator and OrchestratorOptions instead; " "import with: `from ax.orchestration.orchestrator import Orchestrator, "