gmt-python-sdk 0.40.1__tar.gz → 0.41.0__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 (154) hide show
  1. gmt_python_sdk-0.41.0/.release-please-manifest.json +3 -0
  2. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/CHANGELOG.md +8 -0
  3. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/PKG-INFO +1 -1
  4. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/pyproject.toml +1 -1
  5. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_models.py +80 -0
  6. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_version.py +1 -1
  7. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_models.py +57 -3
  8. gmt_python_sdk-0.40.1/.release-please-manifest.json +0 -3
  9. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/.gitignore +0 -0
  10. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/CONTRIBUTING.md +0 -0
  11. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/LICENSE +0 -0
  12. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/README.md +0 -0
  13. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/SECURITY.md +0 -0
  14. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/api.md +0 -0
  15. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/bin/check-release-environment +0 -0
  16. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/bin/publish-pypi +0 -0
  17. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/examples/.keep +0 -0
  18. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/release-please-config.json +0 -0
  19. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/requirements-dev.lock +0 -0
  20. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/__init__.py +0 -0
  21. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_base_client.py +0 -0
  22. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_client.py +0 -0
  23. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_compat.py +0 -0
  24. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_constants.py +0 -0
  25. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_exceptions.py +0 -0
  26. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_files.py +0 -0
  27. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_qs.py +0 -0
  28. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_resource.py +0 -0
  29. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_response.py +0 -0
  30. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_streaming.py +0 -0
  31. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_types.py +0 -0
  32. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/__init__.py +0 -0
  33. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_compat.py +0 -0
  34. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_datetime_parse.py +0 -0
  35. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_json.py +0 -0
  36. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_logs.py +0 -0
  37. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_path.py +0 -0
  38. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_proxy.py +0 -0
  39. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_reflection.py +0 -0
  40. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_resources_proxy.py +0 -0
  41. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_streams.py +0 -0
  42. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_sync.py +0 -0
  43. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_transform.py +0 -0
  44. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_typing.py +0 -0
  45. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/_utils/_utils.py +0 -0
  46. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/lib/.keep +0 -0
  47. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/pagination.py +0 -0
  48. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/py.typed +0 -0
  49. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/__init__.py +0 -0
  50. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/accounts.py +0 -0
  51. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/__init__.py +0 -0
  52. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/discount.py +0 -0
  53. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/profile.py +0 -0
  54. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/referral/__init__.py +0 -0
  55. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/referral/referral.py +0 -0
  56. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/profile/referral/transaction.py +0 -0
  57. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/purchases/__init__.py +0 -0
  58. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/purchases/bulk.py +0 -0
  59. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/purchases/purchases.py +0 -0
  60. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/purchases_by_hash.py +0 -0
  61. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/service.py +0 -0
  62. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/telegram/__init__.py +0 -0
  63. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/telegram/purchases.py +0 -0
  64. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/telegram/telegram.py +0 -0
  65. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/resources/webhooks.py +0 -0
  66. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/__init__.py +0 -0
  67. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/account_list_countries_params.py +0 -0
  68. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/account_list_countries_response.py +0 -0
  69. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/account_list_params.py +0 -0
  70. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/account_list_response.py +0 -0
  71. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/account_retrieve_response.py +0 -0
  72. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/__init__.py +0 -0
  73. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/discount_retrieve_response.py +0 -0
  74. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral/__init__.py +0 -0
  75. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral/transaction_list_params.py +0 -0
  76. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral/transaction_list_response.py +0 -0
  77. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral_retrieve_response.py +0 -0
  78. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral_transfer_balance_params.py +0 -0
  79. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile/referral_transfer_balance_response.py +0 -0
  80. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_language_params.py +0 -0
  81. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_language_response.py +0 -0
  82. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_login_params.py +0 -0
  83. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_login_response.py +0 -0
  84. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_password_params.py +0 -0
  85. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_change_password_response.py +0 -0
  86. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_retrieve_response.py +0 -0
  87. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/profile_unbind_telegram_response.py +0 -0
  88. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_create_params.py +0 -0
  89. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_create_response.py +0 -0
  90. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_list_params.py +0 -0
  91. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_list_response.py +0 -0
  92. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_refund_response.py +0 -0
  93. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_request_verification_code_params.py +0 -0
  94. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_request_verification_code_response.py +0 -0
  95. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchase_retrieve_response.py +0 -0
  96. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases/__init__.py +0 -0
  97. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases/bulk_create_params.py +0 -0
  98. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases/bulk_create_response.py +0 -0
  99. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases/bulk_retrieve_response.py +0 -0
  100. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases_by_hash_request_verification_code_params.py +0 -0
  101. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases_by_hash_request_verification_code_response.py +0 -0
  102. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/purchases_by_hash_retrieve_response.py +0 -0
  103. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/service_get_server_time_response.py +0 -0
  104. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/service_health_check_response.py +0 -0
  105. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/__init__.py +0 -0
  106. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_create_premium_params.py +0 -0
  107. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_create_premium_response.py +0 -0
  108. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_create_stars_params.py +0 -0
  109. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_create_stars_response.py +0 -0
  110. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_list_premium_params.py +0 -0
  111. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_list_premium_response.py +0 -0
  112. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_list_stars_params.py +0 -0
  113. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram/purchase_list_stars_response.py +0 -0
  114. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram_get_premium_price_params.py +0 -0
  115. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram_get_premium_price_response.py +0 -0
  116. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram_get_stars_price_params.py +0 -0
  117. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/telegram_get_stars_price_response.py +0 -0
  118. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/webhook_test_params.py +0 -0
  119. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/src/gmt/types/webhook_test_response.py +0 -0
  120. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/__init__.py +0 -0
  121. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/__init__.py +0 -0
  122. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/profile/__init__.py +0 -0
  123. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/profile/referral/__init__.py +0 -0
  124. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/profile/referral/test_transaction.py +0 -0
  125. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/profile/test_discount.py +0 -0
  126. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/profile/test_referral.py +0 -0
  127. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/purchases/__init__.py +0 -0
  128. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/purchases/test_bulk.py +0 -0
  129. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/telegram/__init__.py +0 -0
  130. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/telegram/test_purchases.py +0 -0
  131. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_accounts.py +0 -0
  132. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_profile.py +0 -0
  133. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_purchases.py +0 -0
  134. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_purchases_by_hash.py +0 -0
  135. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_service.py +0 -0
  136. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_telegram.py +0 -0
  137. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/api_resources/test_webhooks.py +0 -0
  138. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/conftest.py +0 -0
  139. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/sample_file.txt +0 -0
  140. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_client.py +0 -0
  141. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_extract_files.py +0 -0
  142. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_files.py +0 -0
  143. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_qs.py +0 -0
  144. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_required_args.py +0 -0
  145. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_response.py +0 -0
  146. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_streaming.py +0 -0
  147. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_transform.py +0 -0
  148. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_utils/test_datetime_parse.py +0 -0
  149. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_utils/test_json.py +0 -0
  150. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_utils/test_path.py +0 -0
  151. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_utils/test_proxy.py +0 -0
  152. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/test_utils/test_typing.py +0 -0
  153. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/tests/utils.py +0 -0
  154. {gmt_python_sdk-0.40.1 → gmt_python_sdk-0.41.0}/uv.lock +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.41.0"
