Skip to content

Commit

Permalink
fix: Add validation for pricing preview items (#32)
Browse files Browse the repository at this point in the history
* fix: Add validation for pricing preview items

* fix: Fix invalid array type exception messages
  • Loading branch information
davidgrayston-paddle committed Sep 23, 2024
1 parent 0ad9443 commit 383300b
Show file tree
Hide file tree
Showing 22 changed files with 104 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@

class InvalidArgumentException(SdkException):
@staticmethod
def array_contains_invalid_types(field, expected_type, given):
message = f"Expected '{field}' to only contain only type/s '{expected_type}', '{given}' given"
def array_is_empty(field):
message = f"'{field}' cannot be empty"
return InvalidArgumentException(message)

@staticmethod
def array_contains_invalid_types(field, expected_type, given: list = None):
message = f"Expected '{field}' to only contain type '{expected_type}'"

if given is not None:
invalidTypeList = "', '".join(map(lambda x: type(x).__name__, given))
message += f" ('{invalidTypeList}' given)"

return InvalidArgumentException(message)
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def __init__(

# Validation
if any(not isinstance(aid, str) for aid in self.ids):
raise InvalidArgumentException('ids', 'string')
raise InvalidArgumentException.array_contains_invalid_types('ids', 'string')
if any(not isinstance(status, Status) for status in self.statuses):
raise InvalidArgumentException('statuses', Status.__name__)
raise InvalidArgumentException.array_contains_invalid_types('statuses', Status.__name__)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(
for field_name, field_value, field_type in [('currency_code', self.currency_code, CurrencyCode)]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
2 changes: 1 addition & 1 deletion paddle_billing/Resources/Prices/Operations/ListPrices.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
2 changes: 1 addition & 1 deletion paddle_billing/Resources/Prices/PricesClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get(self, price_id: str, includes = None) -> Price:

invalid_items = [item for item in includes if not isinstance(item, PriceIncludes)]
if invalid_items:
raise InvalidArgumentException('includes', PriceIncludes.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types('includes', PriceIncludes.__name__, invalid_items)

params = {'include': ','.join(include.value for include in includes)} if includes else {}
self.response = self.client.get_raw(f"/prices/{price_id}", params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from paddle_billing.Entities.PricingPreviews import PricePreviewItem
from paddle_billing.Entities.Shared import CurrencyCode, AddressPreview

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException


@dataclass
class PreviewPrice:
Expand All @@ -16,5 +18,15 @@ class PreviewPrice:
address: AddressPreview | None | Undefined = Undefined()
customer_ip_address: str | None | Undefined = Undefined()

def __post_init__(self):
# Validation
if len(self.items) == 0:
raise InvalidArgumentException.array_is_empty('items')

invalid_items = [item for item in self.items if not isinstance(item, PricePreviewItem)]
if invalid_items:
raise InvalidArgumentException.array_contains_invalid_types('items', PricePreviewItem.__name__, invalid_items)


def get_parameters(self) -> dict:
return asdict(self)
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
2 changes: 1 addition & 1 deletion paddle_billing/Resources/Products/ProductsClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get(self, product_id: str, includes = None) -> Product | Product:

invalid_items = [item for item in includes if not isinstance(item, ProductIncludes)]
if invalid_items:
raise InvalidArgumentException('includes', ProductIncludes.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types('includes', ProductIncludes.__name__, invalid_items)

params = {'include': ','.join(include.value for include in includes)} if includes else {}
self.response = self.client.get_raw(f"/products/{product_id}", params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __post_init__(self):
# Validation
if any(not isinstance(filter_item, ReportFilter) for filter_item in self.filters):
invalid_items = [filter_item for filter_item in self.filters if not isinstance(filter_item, ReportFilter)]
raise InvalidArgumentException('filters', 'ReportFilter', ', '.join(map(str, invalid_items)))
raise InvalidArgumentException.array_contains_invalid_types('filters', 'ReportFilter', ', '.join(map(str, invalid_items)))


def get_parameters(self) -> dict:
Expand Down
2 changes: 1 addition & 1 deletion paddle_billing/Resources/Reports/Operations/ListReports.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(
for field_name, field_value, field_type in [('statuses', self.statuses, ReportStatus)]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get(self, subscription_id: str, includes = None) -> Subscription:

invalid_items = [item for item in includes if not isinstance(item, SubscriptionIncludes)]
if invalid_items:
raise InvalidArgumentException('includes', SubscriptionIncludes.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types('includes', SubscriptionIncludes.__name__, invalid_items)

params = {'include': ','.join(include.value for include in includes)} if includes else {}
self.response = self.client.get_raw(f"/subscriptions/{subscription_id}", params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
]:
invalid_items = [item for item in field_value if not isinstance(item, field_type)]
if invalid_items:
raise InvalidArgumentException(field_name, field_type.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types(field_name, field_type.__name__, invalid_items)


def get_parameters(self) -> dict:
Expand Down
4 changes: 2 additions & 2 deletions paddle_billing/Resources/Transactions/TransactionsClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get(self, transaction_id: str, includes = None) -> Transaction:

invalid_items = [item for item in includes if not isinstance(item, TransactionIncludes)]
if invalid_items:
raise InvalidArgumentException('includes', TransactionIncludes.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types('includes', TransactionIncludes.__name__, invalid_items)

params = {'include': ','.join(include.value for include in includes)} if includes else {}
self.response = self.client.get_raw(f"/transactions/{transaction_id}", params)
Expand All @@ -61,7 +61,7 @@ def create(self, operation: CreateTransaction, includes = None) -> Transaction:

invalid_items = [item for item in includes if not isinstance(item, TransactionIncludes)]
if invalid_items:
raise InvalidArgumentException('includes', TransactionIncludes.__name__, invalid_items)
raise InvalidArgumentException.array_contains_invalid_types('includes', TransactionIncludes.__name__, invalid_items)

params = {'include': ','.join(include.value for include in includes)} if includes else {}
self.response = self.client.post_raw('/transactions', operation.get_parameters(), params)
Expand Down
12 changes: 12 additions & 0 deletions tests/Unit/Resources/Addresses/Operations/test_ListAddresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pytest import raises

from paddle_billing.Resources.Addresses.Operations import ListAddresses

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException

class TestListAddresses:
def test_raises_invalid_argument_exception_for_invalid_ids(self):
with raises(InvalidArgumentException) as exception_info:
ListAddresses(ids = [1])

assert str(exception_info.value) == "Expected 'ids' to only contain type 'string'"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from pytest import raises

from paddle_billing.Resources.Adjustments.Operations import ListAdjustments

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException

from datetime import datetime

class TestListAdjustments:
def test_raises_invalid_argument_exception_for_invalid_ids(self):
with raises(InvalidArgumentException) as exception_info:
ListAdjustments(ids = [1, datetime.now()])

assert str(exception_info.value) == "Expected 'ids' to only contain type 'str' ('int', 'datetime' given)"


def test_raises_invalid_argument_exception_for_invalid_statuses(self):
with raises(InvalidArgumentException) as exception_info:
ListAdjustments(statuses = [1])

assert str(exception_info.value) == "Expected 'statuses' to only contain type 'AdjustmentStatus' ('int' given)"
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from pytest import mark, raises

from paddle_billing.Resources.PricingPreviews.Operations import PreviewPrice

from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException

class TestPreviewPrice:
@mark.parametrize(
'invalid_items, expected_message',
[
(
[],
"'items' cannot be empty",
), (
['some invalid type'],
"Expected 'items' to only contain type 'PricePreviewItem' ('str' given)",
),
],
ids=[
"Empty items",
"Invalid item type",
],
)
def test_raises_invalid_argument_exception_for_invalid_items(self, invalid_items, expected_message):
with raises(InvalidArgumentException) as exception_info:
PreviewPrice(invalid_items)

assert str(exception_info.value) == expected_message

0 comments on commit 383300b

Please sign in to comment.