Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions hcloud/images/domain.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from __future__ import annotations

from typing import TYPE_CHECKING, TypedDict
import warnings
from datetime import datetime
from typing import TYPE_CHECKING, Any, TypedDict

from ..core import BaseDomain, DomainIdentityMixin
from ..deprecation import DeprecationInfo

if TYPE_CHECKING:
from ..actions import BoundAction
Expand Down Expand Up @@ -52,8 +55,10 @@ class Image(BaseDomain, DomainIdentityMixin):
Protection configuration for the image
:param deprecated: datetime, None
Point in time when the image is considered to be deprecated (in ISO-8601 format)
:param deprecation:
Describes wether the resources is deprecated.
:param labels: Dict
User-defined labels (key-value pairs)
User-defined labels (key-value pairs)
"""

__api_properties__ = (
Expand All @@ -73,11 +78,11 @@ class Image(BaseDomain, DomainIdentityMixin):
"protection",
"labels",
"created",
"deprecated",
"deprecation",
)
__slots__ = __api_properties__

# pylint: disable=too-many-locals
# pylint: disable=too-many-locals,unused-argument
def __init__(
self,
id: int | None = None,
Expand All @@ -87,7 +92,7 @@ def __init__(
description: str | None = None,
image_size: int | None = None,
disk_size: int | None = None,
deprecated: str | None = None,
deprecated: str | None = None, # Preserved for backward compatibility
bound_to: Server | BoundServer | None = None,
os_flavor: str | None = None,
os_version: str | None = None,
Expand All @@ -97,6 +102,7 @@ def __init__(
protection: ImageProtection | None = None,
labels: dict[str, str] | None = None,
status: str | None = None,
deprecation: dict[str, Any] | None = None,
):
self.id = id
self.name = name
Expand All @@ -105,7 +111,6 @@ def __init__(
self.description = description
self.image_size = image_size
self.disk_size = disk_size
self.deprecated = self._parse_datetime(deprecated)
self.bound_to = bound_to
self.os_flavor = os_flavor
self.os_version = os_version
Expand All @@ -115,6 +120,27 @@ def __init__(
self.protection = protection
self.labels = labels
self.status = status
self.deprecation = (
None if deprecation is None else DeprecationInfo.from_dict(deprecation)
)

@property
def deprecated(self) -> datetime | None:
"""
.. deprecated:: 2.24.0
The 'deprecated' property is deprecated. Please use to the '.deprecation' property instead.

See https://docs.hetzner.cloud/changelog#2026-09-08-removing-the-deprecated-field.
"""
warnings.warn(
"The 'deprecated' property is deprecated. Please use to the '.deprecation' property instead. "
"See https://docs.hetzner.cloud/changelog#2026-09-08-removing-the-deprecated-field.",
DeprecationWarning,
stacklevel=2,
)
if self.deprecation is None:
return None
return self.deprecation.announced


class ImageProtection(TypedDict):
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/images/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ def image1():
"created": "2021-08-16T11:12:01Z",
"created_from": None,
"deleted": None,
"deprecated": "2026-08-31T06:21:44Z",
"deprecation": {
"announced": "2026-08-31T06:21:44Z",
"unavailable_after": "2026-12-01T00:00:00Z",
},
"description": "Debian 11",
"disk_size": 5,
"image_size": None,
Expand Down Expand Up @@ -42,7 +45,7 @@ def image2():
"name": "server1",
},
"deleted": None,
"deprecated": None,
"deprecation": None,
"description": "snapshot 2026-09-08T13:44:08Z",
"disk_size": 80,
"image_size": 0.7237785009765625,
Expand Down
9 changes: 7 additions & 2 deletions tests/unit/images/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ def test_init(self, image1, image2):
assert o.rapid_deploy is True
assert o.labels == {}
assert o.protection == {"delete": False}
assert o.deprecated == isoparse("2026-08-31T06:21:44Z")
with pytest.deprecated_call():
assert o.deprecated == isoparse("2026-08-31T06:21:44Z")
assert o.deprecation.announced == isoparse("2026-08-31T06:21:44Z")
assert o.deprecation.unavailable_after == isoparse("2026-12-01T00:00:00Z")

o = BoundImage(client=mock.MagicMock(), data=image2)

Expand All @@ -87,7 +90,9 @@ def test_init(self, image1, image2):
assert o.rapid_deploy is False
assert o.labels == {"key": "value"}
assert o.protection == {"delete": True}
assert o.deprecated is None
with pytest.deprecated_call():
assert o.deprecated is None
assert o.deprecation is None


class TestImagesClient:
Expand Down
Loading