Skip to content

Commit 7786cf3

Browse files
committed
Add API warnings infrastructure
1 parent 94573cf commit 7786cf3

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

elasticsearch/_async/client/utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
_TYPE_HOSTS,
2121
CLIENT_META_SERVICE,
2222
SKIP_IN_PATH,
23+
Stability,
2324
_base64_auth_header,
2425
_quote,
2526
_quote_query,
2627
_rewrite_parameters,
28+
_stability_warning,
2729
client_node_configs,
2830
is_requests_http_auth,
2931
is_requests_node_class,
@@ -37,8 +39,10 @@
3739
"_quote_query",
3840
"_TYPE_HOSTS",
3941
"SKIP_IN_PATH",
42+
"Stability",
4043
"client_node_configs",
4144
"_rewrite_parameters",
45+
"_stability_warning",
4246
"is_requests_http_auth",
4347
"is_requests_node_class",
4448
]

elasticsearch/_sync/client/utils.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import urllib.parse
2121
import warnings
2222
from datetime import date, datetime
23+
from enum import Enum, auto
2324
from functools import wraps
2425
from typing import (
2526
TYPE_CHECKING,
@@ -55,6 +56,8 @@
5556
url_to_node_config,
5657
)
5758

59+
from elasticsearch.exceptions import GeneralAvailabilityWarning
60+
5861
from ..._version import __versionstr__
5962
from ...compat import to_bytes, to_str, warn_stacklevel
6063

@@ -70,6 +73,14 @@
7073
# Default User-Agent used by the client
7174
USER_AGENT = create_user_agent("elasticsearch-py", __versionstr__)
7275

76+
77+
class Stability(Enum):
78+
STABLE = auto()
79+
BETA = auto()
80+
EXPERIMENTAL = auto()
81+
DEPRECATED = auto()
82+
83+
7384
_TYPE_HOSTS = Union[
7485
str, Sequence[Union[str, Mapping[str, Union[str, int]], NodeConfig]]
7586
]
@@ -450,6 +461,43 @@ def wrapped(*args: Any, **kwargs: Any) -> Any:
450461
return wrapper
451462

452463

464+
def _stability_warning(
465+
stability: Stability,
466+
version: Optional[str] = None,
467+
message: Optional[str] = None,
468+
) -> Callable[[F], F]:
469+
def wrapper(api: F) -> F:
470+
@wraps(api)
471+
def wrapped(*args: Any, **kwargs: Any) -> Any:
472+
if stability == Stability.BETA:
473+
warnings.warn(
474+
"This API is in beta and is subject to change. "
475+
"The design and code is less mature than official GA features and is being provided as-is with no warranties. "
476+
"Beta features are not subject to the support SLA of official GA features.",
477+
category=GeneralAvailabilityWarning,
478+
stacklevel=warn_stacklevel(),
479+
)
480+
elif stability == Stability.EXPERIMENTAL:
481+
warnings.warn(
482+
"This API is in technical preview and may be changed or removed in a future release. "
483+
"Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.",
484+
category=GeneralAvailabilityWarning,
485+
stacklevel=warn_stacklevel(),
486+
)
487+
elif stability == Stability.DEPRECATED:
488+
warnings.warn(
489+
f"This API was deprecated in Elasticsearch {version}. {message}",
490+
category=DeprecationWarning,
491+
stacklevel=warn_stacklevel(),
492+
)
493+
494+
return api(*args, **kwargs)
495+
496+
return wrapped # type: ignore[return-value]
497+
498+
return wrapper
499+
500+
453501
def is_requests_http_auth(http_auth: Any) -> bool:
454502
"""Detect if an http_auth value is a custom Requests auth object"""
455503
try:

elasticsearch/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ class ElasticsearchWarning(TransportWarning):
115115
"""
116116

117117

118+
class GeneralAvailabilityWarning(TransportWarning):
119+
"""Warning that is raised when a feature is not yet GA."""
120+
121+
118122
# Aliases for backwards compatibility
119123
ElasticsearchDeprecationWarning = ElasticsearchWarning
120124
RequestError = BadRequestError

test_elasticsearch/test_client/test_utils.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
# under the License.
1717

1818

19-
from elasticsearch._sync.client.utils import _quote
19+
import warnings
20+
21+
from elasticsearch._sync.client.utils import Stability, _quote, _stability_warning
22+
from elasticsearch.exceptions import GeneralAvailabilityWarning
2023

2124

2225
def test_handles_ascii():
@@ -36,3 +39,62 @@ def test_handles_unicode():
3639
def test_handles_unicode2():
3740
string = "中*文,"
3841
assert "%E4%B8%AD*%E6%96%87," == _quote(string)
42+
43+
44+
class TestStabilityWarning:
45+
def test_default(self):
46+
47+
@_stability_warning(stability=Stability.STABLE)
48+
def func_default(*args, **kwargs):
49+
pass
50+
51+
with warnings.catch_warnings():
52+
warnings.simplefilter("error")
53+
func_default()
54+
55+
def test_beta(self, recwarn):
56+
57+
@_stability_warning(stability=Stability.BETA)
58+
def func_beta(*args, **kwargs):
59+
pass
60+
61+
func_beta()
62+
63+
assert len(recwarn) == 1
64+
user_warning = recwarn.pop(GeneralAvailabilityWarning)
65+
assert user_warning.category == GeneralAvailabilityWarning
66+
assert user_warning.message.args[0].startswith(
67+
"This API is in beta and is subject to change."
68+
)
69+
70+
def test_experimental(self, recwarn):
71+
72+
@_stability_warning(stability=Stability.EXPERIMENTAL)
73+
def func_experimental(*args, **kwargs):
74+
pass
75+
76+
func_experimental()
77+
78+
assert len(recwarn) == 1
79+
user_warning = recwarn.pop(GeneralAvailabilityWarning)
80+
assert user_warning.category == GeneralAvailabilityWarning
81+
assert user_warning.message.args[0].startswith(
82+
"This API is in technical preview and may be changed or removed in a future release."
83+
)
84+
85+
def test_deprecated(self, recwarn):
86+
87+
@_stability_warning(
88+
stability=Stability.DEPRECATED, version="8.4.0", message="Use bar instead."
89+
)
90+
def func_deprecated(*args, **kwargs):
91+
pass
92+
93+
func_deprecated()
94+
95+
assert len(recwarn) == 1
96+
user_warning = recwarn.pop(DeprecationWarning)
97+
assert user_warning.category == DeprecationWarning
98+
assert user_warning.message.args[0] == (
99+
"This API was deprecated in Elasticsearch 8.4.0. Use bar instead."
100+
)

0 commit comments

Comments
 (0)