From 822a20c451c944f6f1ff35ae8020f2a4400c867a Mon Sep 17 00:00:00 2001 From: jo Date: Thu, 4 Jun 2026 11:12:24 +0200 Subject: [PATCH] feat: deprecate datacenters The API endpoints `GET /v1/datacenters` and `GET /v1/datacenters/{id}` are now deprecated and will be removed after 1 Oct. 2026. After this date, requests to these endpoints will return `HTTP 410 Gone`. See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. --- hcloud/_client.py | 30 +++++++++++++++++++++++---- hcloud/datacenters/client.py | 23 ++++++++++++++++++++ hcloud/datacenters/domain.py | 8 +++++++ hcloud/primary_ips/client.py | 4 +++- hcloud/servers/client.py | 4 +++- tests/unit/actions/test_client.py | 14 +++++++++---- tests/unit/datacenters/test_client.py | 7 ++++++- tests/unit/datacenters/test_domain.py | 4 ++++ 8 files changed, 83 insertions(+), 11 deletions(-) diff --git a/hcloud/_client.py b/hcloud/_client.py index 20f26c9d..9d37ef08 100644 --- a/hcloud/_client.py +++ b/hcloud/_client.py @@ -1,6 +1,7 @@ from __future__ import annotations import time +import warnings from http import HTTPStatus from random import uniform from typing import Any, Protocol @@ -180,11 +181,10 @@ def __init__( timeout=timeout, ) - self.datacenters = DatacentersClient(self) - """DatacentersClient Instance + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + self.datacenters = DatacentersClient(self) - :type: :class:`DatacentersClient ` - """ self.locations = LocationsClient(self) """LocationsClient Instance @@ -302,6 +302,28 @@ def request( # type: ignore[no-untyped-def] """ return self._client.request(method, url, **kwargs) + @property + def datacenters(self) -> bool | None: + """DatacentersClient Instance + + .. deprecated:: 2.21.0 + The datacenters client is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + + :type: :class:`DatacentersClient ` + """ + warnings.warn( + "The datacenters client is deprecated and will be removed after the 2026-10-01. " + "See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.", + DeprecationWarning, + stacklevel=2, + ) + return self._datacenters + + @datacenters.setter + def datacenters(self, value: DatacentersClient) -> None: + self._datacenters = value + class ClientBase: def __init__( diff --git a/hcloud/datacenters/client.py b/hcloud/datacenters/client.py index 5d7fe964..27ca5484 100644 --- a/hcloud/datacenters/client.py +++ b/hcloud/datacenters/client.py @@ -1,5 +1,6 @@ from __future__ import annotations +import warnings from typing import Any, NamedTuple from ..core import BoundModelBase, Meta, ResourceClientBase @@ -15,6 +16,12 @@ class BoundDatacenter(BoundModelBase[Datacenter], Datacenter): + """ + .. deprecated:: 2.21.0 + The bound datacenter class is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + """ + _client: DatacentersClient model = Datacenter @@ -54,11 +61,27 @@ def __init__(self, client: DatacentersClient, data: dict[str, Any]): class DatacentersPageResult(NamedTuple): + """ + .. deprecated:: 2.21.0 + The datacenters page result class is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + """ + datacenters: list[BoundDatacenter] meta: Meta +@warnings.deprecated( + "The datacenters client class is deprecated and will be removed after the 2026-10-01. " + "See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.", +) class DatacentersClient(ResourceClientBase): + """ + .. deprecated:: 2.21.0 + The datacenters client class is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + """ + _base_url = "/datacenters" def get_by_id(self, id: int) -> BoundDatacenter: diff --git a/hcloud/datacenters/domain.py b/hcloud/datacenters/domain.py index bdc7a27b..afa8c151 100644 --- a/hcloud/datacenters/domain.py +++ b/hcloud/datacenters/domain.py @@ -18,6 +18,10 @@ class Datacenter(BaseDomain, DomainIdentityMixin): """Datacenter Domain + .. deprecated:: 2.21.0 + The datacenters domain class is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + :param id: int ID of Datacenter :param name: str Name of Datacenter :param description: str Description of Datacenter @@ -69,6 +73,10 @@ def server_types(self, value: DatacenterServerTypes | None) -> None: class DatacenterServerTypes(BaseDomain): """DatacenterServerTypes Domain + .. deprecated:: 2.21.0 + The datacenters domain class is deprecated and will be removed after the 2026-10-01. + See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated. + :param available: List[:class:`BoundServerTypes `] All available server types for this datacenter :param supported: List[:class:`BoundServerTypes `] diff --git a/hcloud/primary_ips/client.py b/hcloud/primary_ips/client.py index 875032ae..4a0c490d 100644 --- a/hcloud/primary_ips/client.py +++ b/hcloud/primary_ips/client.py @@ -44,7 +44,9 @@ def __init__( raw = data.get("datacenter", {}) if raw: - data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw) raw = data.get("location", {}) if raw: diff --git a/hcloud/servers/client.py b/hcloud/servers/client.py index 1128f420..6e406f2c 100644 --- a/hcloud/servers/client.py +++ b/hcloud/servers/client.py @@ -77,7 +77,9 @@ def __init__( ): raw = data.get("datacenter") if raw: - data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw) raw = data.get("location") if raw: diff --git a/tests/unit/actions/test_client.py b/tests/unit/actions/test_client.py index 2b9d8113..26930de4 100644 --- a/tests/unit/actions/test_client.py +++ b/tests/unit/actions/test_client.py @@ -1,6 +1,7 @@ from __future__ import annotations import inspect +import warnings from unittest import mock import pytest @@ -47,10 +48,15 @@ def test_resources_with_actions(client: Client): """ Ensure that the list of resource clients above is up to date. """ - members = inspect.getmembers( - client, - predicate=lambda p: isinstance(p, ResourceClientBase) and hasattr(p, "actions"), - ) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + + members = inspect.getmembers( + client, + predicate=lambda p: isinstance(p, ResourceClientBase) + and hasattr(p, "actions"), + ) + for name, member in members: assert name in resources_with_actions diff --git a/tests/unit/datacenters/test_client.py b/tests/unit/datacenters/test_client.py index ef1aa840..59d0d25b 100644 --- a/tests/unit/datacenters/test_client.py +++ b/tests/unit/datacenters/test_client.py @@ -1,5 +1,6 @@ from __future__ import annotations +import warnings from unittest import mock # noqa: F401 import pytest # noqa: F401 @@ -8,6 +9,8 @@ from hcloud.datacenters import BoundDatacenter, DatacentersClient, DatacenterServerTypes from hcloud.locations import BoundLocation +warnings.filterwarnings("ignore", category=DeprecationWarning) + class TestBoundDatacenter: def test_bound_datacenter_init(self, datacenter_response): @@ -64,7 +67,9 @@ def test_bound_datacenter_init(self, datacenter_response): class TestDatacentersClient: @pytest.fixture() def datacenters_client(self, client: Client): - return DatacentersClient(client) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + return DatacentersClient(client) def test_get_by_id( self, diff --git a/tests/unit/datacenters/test_domain.py b/tests/unit/datacenters/test_domain.py index 58666bf6..fbf2b156 100644 --- a/tests/unit/datacenters/test_domain.py +++ b/tests/unit/datacenters/test_domain.py @@ -1,9 +1,13 @@ from __future__ import annotations +import warnings + import pytest from hcloud.datacenters import Datacenter, DatacenterServerTypes +warnings.filterwarnings("ignore", category=DeprecationWarning) + @pytest.mark.parametrize( "value",