paddle-python-sdk 1.7.0__py3-none-any.whl → 1.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. paddle_billing/Client.py +3 -1
  2. paddle_billing/Entities/ClientToken.py +33 -0
  3. paddle_billing/Entities/ClientTokens/ClientTokenStatus.py +6 -0
  4. paddle_billing/Entities/ClientTokens/__init__.py +1 -0
  5. paddle_billing/Entities/Collections/ClientTokenCollection.py +14 -0
  6. paddle_billing/Entities/Collections/__init__.py +1 -0
  7. paddle_billing/Entities/Events/EventTypeName.py +3 -0
  8. paddle_billing/Notifications/Entities/ClientToken.py +33 -0
  9. paddle_billing/Notifications/Entities/ClientTokens/ClientTokenStatus.py +6 -0
  10. paddle_billing/Notifications/Entities/ClientTokens/__init__.py +1 -0
  11. paddle_billing/Notifications/Entities/Simulations/ClientToken.py +38 -0
  12. paddle_billing/Notifications/Entities/Simulations/__init__.py +1 -0
  13. paddle_billing/Notifications/Events/ClientTokenCreated.py +17 -0
  14. paddle_billing/Notifications/Events/ClientTokenRevoked.py +17 -0
  15. paddle_billing/Notifications/Events/ClientTokenUpdated.py +17 -0
  16. paddle_billing/Resources/ClientTokens/ClientTokensClient.py +50 -0
  17. paddle_billing/Resources/ClientTokens/Operations/CreateClientToken.py +10 -0
  18. paddle_billing/Resources/ClientTokens/Operations/ListClientTokens.py +35 -0
  19. paddle_billing/Resources/ClientTokens/Operations/UpdateClientToken.py +10 -0
  20. paddle_billing/Resources/ClientTokens/Operations/__init__.py +3 -0
  21. paddle_billing/Resources/ClientTokens/__init__.py +0 -0
  22. {paddle_python_sdk-1.7.0.dist-info → paddle_python_sdk-1.8.0.dist-info}/METADATA +3 -3
  23. {paddle_python_sdk-1.7.0.dist-info → paddle_python_sdk-1.8.0.dist-info}/RECORD +28 -9
  24. tests/Functional/Resources/ClientToken/__init__.py +0 -0
  25. tests/Functional/Resources/ClientToken/test_ClientTokensClient.py +298 -0
  26. {paddle_python_sdk-1.7.0.dist-info → paddle_python_sdk-1.8.0.dist-info}/WHEEL +0 -0
  27. {paddle_python_sdk-1.7.0.dist-info → paddle_python_sdk-1.8.0.dist-info}/licenses/LICENSE +0 -0
  28. {paddle_python_sdk-1.7.0.dist-info → paddle_python_sdk-1.8.0.dist-info}/top_level.txt +0 -0
paddle_billing/Client.py CHANGED
@@ -18,6 +18,7 @@ from paddle_billing.Logger.NullHandler import NullHandler
18
18
  from paddle_billing.Resources.Addresses.AddressesClient import AddressesClient
19
19
  from paddle_billing.Resources.Adjustments.AdjustmentsClient import AdjustmentsClient
20
20
  from paddle_billing.Resources.Businesses.BusinessesClient import BusinessesClient
21
+ from paddle_billing.Resources.ClientTokens.ClientTokensClient import ClientTokensClient
21
22
  from paddle_billing.Resources.Customers.CustomersClient import CustomersClient
22
23
  from paddle_billing.Resources.CustomerPortalSessions.CustomerPortalSessionsClient import CustomerPortalSessionsClient
23
24
  from paddle_billing.Resources.DiscountGroups.DiscountGroupsClient import DiscountGroupsClient
@@ -71,6 +72,7 @@ class Client:
71
72
  self.addresses = AddressesClient(self)
72
73
  self.adjustments = AdjustmentsClient(self)
73
74
  self.businesses = BusinessesClient(self)
75
+ self.client_tokens = ClientTokensClient(self)
74
76
  self.customers = CustomersClient(self)
75
77
  self.customer_portal_sessions = CustomerPortalSessionsClient(self)
76
78
  self.discounts = DiscountsClient(self)
@@ -198,7 +200,7 @@ class Client:
198
200
  "Authorization": f"Bearer {self.__api_key}",
199
201
  "Content-Type": "application/json",
200
202
  "Paddle-Version": str(self.use_api_version),
201
- "User-Agent": "PaddleSDK/python 1.7.0",
203
+ "User-Agent": "PaddleSDK/python 1.8.0",
202
204
  }
203
205
  )