3
+ }
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.41.0 (2026-05-12)
4
+
5
+ Full Changelog: [v0.40.1...v0.41.0](https://github.com/cameo6/gmt-python-sdk/compare/v0.40.1...v0.41.0)
6
+
7
+ ### Features
8
+
9
+ * **internal/types:** support eagerly validating pydantic iterators ([6f57eab](https://github.com/cameo6/gmt-python-sdk/commit/6f57eab5d36d8ebe7e1da5a46b3ac0cf66e82ed4))
10
+
3
11
  ## 0.40.1 (2026-05-09)
4
12
 
5
13
  Full Changelog: [v0.40.0...v0.40.1](https://github.com/cameo6/gmt-python-sdk/compare/v0.40.0...v0.40.1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: gmt-python-sdk
3
- Version: 0.40.1
3
+ Version: 0.41.0
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gmt-python-sdk"
3
- version = "0.40.1"
3
+ version = "0.41.0"
4
4
  description = "The official Python library for the gmt API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -25,7 +25,9 @@ from typing_extensions import (
25
25
  ClassVar,
26
26
  Protocol,
27
27
  Required,
28
+ Annotated,
28
29
  ParamSpec,
30
+ TypeAlias,
29
31
  TypedDict,
30
32
  TypeGuard,
31
33
  final,
@@ -79,7 +81,15 @@ from ._compat import (
79
81
  from ._constants import RAW_RESPONSE_HEADER
80
82
 
81
83
  if TYPE_CHECKING:
84
+ from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler
85
+ from pydantic_core import CoreSchema, core_schema
82
86
  from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
87
+ else:
88
+ try:
89
+ from pydantic_core import CoreSchema, core_schema
90
+ except ImportError:
91
+ CoreSchema = None
92
+ core_schema = None
83
93
 
84
94
  __all__ = ["BaseModel", "GenericModel"]
85
95
 
@@ -396,6 +406,76 @@ class BaseModel(pydantic.BaseModel):
396
406
  )
397
407
 
398
408
 
409
+ class _EagerIterable(list[_T], Generic[_T]):
410
+ """
411
+ Accepts any Iterable[T] input (including generators), consumes it
412
+ eagerly, and validates all items upfront.
413
+
414
+ Validation preserves the original container type where possible
415
+ (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON)
416
+ always emits a list — round-tripping through model_dump() will not
417
+ restore the original container type.
418
+ """
419
+
420
+ @classmethod
421
+ def __get_pydantic_core_schema__(
422
+ cls,
423
+ source_type: Any,
424
+ handler: GetCoreSchemaHandler,
425
+ ) -> CoreSchema:
426
+ (item_type,) = get_args(source_type) or (Any,)
427
+ item_schema: CoreSchema = handler.generate_schema(item_type)
428
+ list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema)
429
+
430
+ return core_schema.no_info_wrap_validator_function(
431
+ cls._validate,
432
+ list_of_items_schema,
433
+ serialization=core_schema.plain_serializer_function_ser_schema(
434
+ cls._serialize,
435
+ info_arg=False,
436
+ ),
437
+ )
438
+
439
+ @staticmethod
440
+ def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any:
441
+ original_type: type[Any] = type(v)
442
+
443
+ # Normalize to list so list_schema can validate each item
444
+ if isinstance(v, list):
445
+ items: list[_T] = v
446
+ else:
447
+ try:
448
+ items = list(v)
449
+ except TypeError as e:
450
+ raise TypeError("Value is not iterable") from e
451
+
452
+ # Validate items against the inner schema
453
+ validated: list[_T] = handler(items)
454
+
455
+ # Reconstruct original container type
456
+ if original_type is list:
457
+ return validated
458
+ # str(list) produces the list's repr, not a string built from items,
459
+ # so skip reconstruction for str and its subclasses.
460
+ if issubclass(original_type, str):
461
+ return validated
462
+ try:
463
+ return original_type(validated)
464
+ except (TypeError, ValueError):
465
+ # If the type cannot be reconstructed, just return the validated list
466
+ return validated
467
+
468
+ @staticmethod
469
+ def _serialize(v: Iterable[_T]) -> list[_T]:
470
+ """Always serialize as a list so Pydantic's JSON encoder is happy."""
471
+ if isinstance(v, list):
472
+ return v
473
+ return list(v)
474
+
475
+
476
+ EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable]
477
+
478
+
399
479
  def _construct_field(value: object, field: FieldInfo, key: str) -> object:
400
480
  if value is None:
401
481
  return field_get_default(field)
@@ -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.40.1" # x-release-please-version
4
+ __version__ = "0.41.0" # x-release-please-version
@@ -1,7 +1,8 @@
1
1
  import json
2
- from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast
2
+ from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast
3
3
  from datetime import datetime, timezone
4
- from typing_extensions import Literal, Annotated, TypeAliasType
4
+ from collections import deque
5
+ from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType
5
6
 
6
7
  import pytest
7
8
  import pydantic
@@ -9,7 +10,7 @@ from pydantic import Field
9
10
 
10
11
  from gmt._utils import PropertyInfo
11
12
  from gmt._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
12
- from gmt._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
13
+ from gmt._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type
13
14
 
14
15
 
15
16
  class BasicModel(BaseModel):
@@ -961,3 +962,56 @@ def test_extra_properties() -> None:
961
962
  assert model.a.prop == 1
962
963
  assert isinstance(model.a, Item)
963
964
  assert model.other == "foo"
965
+
966
+
967
+ # NOTE: Workaround for Pydantic Iterable behavior.
968
+ # Iterable fields are replaced with a ValidatorIterator and may be consumed
969
+ # during serialization, which can cause subsequent dumps to return empty data.
970
+ # See: https://github.com/pydantic/pydantic/issues/9541
971
+ @pytest.mark.parametrize(
972
+ "data, expected_validated",
973
+ [
974
+ ([1, 2, 3], [1, 2, 3]),
975
+ ((1, 2, 3), (1, 2, 3)),
976
+ (set([1, 2, 3]), set([1, 2, 3])),
977
+ (iter([1, 2, 3]), [1, 2, 3]),
978
+ ([], []),
979
+ ((x for x in [1, 2, 3]), [1, 2, 3]),
980
+ (map(lambda x: x, [1, 2, 3]), [1, 2, 3]),
981
+ (frozenset([1, 2, 3]), frozenset([1, 2, 3])),
982
+ (deque([1, 2, 3]), deque([1, 2, 3])),
983
+ ],
984
+ ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"],
985
+ )
986
+ @pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2")
987
+ def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None:
988
+ class TypeWithIterable(TypedDict):
989
+ items: EagerIterable[int]
990
+
991
+ class Model(BaseModel):
992
+ data: TypeWithIterable
993
+
994
+ m = Model.model_validate({"data": {"items": data}})
995
+ assert m.data["items"] == expected_validated
996
+
997
+ # Verify repeated dumps don't lose data (the original bug)
998
+ assert m.model_dump()["data"]["items"] == list(expected_validated)
999
+ assert m.model_dump()["data"]["items"] == list(expected_validated)
1000
+
1001
+
1002
+ @pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2")
1003
+ def test_iterable_construction_str_falls_back_to_list() -> None:
1004
+ # str is iterable (over chars), but str(list_of_chars) produces the list's repr
1005
+ # rather than reconstructing a string from items. We special-case str to fall
1006
+ # back to list instead of attempting reconstruction.
1007
+ class TypeWithIterable(TypedDict):
1008
+ items: EagerIterable[str]
1009
+
1010
+ class Model(BaseModel):
1011
+ data: TypeWithIterable
1012
+
1013
+ m = Model.model_validate({"data": {"items": "hello"}})
1014
+
1015
+ # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"])
1016
+ assert m.data["items"] == ["h", "e", "l", "l", "o"]
1017
+ assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"]
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.40.1"
3
- }
File without changes
File without changes
File without changes