Skip to content

Commit 58bfab9

Browse files
committed
feat: deprecate datacenters resource
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.
1 parent b4a2597 commit 58bfab9

9 files changed

Lines changed: 127 additions & 46 deletions

File tree

‎hcloud/_client.py‎

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import time
4+
import warnings
45
from http import HTTPStatus
56
from random import uniform
67
from typing import Any, Protocol
@@ -181,11 +182,10 @@ def __init__(
181182
timeout=timeout,
182183
)
183184

184-
self.datacenters = DatacentersClient(self)
185-
"""DatacentersClient Instance
185+
with warnings.catch_warnings():
186+
warnings.filterwarnings("ignore", category=DeprecationWarning)
187+
self.datacenters = DatacentersClient(self)
186188

187-
:type: :class:`DatacentersClient <hcloud.datacenters.client.DatacentersClient>`
188-
"""
189189
self.locations = LocationsClient(self)
190190
"""LocationsClient Instance
191191
@@ -303,6 +303,28 @@ def request( # type: ignore[no-untyped-def]
303303
"""
304304
return self._client.request(method, url, **kwargs)
305305

306+
@property
307+
def datacenters(self) -> DatacentersClient:
308+
"""DatacentersClient Instance
309+
310+
.. deprecated:: 2.22.0
311+
The datacenters client is deprecated and will be removed after the 2026-10-01.
312+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
313+
314+
:type: :class:`DatacentersClient <hcloud.datacenters.client.DatacentersClient>`
315+
"""
316+
warnings.warn(
317+
"The datacenters client is deprecated and will be removed after the 2026-10-01. "
318+
"See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.",
319+
DeprecationWarning,
320+
stacklevel=2,
321+
)
322+
return self._datacenters
323+
324+
@datacenters.setter
325+
def datacenters(self, value: DatacentersClient) -> None:
326+
self._datacenters = value
327+
306328

307329
class ClientBase:
308330
def __init__(

‎hcloud/core/client.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ def __init__(
109109
"""
110110
self._client = client
111111
self.complete = complete
112-
self.data_model: Domain = self.model.from_dict(data)
112+
113+
with warnings.catch_warnings():
114+
warnings.filterwarnings("ignore", category=DeprecationWarning)
115+
self.data_model: Domain = self.model.from_dict(data)
113116

114117
def __getattr__(self, name: str): # type: ignore[no-untyped-def]
115118
"""Allow magical access to the properties of the model

‎hcloud/datacenters/client.py‎

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import warnings
34
from typing import Any, NamedTuple
45

56
from ..core import BoundModelBase, Meta, ResourceClientBase
@@ -13,52 +14,76 @@
1314
"DatacentersClient",
1415
]
1516

17+
with warnings.catch_warnings():
18+
warnings.filterwarnings("ignore", category=DeprecationWarning)
1619

17-
class BoundDatacenter(BoundModelBase[Datacenter], Datacenter):
18-
_client: DatacentersClient
19-
20-
model = Datacenter
21-
22-
def __init__(self, client: DatacentersClient, data: dict[str, Any]):
23-
location = data.get("location")
24-
if location is not None:
25-
data["location"] = BoundLocation(client._parent.locations, location)
20+
class BoundDatacenter(BoundModelBase[Datacenter], Datacenter):
21+
"""
22+
.. deprecated:: 2.22.0
23+
The bound datacenter class is deprecated and will be removed after the 2026-10-01.
24+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
25+
"""
2626

27-
server_types = data.get("server_types")
28-
if server_types is not None:
29-
available = [
30-
BoundServerType(
31-
client._parent.server_types, {"id": server_type}, complete=False
27+
_client: DatacentersClient
28+
29+
model = Datacenter
30+
31+
def __init__(self, client: DatacentersClient, data: dict[str, Any]):
32+
location = data.get("location")
33+
if location is not None:
34+
data["location"] = BoundLocation(client._parent.locations, location)
35+
36+
server_types = data.get("server_types")
37+
if server_types is not None:
38+
available = [
39+
BoundServerType(
40+
client._parent.server_types, {"id": server_type}, complete=False
41+
)
42+
for server_type in server_types["available"]
43+
]
44+
supported = [
45+
BoundServerType(
46+
client._parent.server_types, {"id": server_type}, complete=False
47+
)
48+
for server_type in server_types["supported"]
49+
]
50+
available_for_migration = [
51+
BoundServerType(
52+
client._parent.server_types, {"id": server_type}, complete=False
53+
)
54+
for server_type in server_types["available_for_migration"]
55+
]
56+
data["server_types"] = DatacenterServerTypes(
57+
available=available,
58+
supported=supported,
59+
available_for_migration=available_for_migration,
3260
)
33-
for server_type in server_types["available"]
34-
]
35-
supported = [
36-
BoundServerType(
37-
client._parent.server_types, {"id": server_type}, complete=False
38-
)
39-
for server_type in server_types["supported"]
40-
]
41-
available_for_migration = [
42-
BoundServerType(
43-
client._parent.server_types, {"id": server_type}, complete=False
44-
)
45-
for server_type in server_types["available_for_migration"]
46-
]
47-
data["server_types"] = DatacenterServerTypes(
48-
available=available,
49-
supported=supported,
50-
available_for_migration=available_for_migration,
51-
)
5261

53-
super().__init__(client, data)
62+
super().__init__(client, data)
5463

5564

5665
class DatacentersPageResult(NamedTuple):
66+
"""
67+
.. deprecated:: 2.22.0
68+
The datacenters page result class is deprecated and will be removed after the 2026-10-01.
69+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
70+
"""
71+
5772
datacenters: list[BoundDatacenter]
5873
meta: Meta
5974

6075

76+
@warnings.deprecated(
77+
"The datacenters client class is deprecated and will be removed after the 2026-10-01. "
78+
"See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.",
79+
)
6180
class DatacentersClient(ResourceClientBase):
81+
"""
82+
.. deprecated:: 2.22.0
83+
The datacenters client class is deprecated and will be removed after the 2026-10-01.
84+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
85+
"""
86+
6287
_base_url = "/datacenters"
6388

6489
def get_by_id(self, id: int) -> BoundDatacenter:

‎hcloud/datacenters/domain.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@
1515
]
1616

1717

18+
@warnings.deprecated(
19+
"The datacenter domain class is deprecated and will be removed after the 2026-10-01. "
20+
"See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.",
21+
)
1822
class Datacenter(BaseDomain, DomainIdentityMixin):
1923
"""Datacenter Domain
2024
25+
.. deprecated:: 2.22.0
26+
The datacenters domain class is deprecated and will be removed after the 2026-10-01.
27+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
28+
2129
:param id: int ID of Datacenter
2230
:param name: str Name of Datacenter
2331
:param description: str Description of Datacenter
@@ -69,6 +77,10 @@ def server_types(self, value: DatacenterServerTypes | None) -> None:
6977
class DatacenterServerTypes(BaseDomain):
7078
"""DatacenterServerTypes Domain
7179
80+
.. deprecated:: 2.22.0
81+
The datacenters domain class is deprecated and will be removed after the 2026-10-01.
82+
See https://docs.hetzner.cloud/changelog#2026-06-02-datacenters-deprecated.
83+
7284
:param available: List[:class:`BoundServerTypes <hcloud.server_types.client.BoundServerTypes>`]
7385
All available server types for this datacenter
7486
:param supported: List[:class:`BoundServerTypes <hcloud.server_types.client.BoundServerTypes>`]

‎hcloud/primary_ips/client.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def __init__(
4444

4545
raw = data.get("datacenter", {})
4646
if raw:
47-
data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw)
47+
with warnings.catch_warnings():
48+
warnings.filterwarnings("ignore", category=DeprecationWarning)
49+
data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw)
4850

