diff --git a/cloudpub/models/aws.py b/cloudpub/models/aws.py index 2660593..d43ea4a 100644 --- a/cloudpub/models/aws.py +++ b/cloudpub/models/aws.py @@ -638,12 +638,26 @@ class PromoResourcesVideo(BaseResources): """The promotional video title.""" +@define +class PromotionalMedia(BaseResources): + """Represent a single element of promotional media from class :class:`~cloudpub.models.aws.PromotionalResources`.""" # noqa: E501 + + title: str = field(validator=instance_of(str), metadata={"alias": "Title"}) + """The title of the promotional media resource.""" + + description: Optional[str] = field( + validator=optional(instance_of(str)), metadata={"alias": "Description"} + ) + """The description of the promotional media resource.""" + + @define class PromotionalResources(AttrsJSONDecodeMixin): """Represent the "PromotionalResources" section of the :class:`~cloudpub.models.aws.ProductDetailResponse`.""" # noqa: E501 - promotional_media: Optional[str] = field( - validator=optional(instance_of(str)), + promotional_media: Optional[List[PromotionalMedia]] = field( + converter=lambda x: [PromotionalMedia.from_json(a) for a in x] if x else None, + on_setattr=NO_OP, metadata={"alias": "PromotionalMedia", "hide_unset": True}, ) """The product's promotional media.""" diff --git a/docs/cloud_providers/models/aws.rst.incl b/docs/cloud_providers/models/aws.rst.incl index a1415ba..c61c200 100644 --- a/docs/cloud_providers/models/aws.rst.incl +++ b/docs/cloud_providers/models/aws.rst.incl @@ -122,6 +122,9 @@ Resources internal elements .. autoclass:: cloudpub.models.aws.PromoResourcesVideo() :members: +.. autoclass:: cloudpub.models.aws.PromotionalMedia() + :members: + .. autoclass:: cloudpub.models.aws.PositiveTargeting() :members: diff --git a/tests/aws/test_models.py b/tests/aws/test_models.py index fb7cca8..6c538c7 100644 --- a/tests/aws/test_models.py +++ b/tests/aws/test_models.py @@ -1,5 +1,6 @@ import json import re +from copy import deepcopy from typing import Any, Dict import pytest @@ -16,6 +17,8 @@ ProductVersionsBase, ProductVersionsCloudFormationSource, ProductVersionsVirtualizationSource, + PromotionalMedia, + PromotionalResources, SecurityGroup, Version, VersionMapping, @@ -125,3 +128,64 @@ def test_describe_entity_response_parsed_details( def test_list_changeset_response_parsed(list_changeset_response: Dict[str, Any]) -> None: resp = ListChangeSetsResponse.from_json(list_changeset_response) assert len(resp.change_set_list) == 1 + + +@pytest.mark.parametrize( + "promotional_media", + [ + None, + [], + [ + { + 'Type': 'Image', + 'Url': 'https://foo.com/bar.png', + 'Title': 'Logo1', + 'Description': None, + } + ], + [ + { + 'Type': 'Image', + 'Url': 'https://foo.com/bar.png', + 'Title': 'Logo1', + # Description field intentionally omitted to test absence + } + ], + [ + { + 'Type': 'Image', + 'Url': 'https://foo.com/bar.png', + 'Title': 'Logo1', + 'Description': 'This is the logo1', + }, + { + 'Type': 'Video', + 'Url': 'https://foo.com/video.mp4', + 'Title': 'Video', + 'Description': 'This is the promotional video', + }, + ], + ], +) +def test_promotional_resources_promotional_media( + promotional_media, promotional_resource: Dict[str, Any] +) -> None: + resource = deepcopy(promotional_resource) + resource["PromotionalMedia"] = promotional_media + + obj = PromotionalResources.from_json(resource) + + assert obj + if not promotional_media: + assert obj.promotional_media is None + else: + assert obj.promotional_media == [PromotionalMedia.from_json(x) for x in promotional_media] + + +def test_promotional_resources_promotional_media_absent(promotional_resource: Dict[str, Any]): + resource = deepcopy(promotional_resource) + del resource["PromotionalMedia"] + + obj = PromotionalResources.from_json(resource) + assert obj + assert obj.promotional_media is None