gmt-python-sdk 0.26.0__tar.gz → 0.27.1__tar.gz

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 (129) hide show
  1. gmt_python_sdk-0.27.1/.release-please-manifest.json +3 -0
  2. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/CHANGELOG.md +16 -0
  3. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/PKG-INFO +1 -1
  4. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/api.md +14 -2
  5. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/pyproject.toml +1 -1
  6. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/__init__.py +1 -0
  7. gmt_python_sdk-0.27.1/src/gmt/_utils/_path.py +127 -0
  8. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_version.py +1 -1
  9. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/accounts.py +3 -3
  10. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/profile/profile.py +8 -8
  11. gmt_python_sdk-0.27.1/src/gmt/resources/profile/referral/__init__.py +33 -0
  12. {gmt_python_sdk-0.26.0/src/gmt/resources/profile → gmt_python_sdk-0.27.1/src/gmt/resources/profile/referral}/referral.py +47 -9
  13. gmt_python_sdk-0.27.1/src/gmt/resources/profile/referral/transaction.py +200 -0
  14. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/purchases/bulk.py +5 -5
  15. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/purchases/purchases.py +7 -7
  16. gmt_python_sdk-0.27.1/src/gmt/types/profile/referral/__init__.py +6 -0
  17. gmt_python_sdk-0.27.1/src/gmt/types/profile/referral/transaction_list_params.py +15 -0
  18. gmt_python_sdk-0.27.1/src/gmt/types/profile/referral/transaction_list_response.py +45 -0
  19. gmt_python_sdk-0.27.1/tests/api_resources/profile/referral/test_transaction.py +99 -0
  20. gmt_python_sdk-0.27.1/tests/api_resources/purchases/__init__.py +1 -0
  21. gmt_python_sdk-0.27.1/tests/test_utils/test_path.py +89 -0
  22. gmt_python_sdk-0.26.0/.release-please-manifest.json +0 -3
  23. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/.gitignore +0 -0
  24. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/CONTRIBUTING.md +0 -0
  25. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/LICENSE +0 -0
  26. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/README.md +0 -0
  27. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/SECURITY.md +0 -0
  28. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/bin/check-release-environment +0 -0
  29. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/bin/publish-pypi +0 -0
  30. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/examples/.keep +0 -0
  31. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/release-please-config.json +0 -0
  32. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/requirements-dev.lock +0 -0
  33. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/__init__.py +0 -0
  34. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_base_client.py +0 -0
  35. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_client.py +0 -0
  36. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_compat.py +0 -0
  37. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_constants.py +0 -0
  38. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_exceptions.py +0 -0
  39. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_files.py +0 -0
  40. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_models.py +0 -0
  41. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_qs.py +0 -0
  42. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_resource.py +0 -0
  43. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_response.py +0 -0
  44. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_streaming.py +0 -0
  45. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_types.py +0 -0
  46. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_compat.py +0 -0
  47. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_datetime_parse.py +0 -0
  48. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_json.py +0 -0
  49. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_logs.py +0 -0
  50. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_proxy.py +0 -0
  51. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_reflection.py +0 -0
  52. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_resources_proxy.py +0 -0
  53. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_streams.py +0 -0
  54. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_sync.py +0 -0
  55. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_transform.py +0 -0
  56. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_typing.py +0 -0
  57. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/_utils/_utils.py +0 -0
  58. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/lib/.keep +0 -0
  59. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/pagination.py +0 -0
  60. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/py.typed +0 -0
  61. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/__init__.py +0 -0
  62. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/profile/__init__.py +0 -0
  63. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/profile/discount.py +0 -0
  64. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/purchases/__init__.py +0 -0
  65. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/service.py +0 -0
  66. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/resources/webhooks.py +0 -0
  67. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/__init__.py +0 -0
  68. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/account_list_countries_params.py +0 -0
  69. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/account_list_countries_response.py +0 -0
  70. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/account_list_params.py +0 -0
  71. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/account_list_response.py +0 -0
  72. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/account_retrieve_response.py +0 -0
  73. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile/__init__.py +0 -0
  74. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile/discount_retrieve_response.py +0 -0
  75. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile/referral_retrieve_response.py +0 -0
  76. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile/referral_transfer_balance_params.py +0 -0
  77. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile/referral_transfer_balance_response.py +0 -0
  78. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_change_login_params.py +0 -0
  79. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_change_login_response.py +0 -0
  80. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_change_password_params.py +0 -0
  81. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_change_password_response.py +0 -0
  82. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_retrieve_response.py +0 -0
  83. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/profile_unbind_telegram_response.py +0 -0
  84. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_create_params.py +0 -0
  85. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_create_response.py +0 -0
  86. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_list_params.py +0 -0
  87. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_list_response.py +0 -0
  88. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_refund_response.py +0 -0
  89. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_request_verification_code_params.py +0 -0
  90. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_request_verification_code_response.py +0 -0
  91. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchase_retrieve_response.py +0 -0
  92. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchases/__init__.py +0 -0
  93. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchases/bulk_create_params.py +0 -0
  94. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchases/bulk_create_response.py +0 -0
  95. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/purchases/bulk_retrieve_response.py +0 -0
  96. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/service_get_server_time_response.py +0 -0
  97. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/service_health_check_response.py +0 -0
  98. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/webhook_test_params.py +0 -0
  99. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/src/gmt/types/webhook_test_response.py +0 -0
  100. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/__init__.py +0 -0
  101. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/__init__.py +0 -0
  102. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/profile/__init__.py +0 -0
  103. {gmt_python_sdk-0.26.0/tests/api_resources/purchases → gmt_python_sdk-0.27.1/tests/api_resources/profile/referral}/__init__.py +0 -0
  104. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/profile/test_discount.py +0 -0
  105. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/profile/test_referral.py +0 -0
  106. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/purchases/test_bulk.py +0 -0
  107. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/test_accounts.py +0 -0
  108. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/test_profile.py +0 -0
  109. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/test_purchases.py +0 -0
  110. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/test_service.py +0 -0
  111. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/api_resources/test_webhooks.py +0 -0
  112. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/conftest.py +0 -0
  113. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/sample_file.txt +0 -0
  114. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_client.py +0 -0
  115. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_deepcopy.py +0 -0
  116. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_extract_files.py +0 -0
  117. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_files.py +0 -0
  118. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_models.py +0 -0
  119. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_qs.py +0 -0
  120. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_required_args.py +0 -0
  121. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_response.py +0 -0
  122. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_streaming.py +0 -0
  123. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_transform.py +0 -0
  124. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_utils/test_datetime_parse.py +0 -0
  125. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_utils/test_json.py +0 -0
  126. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_utils/test_proxy.py +0 -0
  127. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/test_utils/test_typing.py +0 -0
  128. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/tests/utils.py +0 -0
  129. {gmt_python_sdk-0.26.0 → gmt_python_sdk-0.27.1}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.27.1"