204
206
 
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from paddle_billing.Entities.Entity import Entity
8
+ from paddle_billing.Entities.ClientTokens import ClientTokenStatus
9
+
10
+
11
+ @dataclass
12
+ class ClientToken(Entity):
13
+ id: str
14
+ status: ClientTokenStatus
15
+ token: str
16
+ name: str
17
+ description: str | None
18
+ created_at: datetime
19
+ updated_at: datetime
20
+ revoked_at: datetime | None
21
+
22
+ @staticmethod
23
+ def from_dict(data: dict[str, Any]) -> ClientToken:
24
+ return ClientToken(
25
+ id=data["id"],
26
+ status=ClientTokenStatus(data["status"]),
27
+ token=data["token"],
28
+ name=data["name"],
29
+ description=data.get("description"),
30
+ created_at=datetime.fromisoformat(data["created_at"]),
31
+ updated_at=datetime.fromisoformat(data["updated_at"]),
32
+ revoked_at=datetime.fromisoformat(data["revoked_at"]) if data.get("revoked_at") else None,
33
+ )
@@ -0,0 +1,6 @@
1
+ from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta
2
+
3
+
4
+ class ClientTokenStatus(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
5
+ Active: "ClientTokenStatus" = "active"
6
+ Revoked: "ClientTokenStatus" = "revoked"
@@ -0,0 +1 @@
1
+ from paddle_billing.Entities.ClientTokens.ClientTokenStatus import ClientTokenStatus
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ from paddle_billing.Entities.Collections.Collection import Collection
5
+ from paddle_billing.Entities.Collections.Paginator import Paginator
6
+ from paddle_billing.Entities.ClientToken import ClientToken
7
+
8
+
9
+ class ClientTokenCollection(Collection[ClientToken]):
10
+ @classmethod
11
+ def from_list(cls, items_data: list[dict[str, Any]], paginator: Paginator | None = None) -> ClientTokenCollection:
12
+ items: list[ClientToken] = [ClientToken.from_dict(item) for item in items_data]
13
+
14
+ return ClientTokenCollection(items, paginator)
@@ -1,6 +1,7 @@
1
1
  from paddle_billing.Entities.Collections.AddressCollection import AddressCollection
2
2
  from paddle_billing.Entities.Collections.AdjustmentCollection import AdjustmentCollection
3
3
  from paddle_billing.Entities.Collections.BusinessCollection import BusinessCollection
4
+ from paddle_billing.Entities.Collections.ClientTokenCollection import ClientTokenCollection
4
5
  from paddle_billing.Entities.Collections.Collection import Collection
5
6
  from paddle_billing.Entities.Collections.CreditBalanceCollection import CreditBalanceCollection
6
7
  from paddle_billing.Entities.Collections.CustomerCollection import CustomerCollection
@@ -15,6 +15,9 @@ class EventTypeName(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
15
15
  BusinessCreated: "EventTypeName" = "business.created"
16
16
  BusinessImported: "EventTypeName" = "business.imported"
17
17
  BusinessUpdated: "EventTypeName" = "business.updated"
18
+ ClientTokenCreated: "EventTypeName" = "client_token.created"
19
+ ClientTokenRevoked: "EventTypeName" = "client_token.revoked"
20
+ ClientTokenUpdated: "EventTypeName" = "client_token.updated"
18
21
  CustomerCreated: "EventTypeName" = "customer.created"
19
22
  CustomerImported: "EventTypeName" = "customer.imported"
20
23
  CustomerUpdated: "EventTypeName" = "customer.updated"
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from paddle_billing.Notifications.Entities.Entity import Entity
8
+ from paddle_billing.Notifications.Entities.ClientTokens import ClientTokenStatus
9
+
10
+
11
+ @dataclass
12
+ class ClientToken(Entity):
13
+ id: str
14
+ status: ClientTokenStatus
15
+ token: str
16
+ name: str
17
+ description: str | None
18
+ created_at: datetime
19
+ updated_at: datetime
20
+ revoked_at: datetime | None
21
+
22
+ @staticmethod
23
+ def from_dict(data: dict[str, Any]) -> ClientToken:
24
+ return ClientToken(
25
+ id=data["id"],
26
+ status=ClientTokenStatus(data["status"]),
27
+ token=data["token"],
28
+ name=data["name"],
29
+ description=data.get("description"),
30
+ created_at=datetime.fromisoformat(data["created_at"]),
31
+ updated_at=datetime.fromisoformat(data["updated_at"]),
32
+ revoked_at=datetime.fromisoformat(data["revoked_at"]) if data.get("revoked_at") else None,
33
+ )
@@ -0,0 +1,6 @@
1
+ from paddle_billing.PaddleStrEnum import PaddleStrEnum, PaddleStrEnumMeta
2
+
3
+
4
+ class ClientTokenStatus(PaddleStrEnum, metaclass=PaddleStrEnumMeta):
5
+ Active: "ClientTokenStatus" = "active"
6
+ Revoked: "ClientTokenStatus" = "revoked"
@@ -0,0 +1 @@
1
+ from paddle_billing.Notifications.Entities.ClientTokens.ClientTokenStatus import ClientTokenStatus
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from paddle_billing.Notifications.Entities.Simulations.SimulationEntity import SimulationEntity
8
+ from paddle_billing.Notifications.Entities.ClientTokens import ClientTokenStatus
9
+ from paddle_billing.Undefined import Undefined
10
+
11
+
12
+ @dataclass
13
+ class ClientToken(SimulationEntity):
14
+ id: str | Undefined = Undefined()
15
+ status: ClientTokenStatus | Undefined = Undefined()
16
+ token: str | Undefined = Undefined()
17
+ name: str | Undefined = Undefined()
18
+ description: str | None | Undefined = Undefined()
19
+ created_at: datetime | Undefined = Undefined()
20
+ updated_at: datetime | Undefined = Undefined()
21
+ revoked_at: datetime | None | Undefined = Undefined()
22
+
23
+ @staticmethod
24
+ def from_dict(data: dict[str, Any]) -> ClientToken:
25
+ return ClientToken(
26
+ id=data.get("id", Undefined()),
27
+ status=ClientTokenStatus(data["status"]) if data.get("status") else Undefined(),
28
+ token=data.get("token", Undefined()),
29
+ name=data.get("name", Undefined()),
30
+ description=data.get("description", Undefined()),
31
+ created_at=datetime.fromisoformat(data["created_at"]) if data.get("created_at") else Undefined(),
32
+ updated_at=datetime.fromisoformat(data["updated_at"]) if data.get("updated_at") else Undefined(),
33
+ revoked_at=(
34
+ datetime.fromisoformat(data["revoked_at"])
35
+ if data.get("revoked_at")
36
+ else data.get("revoked_at", Undefined())
37
+ ),
38
+ )
@@ -1,6 +1,7 @@
1
1
  from paddle_billing.Notifications.Entities.Simulations.Address import Address
2
2
  from paddle_billing.Notifications.Entities.Simulations.Adjustment import Adjustment
3
3
  from paddle_billing.Notifications.Entities.Simulations.Business import Business
4
+ from paddle_billing.Notifications.Entities.Simulations.ClientToken import ClientToken
4
5
  from paddle_billing.Notifications.Entities.Simulations.Customer import Customer
5
6
  from paddle_billing.Notifications.Entities.Simulations.Discount import Discount
6
7
  from paddle_billing.Notifications.Entities.Simulations.PaymentMethod import PaymentMethod
@@ -0,0 +1,17 @@
1
+ from datetime import datetime
2
+
3
+ from paddle_billing.Entities.Event import Event
4
+ from paddle_billing.Entities.Events import EventTypeName
5
+
6
+ from paddle_billing.Notifications.Entities.ClientToken import ClientToken
7
+
8
+
9
+ class ClientTokenCreated(Event):
10
+ def __init__(
11
+ self,
12
+ event_id: str,
13
+ event_type: EventTypeName,
14
+ occurred_at: datetime,
15
+ data: ClientToken,
16
+ ):
17
+ super().__init__(event_id, event_type, occurred_at, data)
@@ -0,0 +1,17 @@
1
+ from datetime import datetime
2
+
3
+ from paddle_billing.Entities.Event import Event
4
+ from paddle_billing.Entities.Events import EventTypeName
5
+
6
+ from paddle_billing.Notifications.Entities.ClientToken import ClientToken
7
+
8
+
9
+ class ClientTokenRevoked(Event):
10
+ def __init__(
11
+ self,
12
+ event_id: str,
13
+ event_type: EventTypeName,
14
+ occurred_at: datetime,
15
+ data: ClientToken,
16
+ ):
17
+ super().__init__(event_id, event_type, occurred_at, data)
@@ -0,0 +1,17 @@
1
+ from datetime import datetime
2
+
3
+ from paddle_billing.Entities.Event import Event
4
+ from paddle_billing.Entities.Events import EventTypeName
5
+
6
+ from paddle_billing.Notifications.Entities.ClientToken import ClientToken
7
+
8
+
9
+ class ClientTokenUpdated(Event):
10
+ def __init__(
11
+ self,
12
+ event_id: str,
13
+ event_type: EventTypeName,
14
+ occurred_at: datetime,
15
+ data: ClientToken,
16
+ ):
17
+ super().__init__(event_id, event_type, occurred_at, data)
@@ -0,0 +1,50 @@
1
+ from paddle_billing.ResponseParser import ResponseParser
2
+
3
+ from paddle_billing.Entities.Collections import Paginator, ClientTokenCollection
4
+ from paddle_billing.Entities.ClientToken import ClientToken
5
+ from paddle_billing.Entities.ClientTokens import ClientTokenStatus
6
+
7
+ from paddle_billing.Resources.ClientTokens.Operations import CreateClientToken, ListClientTokens, UpdateClientToken
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from paddle_billing.Client import Client
13
+
14
+
15
+ class ClientTokensClient:
16
+ def __init__(self, client: "Client"):
17
+ self.client = client
18
+ self.response = None
19
+
20
+ def list(self, operation: ListClientTokens | None = None) -> ClientTokenCollection:
21
+ if operation is None:
22
+ operation = ListClientTokens()
23
+
24
+ self.response = self.client.get_raw("/client-tokens", operation.get_parameters())
25
+ parser = ResponseParser(self.response)
26
+
27
+ return ClientTokenCollection.from_list(
28
+ parser.get_list(), Paginator(self.client, parser.get_pagination(), ClientTokenCollection)
29
+ )
30
+
31
+ def get(self, client_token_id: str) -> ClientToken:
32
+ self.response = self.client.get_raw(f"/client-tokens/{client_token_id}")
33
+ parser = ResponseParser(self.response)
34
+
35
+ return ClientToken.from_dict(parser.get_dict())
36
+
37
+ def create(self, operation: CreateClientToken) -> ClientToken:
38
+ self.response = self.client.post_raw("/client-tokens", operation)
39
+ parser = ResponseParser(self.response)
40
+
41
+ return ClientToken.from_dict(parser.get_dict())
42
+
43
+ def update(self, client_token_id: str, operation: UpdateClientToken) -> ClientToken:
44
+ self.response = self.client.patch_raw(f"/client-tokens/{client_token_id}", operation)
45
+ parser = ResponseParser(self.response)
46
+
47
+ return ClientToken.from_dict(parser.get_dict())
48
+
49
+ def revoke(self, client_token_id: str) -> ClientToken:
50
+ return self.update(client_token_id, UpdateClientToken(status=ClientTokenStatus.Revoked))
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+
3
+ from paddle_billing.Operation import Operation
4
+ from paddle_billing.Undefined import Undefined
5
+
6
+
7
+ @dataclass
8
+ class CreateClientToken(Operation):
9
+ name: str
10
+ description: str | None | Undefined = Undefined()
@@ -0,0 +1,35 @@
1
+ from paddle_billing.Entities.ClientToken import ClientTokenStatus
2
+ from paddle_billing.EnumStringify import enum_stringify
3
+ from paddle_billing.HasParameters import HasParameters
4
+
5
+ from paddle_billing.Exceptions.SdkExceptions.InvalidArgumentException import InvalidArgumentException
6
+ from paddle_billing.Resources.Shared.Operations import Pager
7
+
8
+
9
+ class ListClientTokens(HasParameters):
10
+ def __init__(
11
+ self,
12
+ pager: Pager | None = None,
13
+ statuses: list[ClientTokenStatus] | None = None,
14
+ ):
15
+ self.pager = pager
16
+ self.statuses = statuses if statuses is not None else []
17
+
18
+ # Validation
19
+ for field_name, field_value, field_type in [
20
+ ("statuses", self.statuses, ClientTokenStatus),
21
+ ]:
22
+ invalid_items = [item for item in field_value if not isinstance(item, field_type)]
23
+ if invalid_items:
24
+ raise InvalidArgumentException.array_contains_invalid_types(
25
+ field_name, field_type.__name__, invalid_items
26
+ )
27
+
28
+ def get_parameters(self) -> dict[str, str]:
29
+ parameters = {}
30
+ if self.pager:
31
+ parameters.update(self.pager.get_parameters())
32
+ if self.statuses:
33
+ parameters["status"] = ",".join(map(enum_stringify, self.statuses))
34
+
35
+ return parameters
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+
3
+ from paddle_billing.Operation import Operation
4
+ from paddle_billing.Undefined import Undefined
5
+ from paddle_billing.Entities.ClientTokens import ClientTokenStatus
6
+
7
+
8
+ @dataclass
9
+ class UpdateClientToken(Operation):
10
+ status: ClientTokenStatus | Undefined = Undefined()
@@ -0,0 +1,3 @@
1
+ from paddle_billing.Resources.ClientTokens.Operations.CreateClientToken import CreateClientToken
2
+ from paddle_billing.Resources.ClientTokens.Operations.ListClientTokens import ListClientTokens
3
+ from paddle_billing.Resources.ClientTokens.Operations.UpdateClientToken import UpdateClientToken
File without changes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paddle-python-sdk
3
- Version: 1.7.0
3
+ Version: 1.8.0
4
4
  Summary: Paddle's Python SDK for Paddle Billing
5
5
  Home-page: https://developer.paddle.com/api-reference/overview
6
6
  Author: Paddle and contributors
@@ -19,8 +19,8 @@ License-File: LICENSE
19
19
  Requires-Dist: requests>=2.31
20
20
  Requires-Dist: urllib3>=1.26.18
21
21
  Provides-Extra: dev
22
- Requires-Dist: pytest<8.4.0,>=7.4.4; extra == "dev"
23
- Requires-Dist: pytest-cov<6.1,>=4.1; extra == "dev"
22
+ Requires-Dist: pytest<8.5.0,>=7.4.4; extra == "dev"
23
+ Requires-Dist: pytest-cov<6.3,>=4.1; extra == "dev"
24
24
  Requires-Dist: requests-mock~=1.11.0; extra == "dev"
25
25
  Requires-Dist: setuptools>=69.0.3; extra == "dev"
26
26
  Requires-Dist: pre-commit>=3.8.0; extra == "dev"
@@ -5,7 +5,7 @@ examples/event_polling.py,sha256=580dg_8CFrSCA89Mr1ny4V1gtB3-hk-LfePTbI7DT5w,217
5
5
  examples/get_products.py,sha256=4V7ZG1SH6Oxojufbtzm_TMySw4cOBMQ99mgQK_hlwFQ,1875
6
6
  examples/logger.py,sha256=AxmQmMrsM0ZqMIUnh6iARiczL4S4F9OqQcOu-67owNg,1042
7
7
  examples/webhook_verification.py,sha256=qkNscNdNZUAgxEIk83tCiljN2VmfePZ_k8zTliKz2QY,1205
8
- paddle_billing/Client.py,sha256=sn-7HZQ75m0NkXx6odBcYNZvDSDl3217mKQfkK4KpFs,9128
8
+ paddle_billing/Client.py,sha256=SUq5XIRZFWssz0hTRWMkmJZ_iV6s6FYKYMy54oH19Co,9270
9
9
  paddle_billing/EnumStringify.py,sha256=iDvKULZat3jx9A-_PhvoN6CbFGf2pyxrQeYZxqX9n8M,48
10
10
  paddle_billing/Environment.py,sha256=sY4nrJUwlTugsZKncieAnvfCojqCcKWi4X7rFzjFeSQ,417
11
11
  paddle_billing/FiltersNone.py,sha256=ErOjaTfxtELXrXdxUvFF9DJI_Yl31iseO4K56qTDR54,303
@@ -22,6 +22,7 @@ paddle_billing/Entities/Address.py,sha256=FPyX7sBXkcbDv0ZbZkaNgidWPB1XbBZKzw01X3
22
22
  paddle_billing/Entities/Adjustment.py,sha256=zOtGdcbn2jS-s-3zF0vwyFgOTwp7pnOiRC5ZKmbdFZ4,2133
23
23
  paddle_billing/Entities/AdjustmentCreditNote.py,sha256=pZ48foCPlRLwZFETTDNRs7M-K_0ZqoZIKjWenQA7-50,338
24
24
  paddle_billing/Entities/Business.py,sha256=90T3vhYkdguf_VpXi1HTOsO2rAdR0zwYxYyQ--ql648,1364
25
+ paddle_billing/Entities/ClientToken.py,sha256=br7Asm06YUWAR9tFFx_Qnbb6SH-gFJhMIRO7OUmLayg,1006
25
26
  paddle_billing/Entities/CreditBalance.py,sha256=2ftw3KV2Mew92i1SvZtqFwYzCrgKuYIqWGd8amSGC1k,706
26
27
  paddle_billing/Entities/Customer.py,sha256=aIBbJ3YjsXEUmVHstadm7Jj5EVRIbK6jA1QA-1uvxro,1198
27
28
  paddle_billing/Entities/CustomerAuthToken.py,sha256=735sBPKBnSJu9vEp8hevDDkniXHwjRJFTvyRnVj2tiU,526
@@ -57,9 +58,12 @@ paddle_billing/Entities/Adjustments/AdjustmentItem.py,sha256=oEsz0A6c_k4AsFoyEFy
57
58
  paddle_billing/Entities/Adjustments/AdjustmentTaxRatesUsed.py,sha256=Fq2j54GZ2TinSTQ9fXk_kxMpH5yvcah8YVVMOirDHhg,502
58
59
  paddle_billing/Entities/Adjustments/AdjustmentTotals.py,sha256=QdVxLTJOxhdVF9SK81mHEMxa6W27XIAuEPS7zMIOdI0,399
59
60
  paddle_billing/Entities/Adjustments/__init__.py,sha256=h2dLT_sTySreBTu886fA8F0zjOW16pnyU4FfNAWLAGk,272
61
+ paddle_billing/Entities/ClientTokens/ClientTokenStatus.py,sha256=KnvAHXFsjnrjRPyDSY_82TlrTEVjiSFkI6hhHLWJwYg,233
62
+ paddle_billing/Entities/ClientTokens/__init__.py,sha256=ph1Aqt5NokQMivy67hniNVYI5mGfdo_Cx9z7S1lpCsM,85
60
63
  paddle_billing/Entities/Collections/AddressCollection.py,sha256=IKTlx9PmwmIgMZ4iAH1kRFYIyk4dg_lkCNfkWnvdyYs,561
61
64
  paddle_billing/Entities/Collections/AdjustmentCollection.py,sha256=HsKYx66hyAWwf_WsYUVq9bCCbCMnMjbXmVYPtZcv62g,585
62
65
  paddle_billing/Entities/Collections/BusinessCollection.py,sha256=k5MS3RoE2bcVlb61GcdY58ywBWLmF7IEWNHMiSI3Y0E,570
66
+ paddle_billing/Entities/Collections/ClientTokenCollection.py,sha256=WmZQuAGsGxOw6bKCGfpSW-ozo_O1B-dAfv5JHg93ZqY,593
63
67
  paddle_billing/Entities/Collections/Collection.py,sha256=hbVbZDvRr7_bWOIGA-8t9Twt0mCv5MGY_Qn56W2nS2Y,1276
64
68
  paddle_billing/Entities/Collections/CreditBalanceCollection.py,sha256=9W1VkPz_uDxUXM46JECibC6KAINn7I6-rVXWFxw5-pA,609
65
69
  paddle_billing/Entities/Collections/CustomerCollection.py,sha256=uwIZxlNygFXd9Q_zCnnHysphh7GOdln8gcUv-VLXQ14,569
@@ -84,7 +88,7 @@ paddle_billing/Entities/Collections/SubscriptionPreviewCollection.py,sha256=V1_k
84
88
  paddle_billing/Entities/Collections/TransactionCollection.py,sha256=6yvOLABrD_3TMGKwJtvUjTKzTgSGJ6Edzq_VqBMS7JI,593
85
89
  paddle_billing/Entities/Collections/TransactionPreviewCollection.py,sha256=ZP-xQX9DZE2vHri1Gmb0PcVujWbb4_Orqu2Yu6-B_LE,663
86
90
  paddle_billing/Entities/Collections/TransactionsDataCollection.py,sha256=CaW1GwoXpXSu1ST4Po5pHYF1HlH2WAyu_xzOMmlji8I,642
87
- paddle_billing/Entities/Collections/__init__.py,sha256=5dYiN8A36RadRo-j-dAL5KuOP85uD4Yj74qDpiaYRtI,2466
91
+ paddle_billing/Entities/Collections/__init__.py,sha256=bC6hABSB5NlE9y-dK_GPmM3Y9LJc2wAylwBRvxx342s,2558
88
92
  paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionGeneralUrl.py,sha256=cyN4zrKPD_jDozq5NWqlkIy9HRK4qvFFi-lBnBBZTMc,354
89
93
  paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionSubscriptionUrl.py,sha256=QAk-Ca1Hijg0hVpzFaX6e0WEzMHMU9ZPCmRUzNx0YYo,576
90
94
  paddle_billing/Entities/CustomerPortalSessions/CustomerPortalSessionUrls.py,sha256=syRIa_vZZ0y0BeLM83jo7EZ3ua4-0MCKM0jdxQiWbTE,895
@@ -95,7 +99,7 @@ paddle_billing/Entities/Discounts/DiscountMode.py,sha256=hzk_00WsxvhJOFfbBywzlSH
95
99
  paddle_billing/Entities/Discounts/DiscountStatus.py,sha256=ss0Btu04U7NEXYgWxlnkUOWINjSXILu67LWEgLb1DaA,304
96
100
  paddle_billing/Entities/Discounts/DiscountType.py,sha256=7JQCM_dN2PGHSiA-jzBHTIRVMVTRFKdHAMKxDxpQgf0,270
97
101
  paddle_billing/Entities/Discounts/__init__.py,sha256=tmYgP8Cw5hVZ_fe1yxeR53AIGmdeXzjYKYxudeqG-SU,220
98
- paddle_billing/Entities/Events/EventTypeName.py,sha256=ltCbjxGMD-NRl2HDpA5Z8kZY9_09T2XMUPFBVUcXnyw,3566
102
+ paddle_billing/Entities/Events/EventTypeName.py,sha256=nbvPGbQEMvrlrDBjQfvq94sjlf0KTfQPK2QX7l0L7II,3761
99
103
  paddle_billing/Entities/Events/__init__.py,sha256=DBvU5TZXroY6IACIhh26VV8TWoagJAkne8e9Pz9YdPs,71
100
104
  paddle_billing/Entities/NotificationSettings/NotificationSettingTrafficSource.py,sha256=5jga7qMivQXyU55XOPMGvwsLO1wEPA0Mur40knDgEks,340
101
105
  paddle_billing/Entities/NotificationSettings/NotificationSettingType.py,sha256=zm3kpN5T5QkKp3-3JUpZphUrXCD992OkClAIahqxbns,241
@@ -288,6 +292,7 @@ paddle_billing/Notifications/Entities/Address.py,sha256=ktgEgWXr6UkpSnJtwTQU8Pog
288
292
  paddle_billing/Notifications/Entities/Adjustment.py,sha256=836qBkGD2Cx5aNwoUmJ39IDSUBa3dEmdSYuEv9E9DUA,2323
289
293
  paddle_billing/Notifications/Entities/ApiKey.py,sha256=5-1Dcp8HXqyskFjKOFfkV9u6GNhqpdNBjSsyGCm3Ytg,1287
290
294
  paddle_billing/Notifications/Entities/Business.py,sha256=b_QTTvVBS6KlN4S87OY22V2zoZY0lSHHSTrHjJ0Jwg4,1500
295
+ paddle_billing/Notifications/Entities/ClientToken.py,sha256=yXFcx20UVT-CFO1K7NGtujOKOjlpukchKVDkclcdVck,1034
291
296
  paddle_billing/Notifications/Entities/Customer.py,sha256=i3sFQGYQCwvLByREbOAGt_x7Lb5ywg0Efje-hpibUis,1226
292
297
  paddle_billing/Notifications/Entities/DateTime.py,sha256=iJLwbDZwmfHW2TgE8HRPpkw_xZBrwZyVhFaQnKJENu8,1459
293
298
  paddle_billing/Notifications/Entities/Discount.py,sha256=PHpQTgf_BbVX31FipD_p9lh6R3VFSOZLi72xp7c8Eys,2312
@@ -314,6 +319,8 @@ paddle_billing/Notifications/Entities/ApiKeys/ApiKeyStatus.py,sha256=cKtyxWgPhR5
314
319
  paddle_billing/Notifications/Entities/ApiKeys/__init__.py,sha256=Q7mE3NFLffKO1XkMJroIOrrYiW6S3iVpUoI9wC5zP6Y,176
315
320
  paddle_billing/Notifications/Entities/Businesses/BusinessesContacts.py,sha256=Z-vW8cDGeynSREQ00wd4UxyA463EB4LtkqWGtNS58xQ,351
316
321
  paddle_billing/Notifications/Entities/Businesses/__init__.py,sha256=157wIn7fKwrE3Wuu1-RctcJjpjX83m77BAe_YIYwjXs,99
322
+ paddle_billing/Notifications/Entities/ClientTokens/ClientTokenStatus.py,sha256=KnvAHXFsjnrjRPyDSY_82TlrTEVjiSFkI6hhHLWJwYg,233
323
+ paddle_billing/Notifications/Entities/ClientTokens/__init__.py,sha256=OHeqcAXPavCYOsCFyDJ3SN27R1R1fYU6IjdkcQI4EqM,99
317
324
  paddle_billing/Notifications/Entities/DiscountGroups/DiscountGroupStatus.py,sha256=tFrxDCkoTf0ya_bO1EQOg1y4EcICFWTm6qu1divua_E,241
318
325
  paddle_billing/Notifications/Entities/DiscountGroups/__init__.py,sha256=qU8unAr_wipUP9fpR0DROsBhH44HUVcmntQ9JqQ9DSY,91
319
326
  paddle_billing/Notifications/Entities/Discounts/DiscountMode.py,sha256=hzk_00WsxvhJOFfbBywzlSHOWOgd9GqTIiBFU7Xbtu8,220
@@ -386,6 +393,7 @@ paddle_billing/Notifications/Entities/Simulations/Address.py,sha256=mBcPnHBtwBVK
386
393
  paddle_billing/Notifications/Entities/Simulations/Adjustment.py,sha256=vbcB_VEwRUg6du_pGwkT5tCRdC1DgqdxGVkKR1FW36I,3369
387
394
  paddle_billing/Notifications/Entities/Simulations/ApiKey.py,sha256=neTDaFyVFkqC17YFajSQl6NuykuyY1w5pTeTKZnCWo4,2125
388
395
  paddle_billing/Notifications/Entities/Simulations/Business.py,sha256=Z7_Y-LH5pfJ9iyIA3TbZ-N3YOTMInQAnk6ZDOO95vFM,2385
396
+ paddle_billing/Notifications/Entities/Simulations/ClientToken.py,sha256=CicRvRcQWtzNzPGeB_QEAmGisobICwHdEaAawcMHb6Y,1615
389
397
  paddle_billing/Notifications/Entities/Simulations/Customer.py,sha256=WMnw37Zbh0CKfKWKWYMgDmp9rpilvPP-5SX2jlBMQJg,1995
390
398
  paddle_billing/Notifications/Entities/Simulations/Discount.py,sha256=H34NlXnvLDqo6hsKLKEh1TW4WFG3e5TDLiGHp6iKNSg,3623
391
399
  paddle_billing/Notifications/Entities/Simulations/DiscountGroup.py,sha256=_1sskFllpDRWpEqypPKUm5bfO8Fjow5jLg_qvFawKJE,1500
@@ -399,7 +407,7 @@ paddle_billing/Notifications/Entities/Simulations/SimulationEntity.py,sha256=Wr1
399
407
  paddle_billing/Notifications/Entities/Simulations/Subscription.py,sha256=TTmXAPLTR7XeqZnbzLEN4JNnQRmLE-ptQ3MHOYPeb2g,5559
400
408
  paddle_billing/Notifications/Entities/Simulations/SubscriptionCreated.py,sha256=EfneXY1fDNhq1FG6qZukEqDVCOUQKMTYxpSIrmXP7lo,5705
401
409
  paddle_billing/Notifications/Entities/Simulations/Transaction.py,sha256=SsOHXu-fefeex5_pqXOYNQ4seHoD8lQ9L2R1LXyjbLQ,5007
402
- paddle_billing/Notifications/Entities/Simulations/__init__.py,sha256=tHFS3tOJjn_xwnOLxltc1K3OtpNR1-XfKd7G53JxTwg,1176
410
+ paddle_billing/Notifications/Entities/Simulations/__init__.py,sha256=TYdqWHJ6KWX8kUonxDTcxBGFKSh-yFFMA2esvM-pGPU,1262
403
411
  paddle_billing/Notifications/Entities/Subscriptions/SubscriptionAdjustmentItem.py,sha256=3tHwWipV7K_xISgsN60FnH5BDt0ZEYoh0OT4M-dxxA0,763
404
412
  paddle_billing/Notifications/Entities/Subscriptions/SubscriptionCharge.py,sha256=EqI4qBmFQavDjwRPeJWqVEjba_cA4H5H3Hp_7wEw9EE,475
405
413
  paddle_billing/Notifications/Entities/Subscriptions/SubscriptionCredit.py,sha256=iferu7zSOBHskqHAW6fvKBacS07GT0gIK2-kLNJT1Ow,475
@@ -431,6 +439,9 @@ paddle_billing/Notifications/Events/ApiKeyRevoked.py,sha256=iXeyWaoZxDc7uHuCiZtQ
431
439
  paddle_billing/Notifications/Events/ApiKeyUpdated.py,sha256=Y9LXxNx6p3DdN8vynE6Q73uQW7hpmg0GCf8tu1Yuexw,447
432
440
  paddle_billing/Notifications/Events/BusinessCreated.py,sha256=OujioUI949ZGAIO0575TvYE_YWQw-fin6D-1X8BG89I,455
433
441
  paddle_billing/Notifications/Events/BusinessUpdated.py,sha256=_5HhTE6LWpQCKuA9jBRbJ7R4yj1kdq9b-rq9Yeo6mzo,455
442
+ paddle_billing/Notifications/Events/ClientTokenCreated.py,sha256=I79gnc4X9bGUTL87RVtrEdznIIHs5xKFnIHjJSkeQHg,467
443
+ paddle_billing/Notifications/Events/ClientTokenRevoked.py,sha256=e8WyJlxgZ7Ls7wg1p0i4G_ucpUO5zsbrKdcowYhdwE4,467
444
+ paddle_billing/Notifications/Events/ClientTokenUpdated.py,sha256=y3FU06onCzIB0WN9DTqWsXmZJ-4L3q4V-NPI6laIzzU,467
434
445
  paddle_billing/Notifications/Events/CustomerCreated.py,sha256=vmbI3yn2jL2fVDamOYuHsVNe2-8lJBqlvvrykkuIWcA,455
435
446
  paddle_billing/Notifications/Events/CustomerUpdated.py,sha256=nC7X_bCLb7j4uo_ZJ_HQcHKUiYp554rHwkDzurLwFqE,455
436
447
  paddle_billing/Notifications/Events/DiscountCreated.py,sha256=w8r8aMdrPPMT4VKWq-S4S07QLFPUvT2QdO98i3TbXHE,455
@@ -491,6 +502,12 @@ paddle_billing/Resources/Businesses/Operations/CreateBusiness.py,sha256=zDQ-V7El
491
502
  paddle_billing/Resources/Businesses/Operations/ListBusinesses.py,sha256=ImMW68azO87CWpi2ODnN8xeRL25yIhvJfOyaqOCqWgg,1619
492
503
  paddle_billing/Resources/Businesses/Operations/UpdateBusiness.py,sha256=fzijE9x9ru58jOW5Rq-ZvV_LtFc7m6rksyJQiSNwyLA,562
493
504
  paddle_billing/Resources/Businesses/Operations/__init__.py,sha256=mctosPK-Kdb4n_AmdIqVFKeldZxcjw8e4k4iWWoRml0,267
505
+ paddle_billing/Resources/ClientTokens/ClientTokensClient.py,sha256=b6n3KzG1SZ3OQESupAyrbUwRmf1mVLgks4mr4IVbTRs,2003
506
+ paddle_billing/Resources/ClientTokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
507
+ paddle_billing/Resources/ClientTokens/Operations/CreateClientToken.py,sha256=wTEzFcBHcbg_m_Nfraf_s8McYObRM0hI0DwsZ0KslSw,246
508
+ paddle_billing/Resources/ClientTokens/Operations/ListClientTokens.py,sha256=T26QcrRWbY7u-_y3tysyG9JFZ3o1_DsUXiKSURYeFm8,1327
509
+ paddle_billing/Resources/ClientTokens/Operations/UpdateClientToken.py,sha256=4yXwl65YUKExXQtRfBcgnzx9PE51j4rfZT6h1FWzRIA,301
510
+ paddle_billing/Resources/ClientTokens/Operations/__init__.py,sha256=8yBr7tF_OOuANW-bK7ZgwqQQaeBIVp2Fw3ML0rPgZgM,289
494
511
  paddle_billing/Resources/CustomerPortalSessions/CustomerPortalSessionsClient.py,sha256=u6Ix9aUkzodU2FYz_SqygWmUCKZkmxBhCBqMjdmrQJI,804
495
512
  paddle_billing/Resources/CustomerPortalSessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
496
513
  paddle_billing/Resources/CustomerPortalSessions/Operations/CreateCustomerPortalSession.py,sha256=EvIwrW-2fmC4xgh3XCJJmjya52aAj0YvkFOJk-yzNto,246
@@ -696,7 +713,7 @@ paddle_billing/Resources/Transactions/Operations/Update/TransactionUpdateItem.py
696
713
  paddle_billing/Resources/Transactions/Operations/Update/TransactionUpdateItemWithPrice.py,sha256=3MIhPl85ZTen-9RLLlrX-s9pktno3Eb32X8tW6hyXSg,490
697
714
  paddle_billing/Resources/Transactions/Operations/Update/UpdateBillingDetails.py,sha256=NAfwUJrT3slphzWfVQjDMElwjljde72wwMBX25Qe9YA,447
698
715
  paddle_billing/Resources/Transactions/Operations/Update/__init__.py,sha256=VL03L8n4r2ZuxGI6l7kpHksSYJSmZL6cKaO9ToTu2jo,361
699
- paddle_python_sdk-1.7.0.dist-info/licenses/LICENSE,sha256=e5Sn9mzCdpjnqCLxXpGHNKdYB6JlRSTLhN_CD4WSO6w,10770
716
+ paddle_python_sdk-1.8.0.dist-info/licenses/LICENSE,sha256=e5Sn9mzCdpjnqCLxXpGHNKdYB6JlRSTLhN_CD4WSO6w,10770
700
717
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
701
718
  tests/conftest.py,sha256=K_rWFm4jOBGVpoQP9llOwQwyYrXThbF3CBvood_hNRU,127
702
719
  tests/Functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -709,6 +726,8 @@ tests/Functional/Resources/Adjustments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
709
726
  tests/Functional/Resources/Adjustments/test_AdjustmentsClient.py,sha256=s47ShnZyiW4dnFHG_NBM7ecYnmnYLFBTLNEz_2bg7CQ,19278
710
727
  tests/Functional/Resources/Businesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
711
728
  tests/Functional/Resources/Businesses/test_BusinessesClient.py,sha256=uUAydFqmXq3snmu--gGVI5nNrpg6oySQM_Ulg9q-G1Q,12727
729
+ tests/Functional/Resources/ClientToken/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
730
+ tests/Functional/Resources/ClientToken/test_ClientTokensClient.py,sha256=EKI95cvkt7KR63f_6cZ8RmEmbJk9q4nx0uifjStZ2KA,12046
712
731
  tests/Functional/Resources/CustomerPortalSessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
713
732
  tests/Functional/Resources/CustomerPortalSessions/test_CustomerPortalSessionsClient.py,sha256=n33TXcOD0c6twPECsebfJA_AxLDJV_XV8WixWzvcSvw,7430
714
733
  tests/Functional/Resources/Customers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -763,7 +782,7 @@ tests/Utils/ReadsFixture.py,sha256=3CQ_8XHji3kuR28Ktlmw1Kip565UycocUytldWtuAyw,1
763
782
  tests/Utils/TestClient.py,sha256=-wc7hJMuR6WC-ukw0c7I59b5-8hj_-nzq__-2M81elg,1453
764
783
  tests/Utils/TestLogger.py,sha256=pFO9x711buRmg-8DAqpzIJP_hr21JPty1_ZQRcwoGKk,554
765
784
  tests/Utils/__init__.py,sha256=JtqJNPKqbNZ9exlpXlF3yj_9cfylPGlvopjQYi7yYTA,37
766
- paddle_python_sdk-1.7.0.dist-info/METADATA,sha256=JUuyznJ78G01_03W-TP7Ru_ppswUhhSL5eRcwGJX1Io,8045
767
- paddle_python_sdk-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
768
- paddle_python_sdk-1.7.0.dist-info/top_level.txt,sha256=9a07VPng7o5wK8VAXkl6NC30xrNbW9zff_02jHyHi4c,30
769
- paddle_python_sdk-1.7.0.dist-info/RECORD,,
785
+ paddle_python_sdk-1.8.0.dist-info/METADATA,sha256=3v-dGeq9hV-v_jR3np4ggfxqsg_fMg5JfSbEIBXRzBo,8045
786
+ paddle_python_sdk-1.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
787
+ paddle_python_sdk-1.8.0.dist-info/top_level.txt,sha256=9a07VPng7o5wK8VAXkl6NC30xrNbW9zff_02jHyHi4c,30
788
+ paddle_python_sdk-1.8.0.dist-info/RECORD,,
File without changes
@@ -0,0 +1,298 @@
1
+ from json import loads
2
+ from pytest import mark
3
+ from urllib.parse import unquote
4
+
5
+ from build.lib.paddle_billing.Json import PayloadEncoder
6
+ from paddle_billing.Entities.Collections import ClientTokenCollection
7
+ from paddle_billing.Entities.ClientToken import ClientToken
8
+ from paddle_billing.Entities.ClientTokens import ClientTokenStatus
9
+
10
+ from paddle_billing.Resources.ClientTokens.Operations import CreateClientToken, ListClientTokens, UpdateClientToken
11
+ from paddle_billing.Resources.Shared.Operations import Pager
12
+
13
+ from tests.Utils.ReadsFixture import ReadsFixtures
14
+
15
+
16
+ class TestClientTokensClient:
17
+ @mark.parametrize(
18
+ "operation, expected_request_body, expected_response_status, expected_response_body, expected_url",
19
+ [
20
+ (
21
+ CreateClientToken(
22
+ "Pricing page integration",
23
+ None,
24
+ ),
25
+ ReadsFixtures.read_raw_json_fixture("request/create_basic"),
26
+ 200,
27
+ ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
28
+ "/client-tokens",
29
+ ),
30
+ (
31
+ CreateClientToken(
32
+ "Pricing page integration",
33
+ None,
34
+ ),
35
+ ReadsFixtures.read_raw_json_fixture("request/create_null_description"),
36
+ 200,
37
+ ReadsFixtures.read_raw_json_fixture("response/minimal_entity"),
38
+ "/client-tokens",
39
+ ),
40
+ (
41
+ CreateClientToken(
42
+ "Pricing page integration",
43
+ "Used to display prices and open checkout within our pricing page on our marketing domain.",
44
+ ),
45
+ ReadsFixtures.read_raw_json_fixture("request/create_full"),
46
+ 200,
47
+ ReadsFixtures.read_raw_json_fixture("response/full_entity"),
48
+ "/client-tokens",
49
+ ),
50
+ ],
51
+ ids=[
52
+ "Create client token with basic data",
53
+ "Create client token with basic data - null description",
54
+ "Create client token with full data",
55
+ ],
56
+ )
57
+ def test_create_client_token_uses_expected_payload(
58
+ self,
59
+ test_client,
60
+ mock_requests,
61
+ operation,
62
+ expected_request_body,
63
+ expected_response_status,
64
+ expected_response_body,
65
+ expected_url,
66
+ ):
67
+ expected_url = f"{test_client.base_url}{expected_url}"
68
+ mock_requests.post(expected_url, status_code=expected_response_status, text=expected_response_body)
69
+
70
+ response = test_client.client.client_tokens.create(operation)
71
+ response_json = test_client.client.client_tokens.response.json()
72
+ request_json = test_client.client.payload
73
+ last_request = mock_requests.last_request
74
+
75
+ assert isinstance(response, ClientToken)
76
+ assert last_request is not None
77
+ assert last_request.method == "POST"
78
+ assert test_client.client.status_code == expected_response_status
79
+ assert (
80
+ unquote(last_request.url) == expected_url
81
+ ), "The URL does not match the expected URL, verify the query string is correct"
82
+ assert loads(request_json) == loads(
83
+ expected_request_body
84
+ ), "The request JSON doesn't match the expected fixture JSON"
85
+ assert response_json == loads(
86
+ str(expected_response_body)
87
+ ), "The response JSON doesn't match the expected fixture JSON"
88
+
89
+ @mark.parametrize(
90
+ "client_token_id, operation, expected_request_body, expected_response_status, expected_response_body, expected_url",
91
+ [
92
+ (
93
+ "ctkn_01ghbkd0frb9k95cnhwd1bxpvk",
94
+ UpdateClientToken(status=ClientTokenStatus.Revoked),
95
+ ReadsFixtures.read_raw_json_fixture("request/revoke"),
96
+ 200,
97
+ ReadsFixtures.read_raw_json_fixture("response/revoked_entity"),
98
+ "/client-tokens/ctkn_01ghbkd0frb9k95cnhwd1bxpvk",
99
+ ),
100
+ ],
101
+ ids=["Revoke client token"],
102
+ )
103
+ def test_update_client_token_uses_expected_payload(
104
+ self,
105
+ test_client,
106
+ mock_requests,
107
+ client_token_id,
108
+ operation,
109
+ expected_request_body,
110
+ expected_response_status,
111
+ expected_response_body,
112
+ expected_url,
113
+ ):
114
+ expected_url = f"{test_client.base_url}{expected_url}"
115
+ mock_requests.patch(expected_url, status_code=expected_response_status, text=expected_response_body)
116
+
117
+ response = test_client.client.client_tokens.update(client_token_id, operation)
118
+ response_json = test_client.client.client_tokens.response.json()
119
+ request_json = test_client.client.payload
120
+ last_request = mock_requests.last_request
121
+
122
+ assert isinstance(response, ClientToken)
123
+ assert last_request is not None
124
+ assert last_request.method == "PATCH"
125
+ assert test_client.client.status_code == expected_response_status
126
+ assert (
127
+ unquote(last_request.url) == expected_url
128
+ ), "The URL does not match the expected URL, verify the query string is correct"
129
+ assert loads(request_json) == loads(
130
+ expected_request_body
131
+ ), "The request JSON doesn't match the expected fixture JSON"
132
+ assert response_json == loads(
133
+ str(expected_response_body)
134
+ ), "The response JSON doesn't match the expected fixture JSON"
135
+
136
+ def test_revoke_client_token_uses_expected_payload(
137
+ self,
138
+ test_client,
139
+ mock_requests,
140
+ ):
141
+ client_token_id = "ctkn_01ghbkd0frb9k95cnhwd1bxpvk"
142
+ expected_request_body = ReadsFixtures.read_raw_json_fixture("request/revoke")
143
+ expected_response_body = ReadsFixtures.read_raw_json_fixture("response/revoked_entity")
144
+ expected_url = "/client-tokens/ctkn_01ghbkd0frb9k95cnhwd1bxpvk"
145
+
146
+ expected_url = f"{test_client.base_url}{expected_url}"
147
+ mock_requests.patch(expected_url, status_code=200, text=expected_response_body)
148
+
149
+ response = test_client.client.client_tokens.revoke(client_token_id)
150
+ response_json = test_client.client.client_tokens.response.json()
151
+ request_json = test_client.client.payload
152
+ last_request = mock_requests.last_request
153
+
154
+ assert isinstance(response, ClientToken)
155
+ assert last_request is not None
156
+ assert last_request.method == "PATCH"
157
+ assert test_client.client.status_code == 200
158
+ assert (
159
+ unquote(last_request.url) == expected_url
160
+ ), "The URL does not match the expected URL, verify the query string is correct"
161
+ assert loads(request_json) == loads(
162
+ expected_request_body
163
+ ), "The request JSON doesn't match the expected fixture JSON"
164
+ assert response_json == loads(
165
+ str(expected_response_body)
166
+ ), "The response JSON doesn't match the expected fixture JSON"
167
+
168
+ @mark.parametrize(
169
+ "operation, expected_response_status, expected_response_body, expected_url",
170
+ [
171
+ (
172
+ ListClientTokens(),
173
+ 200,
174
+ ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
175
+ "/client-tokens",
176
+ ),
177
+ (
178
+ ListClientTokens(Pager()),
179
+ 200,
180
+ ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
181
+ "/client-tokens?order_by=id[asc]&per_page=50",
182
+ ),
183
+ (
184
+ ListClientTokens(Pager(after="ctkn_01ghbkd0frb9k95cnhwd1bxpvk")),
185
+ 200,
186
+ ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
187
+ "/client-tokens?after=ctkn_01ghbkd0frb9k95cnhwd1bxpvk&order_by=id[asc]&per_page=50",
188
+ ),
189
+ (
190
+ ListClientTokens(statuses=[ClientTokenStatus.Active]),
191
+ 200,
192
+ ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
193
+ "/client-tokens?status=active",
194
+ ),
195
+ (
196
+ ListClientTokens(statuses=[ClientTokenStatus.Revoked]),
197
+ 200,
198
+ ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
199
+ "/client-tokens?status=revoked",
200
+ ),
201
+ ],
202
+ ids=[
203
+ "List client tokens without pagination",
204
+ "List client tokens with default pagination",
205
+ "List paginated client tokens after specified client token id",
206
+ "List client tokens filtered by active status",
207
+ "List client tokens filtered by revoked status",
208
+ ],
209
+ )
210
+ def test_list_client_tokens_returns_expected_response(
211
+ self,
212
+ test_client,
213
+ mock_requests,
214
+ operation,
215
+ expected_response_status,
216
+ expected_response_body,
217
+ expected_url,
218
+ ):
219
+ expected_url = f"{test_client.base_url}{expected_url}"
220
+ mock_requests.get(expected_url, status_code=expected_response_status, text=expected_response_body)
221
+
222
+ response = test_client.client.client_tokens.list(operation)
223
+ last_request = mock_requests.last_request
224
+
225
+ assert isinstance(response, ClientTokenCollection)
226
+ assert last_request is not None
227
+ assert last_request.method == "GET"
228
+ assert test_client.client.status_code == expected_response_status
229
+ assert (
230
+ unquote(last_request.url) == expected_url
231
+ ), "The URL does not match the expected URL, verify the query string is correct"
232
+ assert loads(PayloadEncoder().encode(response.items[0])) == loads(expected_response_body)["data"][0]
233
+
234
+ def test_list_client_tokens_can_paginate(
235
+ self,
236
+ test_client,
237
+ mock_requests,
238
+ ):
239
+ mock_requests.get(
240
+ f"{test_client.base_url}/client-tokens",
241
+ status_code=200,
242
+ text=ReadsFixtures.read_raw_json_fixture("response/list_page_one"),
243
+ )
244
+
245
+ mock_requests.get(
246
+ f"{test_client.base_url}/client-tokens?after=ctkn_03ghbkd0frb9k95cnhwd1bxpvk",
247
+ status_code=200,
248
+ text=ReadsFixtures.read_raw_json_fixture("response/list_page_two"),
249
+ )
250
+
251
+ response = test_client.client.client_tokens.list()
252
+
253
+ assert isinstance(response, ClientTokenCollection)
254
+
255
+ all = []
256
+ for client_token in response:
257
+ all.append(client_token)
258
+
259
+ assert len(all) == 6
260
+
261
+ @mark.parametrize(
262
+ "client_token_id, expected_response_status, expected_response_body, expected_url",
263
+ [
264
+ (
265
+ "dsc_01h83xenpcfjyhkqr4x214m02x",
266
+ 200,
267
+ ReadsFixtures.read_raw_json_fixture("response/full_entity"),
268
+ "/client-tokens/dsc_01h83xenpcfjyhkqr4x214m02x",
269
+ )
270
+ ],
271
+ ids=["Get client token"],
272
+ )
273
+ def test_get_client_tokens_returns_expected_response(
274
+ self,
275
+ test_client,
276
+ mock_requests,
277
+ client_token_id,
278
+ expected_response_status,
279
+ expected_response_body,
280
+ expected_url,
281
+ ):
282
+ expected_url = f"{test_client.base_url}{expected_url}"
283
+ mock_requests.get(expected_url, status_code=expected_response_status, text=expected_response_body)
284
+
285
+ response = test_client.client.client_tokens.get(client_token_id)
286
+ response_json = test_client.client.client_tokens.response.json()
287
+ last_request = mock_requests.last_request
288
+
289
+ assert isinstance(response, ClientToken)
290
+ assert last_request is not None
291
+ assert last_request.method == "GET"
292
+ assert test_client.client.status_code == expected_response_status
293
+ assert (
294
+ unquote(last_request.url) == expected_url
295
+ ), "The URL does not match the expected URL, verify the query string is correct"
296
+ assert response_json == loads(
297
+ str(expected_response_body)
298
+ ), "The response JSON generated by ResponseParser() doesn't match the expected fixture JSON"