4951
raw = data.get("location", {})
5052
if raw:

‎hcloud/servers/client.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def __init__(
7777
):
7878
raw = data.get("datacenter")
7979
if raw:
80-
data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw)
80+
with warnings.catch_warnings():
81+
warnings.filterwarnings("ignore", category=DeprecationWarning)
82+
data["datacenter"] = BoundDatacenter(client._parent.datacenters, raw)
8183

8284
raw = data.get("location")
8385
if raw:

‎tests/unit/actions/test_client.py‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import inspect
4+
import warnings
45
from unittest import mock
56

67
import pytest
@@ -47,10 +48,15 @@ def test_resources_with_actions(client: Client):
4748
"""
4849
Ensure that the list of resource clients above is up to date.
4950
"""
50-
members = inspect.getmembers(
51-
client,
52-
predicate=lambda p: isinstance(p, ResourceClientBase) and hasattr(p, "actions"),
53-
)
51+
with warnings.catch_warnings():
52+
warnings.filterwarnings("ignore", category=DeprecationWarning)
53+
54+
members = inspect.getmembers(
55+
client,
56+
predicate=lambda p: isinstance(p, ResourceClientBase)
57+
and hasattr(p, "actions"),
58+
)
59+
5460
for name, member in members:
5561
assert name in resources_with_actions
5662

‎tests/unit/datacenters/test_client.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import warnings
34
from unittest import mock # noqa: F401
45

56
import pytest # noqa: F401
@@ -8,6 +9,8 @@
89
from hcloud.datacenters import BoundDatacenter, DatacentersClient, DatacenterServerTypes
910
from hcloud.locations import BoundLocation
1011

12+
warnings.filterwarnings("ignore", category=DeprecationWarning)
13+
1114

1215
class TestBoundDatacenter:
1316
def test_bound_datacenter_init(self, datacenter_response):
@@ -64,7 +67,9 @@ def test_bound_datacenter_init(self, datacenter_response):
6467
class TestDatacentersClient:
6568
@pytest.fixture()
6669
def datacenters_client(self, client: Client):
67-
return DatacentersClient(client)
70+
with warnings.catch_warnings():
71+
warnings.filterwarnings("ignore", category=DeprecationWarning)
72+
return DatacentersClient(client)
6873

6974
def test_get_by_id(
7075
self,

‎tests/unit/datacenters/test_domain.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from __future__ import annotations
22

3+
import warnings
4+
35
import pytest
46

57
from hcloud.datacenters import Datacenter, DatacenterServerTypes
68

9+
warnings.filterwarnings("ignore", category=DeprecationWarning)
10+
711

812
@pytest.mark.parametrize(
913
"value",

0 commit comments

Comments
 (0)