3
+ }
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.27.1 (2026-03-20)
4
+
5
+ Full Changelog: [v0.27.0...v0.27.1](https://github.com/cameo6/gmt-python-sdk/compare/v0.27.0...v0.27.1)
6
+
7
+ ### Bug Fixes
8
+
9
+ * sanitize endpoint path params ([6d2a959](https://github.com/cameo6/gmt-python-sdk/commit/6d2a959bae599064b628dfeb5bb5069b337c0cdf))
10
+
11
+ ## 0.27.0 (2026-03-19)
12
+
13
+ Full Changelog: [v0.26.0...v0.27.0](https://github.com/cameo6/gmt-python-sdk/compare/v0.26.0...v0.27.0)
14
+
15
+ ### Features
16
+
17
+ * **api:** manual updates ([ff595bf](https://github.com/cameo6/gmt-python-sdk/commit/ff595bf16b8743cae98796cc0faead1b1918b924))
18
+
3
19
  ## 0.26.0 (2026-03-19)
4
20
 
5
21
  Full Changelog: [v0.25.0...v0.26.0](https://github.com/cameo6/gmt-python-sdk/compare/v0.25.0...v0.26.0)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gmt-python-sdk
3
- Version: 0.26.0
3
+ Version: 0.27.1
4
4
  Summary: The official Python library for the gmt API
5
5
  Project-URL: Homepage, https://github.com/cameo6/gmt-python-sdk
6
6
  Project-URL: Repository, https://github.com/cameo6/gmt-python-sdk
@@ -67,8 +67,20 @@ from gmt.types.profile import ReferralRetrieveResponse, ReferralTransferBalanceR
67
67
 
68
68
  Methods:
69
69
 
70
- - <code title="get /v1/profile/referral">client.profile.referral.<a href="./src/gmt/resources/profile/referral.py">retrieve</a>() -> <a href="./src/gmt/types/profile/referral_retrieve_response.py">ReferralRetrieveResponse</a></code>
71
- - <code title="post /v1/profile/referral/transfer-balance">client.profile.referral.<a href="./src/gmt/resources/profile/referral.py">transfer_balance</a>(\*\*<a href="src/gmt/types/profile/referral_transfer_balance_params.py">params</a>) -> <a href="./src/gmt/types/profile/referral_transfer_balance_response.py">ReferralTransferBalanceResponse</a></code>
70
+ - <code title="get /v1/profile/referral">client.profile.referral.<a href="./src/gmt/resources/profile/referral/referral.py">retrieve</a>() -> <a href="./src/gmt/types/profile/referral_retrieve_response.py">ReferralRetrieveResponse</a></code>
71
+ - <code title="post /v1/profile/referral/transfer-balance">client.profile.referral.<a href="./src/gmt/resources/profile/referral/referral.py">transfer_balance</a>(\*\*<a href="src/gmt/types/profile/referral_transfer_balance_params.py">params</a>) -> <a href="./src/gmt/types/profile/referral_transfer_balance_response.py">ReferralTransferBalanceResponse</a></code>
72
+
73
+ ### Transaction
74
+
75
+ Types:
76
+
77
+ ```python
78
+ from gmt.types.profile.referral import TransactionListResponse
79
+ ```
80
+
81
+ Methods:
82
+
83
+ - <code title="get /v1/profile/referral/transaction">client.profile.referral.transaction.<a href="./src/gmt/resources/profile/referral/transaction.py">list</a>(\*\*<a href="src/gmt/types/profile/referral/transaction_list_params.py">params</a>) -> <a href="./src/gmt/types/profile/referral/transaction_list_response.py">SyncPageNumber[TransactionListResponse]</a></code>
72
84
 
73
85
  # Purchases
74
86
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gmt-python-sdk"
3
- version = "0.26.0"
3
+ version = "0.27.1"
4
4
  description = "The official Python library for the gmt API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -1,3 +1,4 @@
1
+ from ._path import path_template as path_template
1
2
  from ._sync import asyncify as asyncify
2
3
  from ._proxy import LazyProxy as LazyProxy
3
4
  from ._utils import (
@@ -0,0 +1,127 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import (
5
+ Any,
6
+ Mapping,
7
+ Callable,
8
+ )
9
+ from urllib.parse import quote
10
+
11
+ # Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E).
12
+ _DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$")
13
+
14
+ _PLACEHOLDER_RE = re.compile(r"\{(\w+)\}")
15
+
16
+
17
+ def _quote_path_segment_part(value: str) -> str:
18
+ """Percent-encode `value` for use in a URI path segment.
19
+
20
+ Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe.
21
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
22
+ """
23
+ # quote() already treats unreserved characters (letters, digits, and -._~)
24
+ # as safe, so we only need to add sub-delims, ':', and '@'.
25
+ # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted.
26
+ return quote(value, safe="!$&'()*+,;=:@")
27
+
28
+
29
+ def _quote_query_part(value: str) -> str:
30
+ """Percent-encode `value` for use in a URI query string.
31
+
32
+ Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe.
33
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.4
34
+ """
35
+ return quote(value, safe="!$'()*+,;:@/?")
36
+
37
+
38
+ def _quote_fragment_part(value: str) -> str:
39
+ """Percent-encode `value` for use in a URI fragment.
40
+
41
+ Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe.
42
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.5
43
+ """
44
+ return quote(value, safe="!$&'()*+,;=:@/?")
45
+
46
+
47
+ def _interpolate(
48
+ template: str,
49
+ values: Mapping[str, Any],
50
+ quoter: Callable[[str], str],
51
+ ) -> str:
52
+ """Replace {name} placeholders in `template`, quoting each value with `quoter`.
53
+
54
+ Placeholder names are looked up in `values`.
55
+
56
+ Raises:
57
+ KeyError: If a placeholder is not found in `values`.
58
+ """
59
+ # re.split with a capturing group returns alternating
60
+ # [text, name, text, name, ..., text] elements.
61
+ parts = _PLACEHOLDER_RE.split(template)
62
+
63
+ for i in range(1, len(parts), 2):
64
+ name = parts[i]
65
+ if name not in values:
66
+ raise KeyError(f"a value for placeholder {{{name}}} was not provided")
67
+ val = values[name]
68
+ if val is None:
69
+ parts[i] = "null"
70
+ elif isinstance(val, bool):
71
+ parts[i] = "true" if val else "false"
72
+ else:
73
+ parts[i] = quoter(str(values[name]))
74
+
75
+ return "".join(parts)
76
+
77
+
78
+ def path_template(template: str, /, **kwargs: Any) -> str:
79
+ """Interpolate {name} placeholders in `template` from keyword arguments.
80
+
81
+ Args:
82
+ template: The template string containing {name} placeholders.
83
+ **kwargs: Keyword arguments to interpolate into the template.
84
+
85
+ Returns:
86
+ The template with placeholders interpolated and percent-encoded.
87
+
88
+ Safe characters for percent-encoding are dependent on the URI component.
89
+ Placeholders in path and fragment portions are percent-encoded where the `segment`
90
+ and `fragment` sets from RFC 3986 respectively are considered safe.
91
+ Placeholders in the query portion are percent-encoded where the `query` set from
92
+ RFC 3986 §3.3 is considered safe except for = and & characters.
93
+
94
+ Raises:
95
+ KeyError: If a placeholder is not found in `kwargs`.
96
+ ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments).
97
+ """
98
+ # Split the template into path, query, and fragment portions.
99
+ fragment_template: str | None = None
100
+ query_template: str | None = None
101
+
102
+ rest = template
103
+ if "#" in rest:
104
+ rest, fragment_template = rest.split("#", 1)
105
+ if "?" in rest:
106
+ rest, query_template = rest.split("?", 1)
107
+ path_template = rest
108
+
109
+ # Interpolate each portion with the appropriate quoting rules.
110
+ path_result = _interpolate(path_template, kwargs, _quote_path_segment_part)
111
+
112
+ # Reject dot-segments (. and ..) in the final assembled path. The check
113
+ # runs after interpolation so that adjacent placeholders or a mix of static
114
+ # text and placeholders that together form a dot-segment are caught.
115
+ # Also reject percent-encoded dot-segments to protect against incorrectly
116
+ # implemented normalization in servers/proxies.
117
+ for segment in path_result.split("/"):
118
+ if _DOT_SEGMENT_RE.match(segment):
119
+ raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed")
120
+
121
+ result = path_result
122
+ if query_template is not None:
123
+ result += "?" + _interpolate(query_template, kwargs, _quote_query_part)
124
+ if fragment_template is not None:
125
+ result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part)
126
+
127
+ return result
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "gmt"
4
- __version__ = "0.26.0" # x-release-please-version
4
+ __version__ = "0.27.1" # x-release-please-version
@@ -8,7 +8,7 @@ import httpx
8
8
 
9
9
  from ..types import account_list_params, account_list_countries_params
10
10
  from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
11
- from .._utils import maybe_transform
11
+ from .._utils import path_template, maybe_transform
12
12
  from .._compat import cached_property
13
13
  from .._resource import SyncAPIResource, AsyncAPIResource
14
14
  from .._response import (
@@ -100,7 +100,7 @@ class AccountsResource(SyncAPIResource):
100
100
  if not country_code:
101
101
  raise ValueError(f"Expected a non-empty value for `country_code` but received {country_code!r}")
102
102
  return self._get(
103
- f"/v1/accounts/{country_code}",
103
+ path_template("/v1/accounts/{country_code}", country_code=country_code),
104
104
  options=make_request_options(
105
105
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
106
106
  ),
@@ -322,7 +322,7 @@ class AsyncAccountsResource(AsyncAPIResource):
322
322
  if not country_code:
323
323
  raise ValueError(f"Expected a non-empty value for `country_code` but received {country_code!r}")
324
324
  return await self._get(
325
- f"/v1/accounts/{country_code}",
325
+ path_template("/v1/accounts/{country_code}", country_code=country_code),
326
326
  options=make_request_options(
327
327
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
328
328
  ),
@@ -15,14 +15,6 @@ from .discount import (
15
15
  DiscountResourceWithStreamingResponse,
16
16
  AsyncDiscountResourceWithStreamingResponse,
17
17
  )
18
- from .referral import (
19
- ReferralResource,
20
- AsyncReferralResource,
21
- ReferralResourceWithRawResponse,
22
- AsyncReferralResourceWithRawResponse,
23
- ReferralResourceWithStreamingResponse,
24
- AsyncReferralResourceWithStreamingResponse,
25
- )
26
18
  from ..._compat import cached_property
27
19
  from ..._resource import SyncAPIResource, AsyncAPIResource
28
20
  from ..._response import (
@@ -32,6 +24,14 @@ from ..._response import (
32
24
  async_to_streamed_response_wrapper,
33
25
  )
34
26
  from ..._base_client import make_request_options
27
+ from .referral.referral import (
28
+ ReferralResource,
29
+ AsyncReferralResource,
30
+ ReferralResourceWithRawResponse,
31
+ AsyncReferralResourceWithRawResponse,
32
+ ReferralResourceWithStreamingResponse,
33
+ AsyncReferralResourceWithStreamingResponse,
34
+ )
35
35
  from ...types.profile_retrieve_response import ProfileRetrieveResponse
36
36
  from ...types.profile_change_login_response import ProfileChangeLoginResponse
37
37
  from ...types.profile_change_password_response import ProfileChangePasswordResponse
@@ -0,0 +1,33 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from .referral import (
4
+ ReferralResource,
5
+ AsyncReferralResource,
6
+ ReferralResourceWithRawResponse,
7
+ AsyncReferralResourceWithRawResponse,
8
+ ReferralResourceWithStreamingResponse,
9
+ AsyncReferralResourceWithStreamingResponse,
10
+ )
11
+ from .transaction import (
12
+ TransactionResource,
13
+ AsyncTransactionResource,
14
+ TransactionResourceWithRawResponse,
15
+ AsyncTransactionResourceWithRawResponse,
16
+ TransactionResourceWithStreamingResponse,
17
+ AsyncTransactionResourceWithStreamingResponse,
18
+ )
19
+
20
+ __all__ = [
21
+ "TransactionResource",
22
+ "AsyncTransactionResource",
23
+ "TransactionResourceWithRawResponse",
24
+ "AsyncTransactionResourceWithRawResponse",
25
+ "TransactionResourceWithStreamingResponse",
26
+ "AsyncTransactionResourceWithStreamingResponse",
27
+ "ReferralResource",
28
+ "AsyncReferralResource",
29
+ "ReferralResourceWithRawResponse",
30
+ "AsyncReferralResourceWithRawResponse",
31
+ "ReferralResourceWithStreamingResponse",
32
+ "AsyncReferralResourceWithStreamingResponse",
33
+ ]
@@ -4,20 +4,28 @@ from __future__ import annotations
4
4
 
5
5
  import httpx
6
6
 
7
- from ..._types import Body, Query, Headers, NotGiven, not_given
8
- from ..._utils import maybe_transform, async_maybe_transform
9
- from ..._compat import cached_property
10
- from ..._resource import SyncAPIResource, AsyncAPIResource
11
- from ..._response import (
7
+ from ...._types import Body, Query, Headers, NotGiven, not_given
8
+ from ...._utils import maybe_transform, async_maybe_transform
9
+ from ...._compat import cached_property
10
+ from .transaction import (
11
+ TransactionResource,
12
+ AsyncTransactionResource,
13
+ TransactionResourceWithRawResponse,
14
+ AsyncTransactionResourceWithRawResponse,
15
+ TransactionResourceWithStreamingResponse,
16
+ AsyncTransactionResourceWithStreamingResponse,
17
+ )
18
+ from ...._resource import SyncAPIResource, AsyncAPIResource
19
+ from ...._response import (
12
20
  to_raw_response_wrapper,
13
21
  to_streamed_response_wrapper,
14
22
  async_to_raw_response_wrapper,
15
23
  async_to_streamed_response_wrapper,
16
24
  )
17
- from ..._base_client import make_request_options
18
- from ...types.profile import referral_transfer_balance_params
19
- from ...types.profile.referral_retrieve_response import ReferralRetrieveResponse
20
- from ...types.profile.referral_transfer_balance_response import ReferralTransferBalanceResponse
25
+ from ...._base_client import make_request_options
26
+ from ....types.profile import referral_transfer_balance_params
27
+ from ....types.profile.referral_retrieve_response import ReferralRetrieveResponse
28
+ from ....types.profile.referral_transfer_balance_response import ReferralTransferBalanceResponse
21
29
 
22
30
  __all__ = ["ReferralResource", "AsyncReferralResource"]
23
31
 
@@ -25,6 +33,11 @@ __all__ = ["ReferralResource", "AsyncReferralResource"]
25
33
  class ReferralResource(SyncAPIResource):
26
34
  """User profile management."""
27
35
 
36
+ @cached_property
37
+ def transaction(self) -> TransactionResource:
38
+ """User profile management."""
39
+ return TransactionResource(self._client)
40
+
28
41
  @cached_property
29
42
  def with_raw_response(self) -> ReferralResourceWithRawResponse:
30
43
  """
@@ -104,6 +117,11 @@ class ReferralResource(SyncAPIResource):
104
117
  class AsyncReferralResource(AsyncAPIResource):
105
118
  """User profile management."""
106
119
 
120
+ @cached_property
121
+ def transaction(self) -> AsyncTransactionResource:
122
+ """User profile management."""
123
+ return AsyncTransactionResource(self._client)
124
+
107
125
  @cached_property
108
126
  def with_raw_response(self) -> AsyncReferralResourceWithRawResponse:
109
127
  """
@@ -193,6 +211,11 @@ class ReferralResourceWithRawResponse:
193
211
  referral.transfer_balance,
194
212
  )
195
213
 
214
+ @cached_property
215
+ def transaction(self) -> TransactionResourceWithRawResponse:
216
+ """User profile management."""
217
+ return TransactionResourceWithRawResponse(self._referral.transaction)
218
+
196
219
 
197
220
  class AsyncReferralResourceWithRawResponse:
198
221
  def __init__(self, referral: AsyncReferralResource) -> None:
@@ -205,6 +228,11 @@ class AsyncReferralResourceWithRawResponse:
205
228
  referral.transfer_balance,
206
229
  )
207
230
 
231
+ @cached_property
232
+ def transaction(self) -> AsyncTransactionResourceWithRawResponse:
233
+ """User profile management."""
234
+ return AsyncTransactionResourceWithRawResponse(self._referral.transaction)
235
+
208
236
 
209
237
  class ReferralResourceWithStreamingResponse:
210
238
  def __init__(self, referral: ReferralResource) -> None:
@@ -217,6 +245,11 @@ class ReferralResourceWithStreamingResponse:
217
245
  referral.transfer_balance,
218
246
  )
219
247
 
248
+ @cached_property
249
+ def transaction(self) -> TransactionResourceWithStreamingResponse:
250
+ """User profile management."""
251
+ return TransactionResourceWithStreamingResponse(self._referral.transaction)
252
+
220
253
 
221
254
  class AsyncReferralResourceWithStreamingResponse:
222
255
  def __init__(self, referral: AsyncReferralResource) -> None:
@@ -228,3 +261,8 @@ class AsyncReferralResourceWithStreamingResponse:
228
261
  self.transfer_balance = async_to_streamed_response_wrapper(
229
262
  referral.transfer_balance,
230
263
  )
264
+
265
+ @cached_property
266
+ def transaction(self) -> AsyncTransactionResourceWithStreamingResponse:
267
+ """User profile management."""
268
+ return AsyncTransactionResourceWithStreamingResponse(self._referral.transaction)
@@ -0,0 +1,200 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from __future__ import annotations
4
+
5
+ import httpx
6
+
7
+ from ...._types import Body, Query, Headers, NotGiven, not_given
8
+ from ...._utils import maybe_transform
9
+ from ...._compat import cached_property
10
+ from ...._resource import SyncAPIResource, AsyncAPIResource
11
+ from ...._response import (
12
+ to_raw_response_wrapper,
13
+ to_streamed_response_wrapper,
14
+ async_to_raw_response_wrapper,
15
+ async_to_streamed_response_wrapper,
16
+ )
17
+ from ....pagination import SyncPageNumber, AsyncPageNumber
18
+ from ...._base_client import AsyncPaginator, make_request_options
19
+ from ....types.profile.referral import transaction_list_params
20
+ from ....types.profile.referral.transaction_list_response import TransactionListResponse
21
+
22
+ __all__ = ["TransactionResource", "AsyncTransactionResource"]
23
+
24
+
25
+ class TransactionResource(SyncAPIResource):
26
+ """User profile management."""
27
+
28
+ @cached_property
29
+ def with_raw_response(self) -> TransactionResourceWithRawResponse:
30
+ """
31
+ This property can be used as a prefix for any HTTP method call to return
32
+ the raw response object instead of the parsed content.
33
+
34
+ For more information, see https://www.github.com/cameo6/gmt-python-sdk#accessing-raw-response-data-eg-headers
35
+ """
36
+ return TransactionResourceWithRawResponse(self)
37
+
38
+ @cached_property
39
+ def with_streaming_response(self) -> TransactionResourceWithStreamingResponse:
40
+ """
41
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
42
+
43
+ For more information, see https://www.github.com/cameo6/gmt-python-sdk#with_streaming_response
44
+ """
45
+ return TransactionResourceWithStreamingResponse(self)
46
+
47
+ def list(
48
+ self,
49
+ *,
50
+ page: int,
51
+ page_size: int,
52
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
53
+ # The extra values given here take precedence over values defined on the client or passed to this method.
54
+ extra_headers: Headers | None = None,
55
+ extra_query: Query | None = None,
56
+ extra_body: Body | None = None,
57
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
58
+ ) -> SyncPageNumber[TransactionListResponse]:
59
+ """
60
+ Returns paginated referral transaction history for the authenticated user,
61
+ ordered by newest first.
62
+
63
+ Args:
64
+ page: Page number.
65
+
66
+ page_size: Number of items per page.
67
+
68
+ extra_headers: Send extra headers
69
+
70
+ extra_query: Add additional query parameters to the request
71
+
72
+ extra_body: Add additional JSON properties to the request
73
+
74
+ timeout: Override the client-level default timeout for this request, in seconds
75
+ """
76
+ return self._get_api_list(
77
+ "/v1/profile/referral/transaction",
78
+ page=SyncPageNumber[TransactionListResponse],
79
+ options=make_request_options(
80
+ extra_headers=extra_headers,
81
+ extra_query=extra_query,
82
+ extra_body=extra_body,
83
+ timeout=timeout,
84
+ query=maybe_transform(
85
+ {
86
+ "page": page,
87
+ "page_size": page_size,
88
+ },
89
+ transaction_list_params.TransactionListParams,
90
+ ),
91
+ ),
92
+ model=TransactionListResponse,
93
+ )
94
+
95
+
96
+ class AsyncTransactionResource(AsyncAPIResource):
97
+ """User profile management."""
98
+
99
+ @cached_property
100
+ def with_raw_response(self) -> AsyncTransactionResourceWithRawResponse:
101
+ """
102
+ This property can be used as a prefix for any HTTP method call to return
103
+ the raw response object instead of the parsed content.
104
+
105
+ For more information, see https://www.github.com/cameo6/gmt-python-sdk#accessing-raw-response-data-eg-headers
106
+ """
107
+ return AsyncTransactionResourceWithRawResponse(self)
108
+
109
+ @cached_property
110
+ def with_streaming_response(self) -> AsyncTransactionResourceWithStreamingResponse:
111
+ """
112
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
113
+
114
+ For more information, see https://www.github.com/cameo6/gmt-python-sdk#with_streaming_response
115
+ """
116
+ return AsyncTransactionResourceWithStreamingResponse(self)
117
+
118
+ def list(
119
+ self,
120
+ *,
121
+ page: int,
122
+ page_size: int,
123
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
124
+ # The extra values given here take precedence over values defined on the client or passed to this method.
125
+ extra_headers: Headers | None = None,
126
+ extra_query: Query | None = None,
127
+ extra_body: Body | None = None,
128
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
129
+ ) -> AsyncPaginator[TransactionListResponse, AsyncPageNumber[TransactionListResponse]]:
130
+ """
131
+ Returns paginated referral transaction history for the authenticated user,
132
+ ordered by newest first.
133
+
134
+ Args:
135
+ page: Page number.
136
+
137
+ page_size: Number of items per page.
138
+
139
+ extra_headers: Send extra headers
140
+
141
+ extra_query: Add additional query parameters to the request
142
+
143
+ extra_body: Add additional JSON properties to the request
144
+
145
+ timeout: Override the client-level default timeout for this request, in seconds
146
+ """
147
+ return self._get_api_list(
148
+ "/v1/profile/referral/transaction",
149
+ page=AsyncPageNumber[TransactionListResponse],
150
+ options=make_request_options(
151
+ extra_headers=extra_headers,
152
+ extra_query=extra_query,
153
+ extra_body=extra_body,
154
+ timeout=timeout,
155
+ query=maybe_transform(
156
+ {
157
+ "page": page,
158
+ "page_size": page_size,
159
+ },
160
+ transaction_list_params.TransactionListParams,
161
+ ),
162
+ ),
163
+ model=TransactionListResponse,
164
+ )
165
+
166
+
167
+ class TransactionResourceWithRawResponse:
168
+ def __init__(self, transaction: TransactionResource) -> None:
169
+ self._transaction = transaction
170
+
171
+ self.list = to_raw_response_wrapper(
172
+ transaction.list,
173
+ )
174
+
175
+
176
+ class AsyncTransactionResourceWithRawResponse:
177
+ def __init__(self, transaction: AsyncTransactionResource) -> None:
178
+ self._transaction = transaction
179
+
180
+ self.list = async_to_raw_response_wrapper(
181
+ transaction.list,
182
+ )
183
+
184
+
185
+ class TransactionResourceWithStreamingResponse:
186
+ def __init__(self, transaction: TransactionResource) -> None:
187
+ self._transaction = transaction
188
+
189
+ self.list = to_streamed_response_wrapper(
190
+ transaction.list,
191
+ )
192
+
193
+
194
+ class AsyncTransactionResourceWithStreamingResponse:
195
+ def __init__(self, transaction: AsyncTransactionResource) -> None:
196
+ self._transaction = transaction
197
+
198
+ self.list = async_to_streamed_response_wrapper(
199
+ transaction.list,
200
+ )
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import httpx
6
6
 
7
7
  from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
8
- from ..._utils import maybe_transform, async_maybe_transform
8
+ from ..._utils import path_template, maybe_transform, async_maybe_transform
9
9
  from ..._compat import cached_property
10
10
  from ..._resource import SyncAPIResource, AsyncAPIResource
11
11
  from ..._response import (
@@ -145,7 +145,7 @@ class BulkResource(SyncAPIResource):
145
145
  if not purchase_id:
146
146
  raise ValueError(f"Expected a non-empty value for `purchase_id` but received {purchase_id!r}")
147
147
  return self._get(
148
- f"/v1/purchases/bulk/{purchase_id}",
148
+ path_template("/v1/purchases/bulk/{purchase_id}", purchase_id=purchase_id),
149
149
  options=make_request_options(
150
150
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
151
151
  ),
@@ -180,7 +180,7 @@ class BulkResource(SyncAPIResource):
180
180
  raise ValueError(f"Expected a non-empty value for `purchase_id` but received {purchase_id!r}")
181
181
  extra_headers = {"Accept": "application/zip", **(extra_headers or {})}
182
182
  return self._get(
183
- f"/v1/purchases/bulk/{purchase_id}/download",
183
+ path_template("/v1/purchases/bulk/{purchase_id}/download", purchase_id=purchase_id),
184
184
  options=make_request_options(
185
185
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
186
186
  ),
@@ -303,7 +303,7 @@ class AsyncBulkResource(AsyncAPIResource):
303
303
  if not purchase_id:
304
304
  raise ValueError(f"Expected a non-empty value for `purchase_id` but received {purchase_id!r}")
305
305
  return await self._get(
306
- f"/v1/purchases/bulk/{purchase_id}",
306
+ path_template("/v1/purchases/bulk/{purchase_id}", purchase_id=purchase_id),
307
307
  options=make_request_options(
308
308
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
309
309
  ),
@@ -338,7 +338,7 @@ class AsyncBulkResource(AsyncAPIResource):
338
338
  raise ValueError(f"Expected a non-empty value for `purchase_id` but received {purchase_id!r}")
339
339
  extra_headers = {"Accept": "application/zip", **(extra_headers or {})}
340
340
  return await self._get(
341
- f"/v1/purchases/bulk/{purchase_id}/download",
341
+ path_template("/v1/purchases/bulk/{purchase_id}/download", purchase_id=purchase_id),
342
342
  options=make_request_options(
343
343
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
344
344
  ),