From 8b4463e474a42da746262b25173ece6ac03df482 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Wed, 6 Nov 2024 11:54:44 +0400 Subject: [PATCH 1/4] Add API warnings infrastructure --- .../_async/client/utils.py | 4 ++ .../_sync/client/utils.py | 48 ++++++++++++++ elasticsearch_serverless/exceptions.py | 4 ++ .../test_client/test_utils.py | 66 ++++++++++++++++++- 4 files changed, 119 insertions(+), 3 deletions(-) diff --git a/elasticsearch_serverless/_async/client/utils.py b/elasticsearch_serverless/_async/client/utils.py index 2f062de..60366c7 100644 --- a/elasticsearch_serverless/_async/client/utils.py +++ b/elasticsearch_serverless/_async/client/utils.py @@ -19,10 +19,12 @@ _TYPE_HOST, CLIENT_META_SERVICE, SKIP_IN_PATH, + Stability, _base64_auth_header, _quote, _quote_query, _rewrite_parameters, + _stability_warning, client_node_config, is_requests_http_auth, is_requests_node_class, @@ -35,8 +37,10 @@ "_quote_query", "_TYPE_HOST", "SKIP_IN_PATH", + "Stability", "client_node_config", "_rewrite_parameters", + "_stability_warning", "is_requests_http_auth", "is_requests_node_class", ] diff --git a/elasticsearch_serverless/_sync/client/utils.py b/elasticsearch_serverless/_sync/client/utils.py index 980870d..536f99d 100644 --- a/elasticsearch_serverless/_sync/client/utils.py +++ b/elasticsearch_serverless/_sync/client/utils.py @@ -19,6 +19,7 @@ import inspect import warnings from datetime import date, datetime +from enum import Enum, auto from functools import wraps from typing import ( TYPE_CHECKING, @@ -46,6 +47,8 @@ url_to_node_config, ) +from elasticsearch_serverless.exceptions import GeneralAvailabilityWarning + from ..._version import __versionstr__ from ...compat import to_bytes, to_str, warn_stacklevel @@ -62,6 +65,14 @@ USER_AGENT = create_user_agent("elasticsearch-py", __versionstr__) ELASTIC_API_VERSION = "2023-10-31" + +class Stability(Enum): + STABLE = auto() + BETA = auto() + EXPERIMENTAL = auto() + DEPRECATED = auto() + + _TYPE_HOST = Union[str, Mapping[str, Union[str, int]], NodeConfig] _TYPE_BODY = Union[bytes, str, Dict[str, Any]] @@ -420,6 +431,43 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: return wrapper +def _stability_warning( + stability: Stability, + version: Optional[str] = None, + message: Optional[str] = None, +) -> Callable[[F], F]: + def wrapper(api: F) -> F: + @wraps(api) + def wrapped(*args: Any, **kwargs: Any) -> Any: + if stability == Stability.BETA: + warnings.warn( + "This API is in beta and is subject to change. " + "The design and code is less mature than official GA features and is being provided as-is with no warranties. " + "Beta features are not subject to the support SLA of official GA features.", + category=GeneralAvailabilityWarning, + stacklevel=warn_stacklevel(), + ) + elif stability == Stability.EXPERIMENTAL: + warnings.warn( + "This API is in technical preview and may be changed or removed in a future release. " + "Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.", + category=GeneralAvailabilityWarning, + stacklevel=warn_stacklevel(), + ) + elif stability == Stability.DEPRECATED: + warnings.warn( + f"This API was deprecated in Elasticsearch {version}. {message}", + category=DeprecationWarning, + stacklevel=warn_stacklevel(), + ) + + return api(*args, **kwargs) + + return wrapped # type: ignore[return-value] + + return wrapper + + def is_requests_http_auth(http_auth: Any) -> bool: """Detect if an http_auth value is a custom Requests auth object""" try: diff --git a/elasticsearch_serverless/exceptions.py b/elasticsearch_serverless/exceptions.py index f587067..dc410ae 100644 --- a/elasticsearch_serverless/exceptions.py +++ b/elasticsearch_serverless/exceptions.py @@ -115,6 +115,10 @@ class ElasticsearchWarning(TransportWarning): """ +class GeneralAvailabilityWarning(TransportWarning): + """Warning that is raised when a feature is not yet GA.""" + + # Aliases for backwards compatibility ElasticsearchDeprecationWarning = ElasticsearchWarning RequestError = BadRequestError diff --git a/test_elasticsearch_serverless/test_client/test_utils.py b/test_elasticsearch_serverless/test_client/test_utils.py index 32c56bd..90f8b10 100644 --- a/test_elasticsearch_serverless/test_client/test_utils.py +++ b/test_elasticsearch_serverless/test_client/test_utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Licensed to Elasticsearch B.V. under one or more contributor # license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright @@ -16,9 +15,11 @@ # specific language governing permissions and limitations # under the License. -from __future__ import unicode_literals -from elasticsearch_serverless._sync.client.utils import _quote +import warnings + +from elasticsearch._sync.client.utils import Stability, _quote, _stability_warning +from elasticsearch.exceptions import GeneralAvailabilityWarning def test_handles_ascii(): @@ -38,3 +39,62 @@ def test_handles_unicode(): def test_handles_unicode2(): string = "中*文," assert "%E4%B8%AD*%E6%96%87," == _quote(string) + + +class TestStabilityWarning: + def test_default(self): + + @_stability_warning(stability=Stability.STABLE) + def func_default(*args, **kwargs): + pass + + with warnings.catch_warnings(): + warnings.simplefilter("error") + func_default() + + def test_beta(self, recwarn): + + @_stability_warning(stability=Stability.BETA) + def func_beta(*args, **kwargs): + pass + + func_beta() + + assert len(recwarn) == 1 + user_warning = recwarn.pop(GeneralAvailabilityWarning) + assert user_warning.category == GeneralAvailabilityWarning + assert user_warning.message.args[0].startswith( + "This API is in beta and is subject to change." + ) + + def test_experimental(self, recwarn): + + @_stability_warning(stability=Stability.EXPERIMENTAL) + def func_experimental(*args, **kwargs): + pass + + func_experimental() + + assert len(recwarn) == 1 + user_warning = recwarn.pop(GeneralAvailabilityWarning) + assert user_warning.category == GeneralAvailabilityWarning + assert user_warning.message.args[0].startswith( + "This API is in technical preview and may be changed or removed in a future release." + ) + + def test_deprecated(self, recwarn): + + @_stability_warning( + stability=Stability.DEPRECATED, version="8.4.0", message="Use bar instead." + ) + def func_deprecated(*args, **kwargs): + pass + + func_deprecated() + + assert len(recwarn) == 1 + user_warning = recwarn.pop(DeprecationWarning) + assert user_warning.category == DeprecationWarning + assert user_warning.message.args[0] == ( + "This API was deprecated in Elasticsearch 8.4.0. Use bar instead." + ) From 70071fb9a05f75664b02106fa2c0a63ed28b1c26 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Wed, 6 Nov 2024 12:00:19 +0400 Subject: [PATCH 2/4] Auto-generated API code --- .../_async/client/__init__.py | 3 ++ .../_async/client/connector.py | 32 ++++++++++++++++++- .../_async/client/inference.py | 12 ++++++- elasticsearch_serverless/_async/client/ml.py | 9 +++++- .../_async/client/search_application.py | 16 +++++++++- .../_async/client/tasks.py | 9 +++++- .../_sync/client/__init__.py | 3 ++ .../_sync/client/connector.py | 32 ++++++++++++++++++- .../_sync/client/inference.py | 12 ++++++- elasticsearch_serverless/_sync/client/ml.py | 9 +++++- .../_sync/client/search_application.py | 16 +++++++++- .../_sync/client/tasks.py | 9 +++++- 12 files changed, 152 insertions(+), 10 deletions(-) diff --git a/elasticsearch_serverless/_async/client/__init__.py b/elasticsearch_serverless/_async/client/__init__.py index 127bf8a..fdf058b 100644 --- a/elasticsearch_serverless/_async/client/__init__.py +++ b/elasticsearch_serverless/_async/client/__init__.py @@ -59,8 +59,10 @@ _TYPE_HOST, CLIENT_META_SERVICE, SKIP_IN_PATH, + Stability, _quote, _rewrite_parameters, + _stability_warning, client_node_config, is_requests_http_auth, is_requests_node_class, @@ -3070,6 +3072,7 @@ async def render_search_template( @_rewrite_parameters( body_fields=("context", "context_setup", "script"), ) + @_stability_warning(Stability.EXPERIMENTAL) async def scripts_painless_execute( self, *, diff --git a/elasticsearch_serverless/_async/client/connector.py b/elasticsearch_serverless/_async/client/connector.py index 28186bc..79ffd7d 100644 --- a/elasticsearch_serverless/_async/client/connector.py +++ b/elasticsearch_serverless/_async/client/connector.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class ConnectorClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def check_in( self, *, @@ -67,6 +74,7 @@ async def check_in( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def delete( self, *, @@ -115,6 +123,7 @@ async def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def get( self, *, @@ -157,6 +166,7 @@ async def get( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) async def list( self, *, @@ -230,6 +240,7 @@ async def list( "service_type", ), ) + @_stability_warning(Stability.BETA) async def post( self, *, @@ -311,6 +322,7 @@ async def post( "service_type", ), ) + @_stability_warning(Stability.BETA) async def put( self, *, @@ -387,6 +399,7 @@ async def put( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def sync_job_cancel( self, *, @@ -434,6 +447,7 @@ async def sync_job_cancel( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def sync_job_delete( self, *, @@ -478,6 +492,7 @@ async def sync_job_delete( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def sync_job_get( self, *, @@ -522,6 +537,7 @@ async def sync_job_get( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) async def sync_job_list( self, *, @@ -601,6 +617,7 @@ async def sync_job_list( @_rewrite_parameters( body_fields=("id", "job_type", "trigger_method"), ) + @_stability_warning(Stability.BETA) async def sync_job_post( self, *, @@ -660,6 +677,7 @@ async def sync_job_post( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def update_active_filtering( self, *, @@ -703,6 +721,7 @@ async def update_active_filtering( @_rewrite_parameters( body_fields=("api_key_id", "api_key_secret_id"), ) + @_stability_warning(Stability.BETA) async def update_api_key_id( self, *, @@ -761,6 +780,7 @@ async def update_api_key_id( @_rewrite_parameters( body_fields=("configuration", "values"), ) + @_stability_warning(Stability.BETA) async def update_configuration( self, *, @@ -816,6 +836,7 @@ async def update_configuration( @_rewrite_parameters( body_fields=("error",), ) + @_stability_warning(Stability.EXPERIMENTAL) async def update_error( self, *, @@ -871,6 +892,7 @@ async def update_error( @_rewrite_parameters( body_fields=("advanced_snippet", "filtering", "rules"), ) + @_stability_warning(Stability.BETA) async def update_filtering( self, *, @@ -932,6 +954,7 @@ async def update_filtering( @_rewrite_parameters( body_fields=("validation",), ) + @_stability_warning(Stability.EXPERIMENTAL) async def update_filtering_validation( self, *, @@ -985,6 +1008,7 @@ async def update_filtering_validation( @_rewrite_parameters( body_fields=("index_name",), ) + @_stability_warning(Stability.BETA) async def update_index_name( self, *, @@ -1038,6 +1062,7 @@ async def update_index_name( @_rewrite_parameters( body_fields=("description", "name"), ) + @_stability_warning(Stability.BETA) async def update_name( self, *, @@ -1092,6 +1117,7 @@ async def update_name( @_rewrite_parameters( body_fields=("is_native",), ) + @_stability_warning(Stability.BETA) async def update_native( self, *, @@ -1144,6 +1170,7 @@ async def update_native( @_rewrite_parameters( body_fields=("pipeline",), ) + @_stability_warning(Stability.BETA) async def update_pipeline( self, *, @@ -1197,6 +1224,7 @@ async def update_pipeline( @_rewrite_parameters( body_fields=("scheduling",), ) + @_stability_warning(Stability.BETA) async def update_scheduling( self, *, @@ -1249,6 +1277,7 @@ async def update_scheduling( @_rewrite_parameters( body_fields=("service_type",), ) + @_stability_warning(Stability.BETA) async def update_service_type( self, *, @@ -1301,6 +1330,7 @@ async def update_service_type( @_rewrite_parameters( body_fields=("status",), ) + @_stability_warning(Stability.EXPERIMENTAL) async def update_status( self, *, diff --git a/elasticsearch_serverless/_async/client/inference.py b/elasticsearch_serverless/_async/client/inference.py index b7fd1b7..29906c0 100644 --- a/elasticsearch_serverless/_async/client/inference.py +++ b/elasticsearch_serverless/_async/client/inference.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class InferenceClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def delete( self, *, @@ -93,6 +100,7 @@ async def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def get( self, *, @@ -151,6 +159,7 @@ async def get( @_rewrite_parameters( body_fields=("input", "query", "task_settings"), ) + @_stability_warning(Stability.EXPERIMENTAL) async def inference( self, *, @@ -237,6 +246,7 @@ async def inference( @_rewrite_parameters( body_name="inference_config", ) + @_stability_warning(Stability.EXPERIMENTAL) async def put( self, *, diff --git a/elasticsearch_serverless/_async/client/ml.py b/elasticsearch_serverless/_async/client/ml.py index cc36142..51af55c 100644 --- a/elasticsearch_serverless/_async/client/ml.py +++ b/elasticsearch_serverless/_async/client/ml.py @@ -20,7 +20,13 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class MlClient(NamespacedClient): @@ -3919,6 +3925,7 @@ async def update_job( @_rewrite_parameters( body_fields=("number_of_allocations",), ) + @_stability_warning(Stability.BETA) async def update_trained_model_deployment( self, *, diff --git a/elasticsearch_serverless/_async/client/search_application.py b/elasticsearch_serverless/_async/client/search_application.py index f35714b..d5a3d15 100644 --- a/elasticsearch_serverless/_async/client/search_application.py +++ b/elasticsearch_serverless/_async/client/search_application.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class SearchApplicationClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def delete( self, *, @@ -67,6 +74,7 @@ async def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def delete_behavioral_analytics( self, *, @@ -108,6 +116,7 @@ async def delete_behavioral_analytics( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) async def get( self, *, @@ -148,6 +157,7 @@ async def get( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def get_behavioral_analytics( self, *, @@ -193,6 +203,7 @@ async def get_behavioral_analytics( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) async def list( self, *, @@ -243,6 +254,7 @@ async def list( @_rewrite_parameters( body_name="search_application", ) + @_stability_warning(Stability.BETA) async def put( self, *, @@ -299,6 +311,7 @@ async def put( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def put_behavioral_analytics( self, *, @@ -342,6 +355,7 @@ async def put_behavioral_analytics( body_fields=("params",), ignore_deprecated_options={"params"}, ) + @_stability_warning(Stability.BETA) async def search( self, *, diff --git a/elasticsearch_serverless/_async/client/tasks.py b/elasticsearch_serverless/_async/client/tasks.py index cb85eec..c3e9843 100644 --- a/elasticsearch_serverless/_async/client/tasks.py +++ b/elasticsearch_serverless/_async/client/tasks.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class TasksClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) async def get( self, *, diff --git a/elasticsearch_serverless/_sync/client/__init__.py b/elasticsearch_serverless/_sync/client/__init__.py index 46d8d1d..6790b51 100644 --- a/elasticsearch_serverless/_sync/client/__init__.py +++ b/elasticsearch_serverless/_sync/client/__init__.py @@ -59,8 +59,10 @@ _TYPE_HOST, CLIENT_META_SERVICE, SKIP_IN_PATH, + Stability, _quote, _rewrite_parameters, + _stability_warning, client_node_config, is_requests_http_auth, is_requests_node_class, @@ -3068,6 +3070,7 @@ def render_search_template( @_rewrite_parameters( body_fields=("context", "context_setup", "script"), ) + @_stability_warning(Stability.EXPERIMENTAL) def scripts_painless_execute( self, *, diff --git a/elasticsearch_serverless/_sync/client/connector.py b/elasticsearch_serverless/_sync/client/connector.py index 1ade6ac..1f30c53 100644 --- a/elasticsearch_serverless/_sync/client/connector.py +++ b/elasticsearch_serverless/_sync/client/connector.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class ConnectorClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def check_in( self, *, @@ -67,6 +74,7 @@ def check_in( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def delete( self, *, @@ -115,6 +123,7 @@ def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def get( self, *, @@ -157,6 +166,7 @@ def get( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) def list( self, *, @@ -230,6 +240,7 @@ def list( "service_type", ), ) + @_stability_warning(Stability.BETA) def post( self, *, @@ -311,6 +322,7 @@ def post( "service_type", ), ) + @_stability_warning(Stability.BETA) def put( self, *, @@ -387,6 +399,7 @@ def put( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def sync_job_cancel( self, *, @@ -434,6 +447,7 @@ def sync_job_cancel( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def sync_job_delete( self, *, @@ -478,6 +492,7 @@ def sync_job_delete( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def sync_job_get( self, *, @@ -522,6 +537,7 @@ def sync_job_get( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) def sync_job_list( self, *, @@ -601,6 +617,7 @@ def sync_job_list( @_rewrite_parameters( body_fields=("id", "job_type", "trigger_method"), ) + @_stability_warning(Stability.BETA) def sync_job_post( self, *, @@ -660,6 +677,7 @@ def sync_job_post( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def update_active_filtering( self, *, @@ -703,6 +721,7 @@ def update_active_filtering( @_rewrite_parameters( body_fields=("api_key_id", "api_key_secret_id"), ) + @_stability_warning(Stability.BETA) def update_api_key_id( self, *, @@ -761,6 +780,7 @@ def update_api_key_id( @_rewrite_parameters( body_fields=("configuration", "values"), ) + @_stability_warning(Stability.BETA) def update_configuration( self, *, @@ -816,6 +836,7 @@ def update_configuration( @_rewrite_parameters( body_fields=("error",), ) + @_stability_warning(Stability.EXPERIMENTAL) def update_error( self, *, @@ -871,6 +892,7 @@ def update_error( @_rewrite_parameters( body_fields=("advanced_snippet", "filtering", "rules"), ) + @_stability_warning(Stability.BETA) def update_filtering( self, *, @@ -932,6 +954,7 @@ def update_filtering( @_rewrite_parameters( body_fields=("validation",), ) + @_stability_warning(Stability.EXPERIMENTAL) def update_filtering_validation( self, *, @@ -985,6 +1008,7 @@ def update_filtering_validation( @_rewrite_parameters( body_fields=("index_name",), ) + @_stability_warning(Stability.BETA) def update_index_name( self, *, @@ -1038,6 +1062,7 @@ def update_index_name( @_rewrite_parameters( body_fields=("description", "name"), ) + @_stability_warning(Stability.BETA) def update_name( self, *, @@ -1092,6 +1117,7 @@ def update_name( @_rewrite_parameters( body_fields=("is_native",), ) + @_stability_warning(Stability.BETA) def update_native( self, *, @@ -1144,6 +1170,7 @@ def update_native( @_rewrite_parameters( body_fields=("pipeline",), ) + @_stability_warning(Stability.BETA) def update_pipeline( self, *, @@ -1197,6 +1224,7 @@ def update_pipeline( @_rewrite_parameters( body_fields=("scheduling",), ) + @_stability_warning(Stability.BETA) def update_scheduling( self, *, @@ -1249,6 +1277,7 @@ def update_scheduling( @_rewrite_parameters( body_fields=("service_type",), ) + @_stability_warning(Stability.BETA) def update_service_type( self, *, @@ -1301,6 +1330,7 @@ def update_service_type( @_rewrite_parameters( body_fields=("status",), ) + @_stability_warning(Stability.EXPERIMENTAL) def update_status( self, *, diff --git a/elasticsearch_serverless/_sync/client/inference.py b/elasticsearch_serverless/_sync/client/inference.py index 2fc2a8d..780db0a 100644 --- a/elasticsearch_serverless/_sync/client/inference.py +++ b/elasticsearch_serverless/_sync/client/inference.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class InferenceClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def delete( self, *, @@ -93,6 +100,7 @@ def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def get( self, *, @@ -151,6 +159,7 @@ def get( @_rewrite_parameters( body_fields=("input", "query", "task_settings"), ) + @_stability_warning(Stability.EXPERIMENTAL) def inference( self, *, @@ -237,6 +246,7 @@ def inference( @_rewrite_parameters( body_name="inference_config", ) + @_stability_warning(Stability.EXPERIMENTAL) def put( self, *, diff --git a/elasticsearch_serverless/_sync/client/ml.py b/elasticsearch_serverless/_sync/client/ml.py index 7db7748..ff876ca 100644 --- a/elasticsearch_serverless/_sync/client/ml.py +++ b/elasticsearch_serverless/_sync/client/ml.py @@ -20,7 +20,13 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class MlClient(NamespacedClient): @@ -3919,6 +3925,7 @@ def update_job( @_rewrite_parameters( body_fields=("number_of_allocations",), ) + @_stability_warning(Stability.BETA) def update_trained_model_deployment( self, *, diff --git a/elasticsearch_serverless/_sync/client/search_application.py b/elasticsearch_serverless/_sync/client/search_application.py index 69a186e..d13093f 100644 --- a/elasticsearch_serverless/_sync/client/search_application.py +++ b/elasticsearch_serverless/_sync/client/search_application.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class SearchApplicationClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.BETA) def delete( self, *, @@ -67,6 +74,7 @@ def delete( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def delete_behavioral_analytics( self, *, @@ -108,6 +116,7 @@ def delete_behavioral_analytics( ) @_rewrite_parameters() + @_stability_warning(Stability.BETA) def get( self, *, @@ -148,6 +157,7 @@ def get( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def get_behavioral_analytics( self, *, @@ -193,6 +203,7 @@ def get_behavioral_analytics( @_rewrite_parameters( parameter_aliases={"from": "from_"}, ) + @_stability_warning(Stability.BETA) def list( self, *, @@ -243,6 +254,7 @@ def list( @_rewrite_parameters( body_name="search_application", ) + @_stability_warning(Stability.BETA) def put( self, *, @@ -299,6 +311,7 @@ def put( ) @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def put_behavioral_analytics( self, *, @@ -342,6 +355,7 @@ def put_behavioral_analytics( body_fields=("params",), ignore_deprecated_options={"params"}, ) + @_stability_warning(Stability.BETA) def search( self, *, diff --git a/elasticsearch_serverless/_sync/client/tasks.py b/elasticsearch_serverless/_sync/client/tasks.py index a35acf7..6f149b4 100644 --- a/elasticsearch_serverless/_sync/client/tasks.py +++ b/elasticsearch_serverless/_sync/client/tasks.py @@ -20,12 +20,19 @@ from elastic_transport import ObjectApiResponse from ._base import NamespacedClient -from .utils import SKIP_IN_PATH, _quote, _rewrite_parameters +from .utils import ( + SKIP_IN_PATH, + Stability, + _quote, + _rewrite_parameters, + _stability_warning, +) class TasksClient(NamespacedClient): @_rewrite_parameters() + @_stability_warning(Stability.EXPERIMENTAL) def get( self, *, From c59b8c0a517e14ab877a831d7f92a514622c5288 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Wed, 6 Nov 2024 13:56:52 +0400 Subject: [PATCH 3/4] Fix test_utils imports --- test_elasticsearch_serverless/test_client/test_utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test_elasticsearch_serverless/test_client/test_utils.py b/test_elasticsearch_serverless/test_client/test_utils.py index 90f8b10..8b011e0 100644 --- a/test_elasticsearch_serverless/test_client/test_utils.py +++ b/test_elasticsearch_serverless/test_client/test_utils.py @@ -18,8 +18,12 @@ import warnings -from elasticsearch._sync.client.utils import Stability, _quote, _stability_warning -from elasticsearch.exceptions import GeneralAvailabilityWarning +from elasticsearch_serverless._sync.client.utils import ( + Stability, + _quote, + _stability_warning, +) +from elasticsearch_serverless.exceptions import GeneralAvailabilityWarning def test_handles_ascii(): From e79e888c4d7e83ce26258be028640804756a31b5 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Thu, 7 Nov 2024 17:38:07 +0400 Subject: [PATCH 4/4] Port fixes from elasticsearch-py pull request --- .../_sync/client/utils.py | 7 --- .../test_client/test_utils.py | 45 +++++-------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/elasticsearch_serverless/_sync/client/utils.py b/elasticsearch_serverless/_sync/client/utils.py index 536f99d..34b9336 100644 --- a/elasticsearch_serverless/_sync/client/utils.py +++ b/elasticsearch_serverless/_sync/client/utils.py @@ -70,7 +70,6 @@ class Stability(Enum): STABLE = auto() BETA = auto() EXPERIMENTAL = auto() - DEPRECATED = auto() _TYPE_HOST = Union[str, Mapping[str, Union[str, int]], NodeConfig] @@ -454,12 +453,6 @@ def wrapped(*args: Any, **kwargs: Any) -> Any: category=GeneralAvailabilityWarning, stacklevel=warn_stacklevel(), ) - elif stability == Stability.DEPRECATED: - warnings.warn( - f"This API was deprecated in Elasticsearch {version}. {message}", - category=DeprecationWarning, - stacklevel=warn_stacklevel(), - ) return api(*args, **kwargs) diff --git a/test_elasticsearch_serverless/test_client/test_utils.py b/test_elasticsearch_serverless/test_client/test_utils.py index 8b011e0..180615e 100644 --- a/test_elasticsearch_serverless/test_client/test_utils.py +++ b/test_elasticsearch_serverless/test_client/test_utils.py @@ -18,6 +18,8 @@ import warnings +import pytest + from elasticsearch_serverless._sync.client.utils import ( Stability, _quote, @@ -62,14 +64,11 @@ def test_beta(self, recwarn): def func_beta(*args, **kwargs): pass - func_beta() - - assert len(recwarn) == 1 - user_warning = recwarn.pop(GeneralAvailabilityWarning) - assert user_warning.category == GeneralAvailabilityWarning - assert user_warning.message.args[0].startswith( - "This API is in beta and is subject to change." - ) + with pytest.warns( + GeneralAvailabilityWarning, + match="This API is in beta and is subject to change.", + ): + func_beta() def test_experimental(self, recwarn): @@ -77,28 +76,8 @@ def test_experimental(self, recwarn): def func_experimental(*args, **kwargs): pass - func_experimental() - - assert len(recwarn) == 1 - user_warning = recwarn.pop(GeneralAvailabilityWarning) - assert user_warning.category == GeneralAvailabilityWarning - assert user_warning.message.args[0].startswith( - "This API is in technical preview and may be changed or removed in a future release." - ) - - def test_deprecated(self, recwarn): - - @_stability_warning( - stability=Stability.DEPRECATED, version="8.4.0", message="Use bar instead." - ) - def func_deprecated(*args, **kwargs): - pass - - func_deprecated() - - assert len(recwarn) == 1 - user_warning = recwarn.pop(DeprecationWarning) - assert user_warning.category == DeprecationWarning - assert user_warning.message.args[0] == ( - "This API was deprecated in Elasticsearch 8.4.0. Use bar instead." - ) + with pytest.warns( + GeneralAvailabilityWarning, + match="This API is in technical preview and may be changed or removed in a future release.", + ): + func_experimental()