prelude-python-sdk 0.4.0__tar.gz → 0.6.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 (88) hide show
  1. prelude_python_sdk-0.6.0/.release-please-manifest.json +3 -0
  2. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/CHANGELOG.md +46 -0
  3. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/CONTRIBUTING.md +1 -2
  4. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/PKG-INFO +43 -3
  5. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/README.md +39 -2
  6. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/SECURITY.md +2 -2
  7. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/pyproject.toml +5 -2
  8. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/requirements-dev.lock +31 -0
  9. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/requirements.lock +27 -0
  10. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/__init__.py +2 -1
  11. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_base_client.py +44 -2
  12. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_models.py +2 -0
  13. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_types.py +2 -0
  14. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_version.py +1 -1
  15. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/verification_create_params.py +2 -2
  16. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/verification_create_response.py +18 -2
  17. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/api_resources/test_lookup.py +3 -1
  18. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/api_resources/test_transactional.py +3 -1
  19. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/api_resources/test_verification.py +3 -1
  20. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/api_resources/test_watch.py +3 -1
  21. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/conftest.py +39 -6
  22. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_client.py +132 -77
  23. prelude_python_sdk-0.4.0/.release-please-manifest.json +0 -3
  24. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/.gitignore +0 -0
  25. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/LICENSE +0 -0
  26. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/api.md +0 -0
  27. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/bin/check-release-environment +0 -0
  28. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/bin/publish-pypi +0 -0
  29. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/examples/.keep +0 -0
  30. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/mypy.ini +0 -0
  31. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/noxfile.py +0 -0
  32. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/release-please-config.json +0 -0
  33. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude/lib/.keep +0 -0
  34. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_client.py +0 -0
  35. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_compat.py +0 -0
  36. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_constants.py +0 -0
  37. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_exceptions.py +0 -0
  38. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_files.py +0 -0
  39. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_qs.py +0 -0
  40. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_resource.py +0 -0
  41. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_response.py +0 -0
  42. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_streaming.py +0 -0
  43. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/__init__.py +0 -0
  44. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_logs.py +0 -0
  45. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_proxy.py +0 -0
  46. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_reflection.py +0 -0
  47. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_resources_proxy.py +0 -0
  48. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_streams.py +0 -0
  49. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_sync.py +0 -0
  50. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_transform.py +0 -0
  51. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_typing.py +0 -0
  52. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/_utils/_utils.py +0 -0
  53. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/lib/.keep +0 -0
  54. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/py.typed +0 -0
  55. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/resources/__init__.py +0 -0
  56. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/resources/lookup.py +0 -0
  57. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/resources/transactional.py +0 -0
  58. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/resources/verification.py +0 -0
  59. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/resources/watch.py +0 -0
  60. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/__init__.py +0 -0
  61. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/lookup_lookup_params.py +0 -0
  62. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/lookup_lookup_response.py +0 -0
  63. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/transactional_send_params.py +0 -0
  64. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/transactional_send_response.py +0 -0
  65. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/verification_check_params.py +0 -0
  66. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/verification_check_response.py +0 -0
  67. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_predict_params.py +0 -0
  68. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_predict_response.py +0 -0
  69. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_send_events_params.py +0 -0
  70. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_send_events_response.py +0 -0
  71. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_send_feedbacks_params.py +0 -0
  72. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_python_sdk/types/watch_send_feedbacks_response.py +0 -0
  73. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/src/prelude_sdk/lib/.keep +0 -0
  74. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/__init__.py +0 -0
  75. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/api_resources/__init__.py +0 -0
  76. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/sample_file.txt +0 -0
  77. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_deepcopy.py +0 -0
  78. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_extract_files.py +0 -0
  79. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_files.py +0 -0
  80. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_models.py +0 -0
  81. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_qs.py +0 -0
  82. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_required_args.py +0 -0
  83. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_response.py +0 -0
  84. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_streaming.py +0 -0
  85. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_transform.py +0 -0
  86. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_utils/test_proxy.py +0 -0
  87. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/test_utils/test_typing.py +0 -0
  88. {prelude_python_sdk-0.4.0 → prelude_python_sdk-0.6.0}/tests/utils.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.6.0"
3
+ }
@@ -1,5 +1,51 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 (2025-06-23)
4
+
5
+ Full Changelog: [v0.5.0...v0.6.0](https://github.com/prelude-so/python-sdk/compare/v0.5.0...v0.6.0)
6
+
7
+ ### Features
8
+
9
+ * **client:** add follow_redirects request option ([da19e96](https://github.com/prelude-so/python-sdk/commit/da19e966164aceec4e1a1b0d48411972dd16ac57))
10
+ * **client:** add support for aiohttp ([fe01e14](https://github.com/prelude-so/python-sdk/commit/fe01e142af02731f76b0c6d4199a9384f1e9707e))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **client:** correctly parse binary response | stream ([e3dfded](https://github.com/prelude-so/python-sdk/commit/e3dfded9ae983f50630cab36befb34dd6306eb1f))
16
+ * **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([77eef78](https://github.com/prelude-so/python-sdk/commit/77eef78d5df7e67d148a0e52a914b5b91a69b804))
17
+
18
+
19
+ ### Chores
20
+
21
+ * **ci:** enable for pull requests ([da78c21](https://github.com/prelude-so/python-sdk/commit/da78c212562c4561494ea3c648aa21289e2e15dc))
22
+ * **docs:** remove reference to rye shell ([17caed7](https://github.com/prelude-so/python-sdk/commit/17caed7d4f227f504f924cb7117923153dbe0c57))
23
+ * **internal:** update conftest.py ([4d73eac](https://github.com/prelude-so/python-sdk/commit/4d73eace815b6ac0422b55f1d52837fd7b515b46))
24
+ * **readme:** update badges ([a5f1b45](https://github.com/prelude-so/python-sdk/commit/a5f1b45fb802eea987c0dcadb5f464fe9071cf44))
25
+ * **tests:** add tests for httpx client instantiation & proxies ([c0a7434](https://github.com/prelude-so/python-sdk/commit/c0a743495858c5082d1a1634855e72efacaaaa22))
26
+ * **tests:** run tests in parallel ([646764a](https://github.com/prelude-so/python-sdk/commit/646764ac379ac82faf861bd1bf00ce593cbf13e9))
27
+ * **tests:** skip some failing tests on the latest python versions ([734cb0d](https://github.com/prelude-so/python-sdk/commit/734cb0dc7855541bc3379bd87c89a41a49f618c7))
28
+
29
+
30
+ ### Documentation
31
+
32
+ * **client:** fix httpx.Timeout documentation reference ([041dd82](https://github.com/prelude-so/python-sdk/commit/041dd82ad1711670db7e1fbd4ee11fd1eae0ea99))
33
+
34
+ ## 0.5.0 (2025-06-02)
35
+
36
+ Full Changelog: [v0.4.0...v0.5.0](https://github.com/prelude-so/python-sdk/compare/v0.4.0...v0.5.0)
37
+
38
+ ### Features
39
+
40
+ * **api:** update via SDK Studio ([89eb324](https://github.com/prelude-so/python-sdk/commit/89eb3248d31252d70799490dfdf6f29645f56e1b))
41
+
42
+
43
+ ### Chores
44
+
45
+ * **ci:** fix installation instructions ([afe0c52](https://github.com/prelude-so/python-sdk/commit/afe0c524b286def7133c08b84e4f0679bd045b49))
46
+ * **ci:** upload sdks to package manager ([5f4eaa3](https://github.com/prelude-so/python-sdk/commit/5f4eaa3b2581ea51ff992504996d141759496b96))
47
+ * **docs:** grammar improvements ([79cf9fe](https://github.com/prelude-so/python-sdk/commit/79cf9fe6f5084631be0a6de5b7f334c0d8e554e3))
48
+
3
49
  ## 0.4.0 (2025-05-13)
4
50
 
5
51
  Full Changelog: [v0.3.0...v0.4.0](https://github.com/prelude-so/python-sdk/compare/v0.3.0...v0.4.0)
@@ -17,8 +17,7 @@ $ rye sync --all-features
17
17
  You can then run scripts using `rye run python script.py` or by activating the virtual environment:
18
18
 
19
19
  ```sh
20
- $ rye shell
21
- # or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
20
+ # Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work
22
21
  $ source .venv/bin/activate
23
22
 
24
23
  # now you can omit the `rye run` prefix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: prelude-python-sdk
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: The official Python library for the Prelude API
5
5
  Project-URL: Homepage, https://github.com/prelude-so/python-sdk
6
6
  Project-URL: Repository, https://github.com/prelude-so/python-sdk
@@ -27,11 +27,14 @@ Requires-Dist: httpx<1,>=0.23.0
27
27
  Requires-Dist: pydantic<3,>=1.9.0
28
28
  Requires-Dist: sniffio
29
29
  Requires-Dist: typing-extensions<5,>=4.10
30
+ Provides-Extra: aiohttp
31
+ Requires-Dist: aiohttp; extra == 'aiohttp'
32
+ Requires-Dist: httpx-aiohttp>=0.1.6; extra == 'aiohttp'
30
33
  Description-Content-Type: text/markdown
31
34
 
32
35
  # Prelude Python API library
33
36
 
34
- [![PyPI version](https://img.shields.io/pypi/v/prelude-python-sdk.svg)](https://pypi.org/project/prelude-python-sdk/)
37
+ [![PyPI version](https://github.com/prelude-so/python-sdk/tree/main/<https://img.shields.io/pypi/v/prelude-python-sdk.svg?label=pypi%20(stable)>)](https://pypi.org/project/prelude-python-sdk/)
35
38
 
36
39
  The Prelude Python library provides convenient access to the Prelude REST API from any Python 3.8+
37
40
  application. The library includes type definitions for all request params and response fields,
@@ -105,6 +108,43 @@ asyncio.run(main())
105
108
 
106
109
  Functionality between the synchronous and asynchronous clients is otherwise identical.
107
110
 
111
+ ### With aiohttp
112
+
113
+ By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
114
+
115
+ You can enable this by installing `aiohttp`:
116
+
117
+ ```sh
118
+ # install from PyPI
119
+ pip install prelude-python-sdk[aiohttp]
120
+ ```
121
+
122
+ Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
123
+
124
+ ```python
125
+ import os
126
+ import asyncio
127
+ from prelude_python_sdk import DefaultAioHttpClient
128
+ from prelude_python_sdk import AsyncPrelude
129
+
130
+
131
+ async def main() -> None:
132
+ async with AsyncPrelude(
133
+ api_token=os.environ.get("API_TOKEN"), # This is the default and can be omitted
134
+ http_client=DefaultAioHttpClient(),
135
+ ) as client:
136
+ verification = await client.verification.create(
137
+ target={
138
+ "type": "phone_number",
139
+ "value": "+30123456789",
140
+ },
141
+ )
142
+ print(verification.id)
143
+
144
+
145
+ asyncio.run(main())
146
+ ```
147
+
108
148
  ## Using types
109
149
 
110
150
  Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
@@ -207,7 +247,7 @@ client.with_options(max_retries=5).verification.create(
207
247
  ### Timeouts
208
248
 
209
249
  By default requests time out after 1 minute. You can configure this with a `timeout` option,
210
- which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
250
+ which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
211
251
 
212
252
  ```python
213
253
  from prelude_python_sdk import Prelude
@@ -1,6 +1,6 @@
1
1
  # Prelude Python API library
2
2
 
3
- [![PyPI version](https://img.shields.io/pypi/v/prelude-python-sdk.svg)](https://pypi.org/project/prelude-python-sdk/)
3
+ [![PyPI version](<https://img.shields.io/pypi/v/prelude-python-sdk.svg?label=pypi%20(stable)>)](https://pypi.org/project/prelude-python-sdk/)
4
4
 
5
5
  The Prelude Python library provides convenient access to the Prelude REST API from any Python 3.8+
6
6
  application. The library includes type definitions for all request params and response fields,
@@ -74,6 +74,43 @@ asyncio.run(main())
74
74
 
75
75
  Functionality between the synchronous and asynchronous clients is otherwise identical.
76
76
 
77
+ ### With aiohttp
78
+
79
+ By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
80
+
81
+ You can enable this by installing `aiohttp`:
82
+
83
+ ```sh
84
+ # install from PyPI
85
+ pip install prelude-python-sdk[aiohttp]
86
+ ```
87
+
88
+ Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
89
+
90
+ ```python
91
+ import os
92
+ import asyncio
93
+ from prelude_python_sdk import DefaultAioHttpClient
94
+ from prelude_python_sdk import AsyncPrelude
95
+
96
+
97
+ async def main() -> None:
98
+ async with AsyncPrelude(
99
+ api_token=os.environ.get("API_TOKEN"), # This is the default and can be omitted
100
+ http_client=DefaultAioHttpClient(),
101
+ ) as client:
102
+ verification = await client.verification.create(
103
+ target={
104
+ "type": "phone_number",
105
+ "value": "+30123456789",
106
+ },
107
+ )
108
+ print(verification.id)
109
+
110
+
111
+ asyncio.run(main())
112
+ ```
113
+
77
114
  ## Using types
78
115
 
79
116
  Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:
@@ -176,7 +213,7 @@ client.with_options(max_retries=5).verification.create(
176
213
  ### Timeouts
177
214
 
178
215
  By default requests time out after 1 minute. You can configure this with a `timeout` option,
179
- which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
216
+ which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
180
217
 
181
218
  ```python
182
219
  from prelude_python_sdk import Prelude
@@ -16,11 +16,11 @@ before making any information public.
16
16
  ## Reporting Non-SDK Related Security Issues
17
17
 
18
18
  If you encounter security issues that are not directly related to SDKs but pertain to the services
19
- or products provided by Prelude please follow the respective company's security reporting guidelines.
19
+ or products provided by Prelude, please follow the respective company's security reporting guidelines.
20
20
 
21
21
  ### Prelude Terms and Policies
22
22
 
23
- Please contact hello@prelude.so for any questions or concerns regarding security of our services.
23
+ Please contact hello@prelude.so for any questions or concerns regarding the security of our services.
24
24
 
25
25
  ---
26
26
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "prelude-python-sdk"
3
- version = "0.4.0"
3
+ version = "0.6.0"
4
4
  description = "The official Python library for the Prelude API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -37,6 +37,8 @@ classifiers = [
37
37
  Homepage = "https://github.com/prelude-so/python-sdk"
38
38
  Repository = "https://github.com/prelude-so/python-sdk"
39
39
 
40
+ [project.optional-dependencies]
41
+ aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"]
40
42
 
41
43
  [tool.rye]
42
44
  managed = true
@@ -54,6 +56,7 @@ dev-dependencies = [
54
56
  "importlib-metadata>=6.7.0",
55
57
  "rich>=13.7.1",
56
58
  "nest_asyncio==1.6.0",
59
+ "pytest-xdist>=3.6.1",
57
60
  ]
58
61
 
59
62
  [tool.rye.scripts]
@@ -125,7 +128,7 @@ replacement = '[\1](https://github.com/prelude-so/python-sdk/tree/main/\g<2>)'
125
128
 
126
129
  [tool.pytest.ini_options]
127
130
  testpaths = ["tests"]
128
- addopts = "--tb=short"
131
+ addopts = "--tb=short -n auto"
129
132
  xfail_strict = true
130
133
  asyncio_mode = "auto"
131
134
  asyncio_default_fixture_loop_scope = "session"
@@ -10,6 +10,13 @@
10
10
  # universal: false
11
11
 
12
12
  -e file:.
13
+ aiohappyeyeballs==2.6.1
14
+ # via aiohttp
15
+ aiohttp==3.12.8
16
+ # via httpx-aiohttp
17
+ # via prelude-python-sdk
18
+ aiosignal==1.3.2
19
+ # via aiohttp
13
20
  annotated-types==0.6.0
14
21
  # via pydantic
15
22
  anyio==4.4.0
@@ -17,6 +24,10 @@ anyio==4.4.0
17
24
  # via prelude-python-sdk
18
25
  argcomplete==3.1.2
19
26
  # via nox
27
+ async-timeout==5.0.1
28
+ # via aiohttp
29
+ attrs==25.3.0
30
+ # via aiohttp
20
31
  certifi==2023.7.22
21
32
  # via httpcore
22
33
  # via httpx
@@ -30,18 +41,27 @@ distro==1.8.0
30
41
  exceptiongroup==1.2.2
31
42
  # via anyio
32
43
  # via pytest
44
+ execnet==2.1.1
45
+ # via pytest-xdist
33
46
  filelock==3.12.4
34
47
  # via virtualenv
48
+ frozenlist==1.6.2
49
+ # via aiohttp
50
+ # via aiosignal
35
51
  h11==0.14.0
36
52
  # via httpcore
37
53
  httpcore==1.0.2
38
54
  # via httpx
39
55
  httpx==0.28.1
56
+ # via httpx-aiohttp
40
57
  # via prelude-python-sdk
41
58
  # via respx
59
+ httpx-aiohttp==0.1.6
60
+ # via prelude-python-sdk
42
61
  idna==3.4
43
62
  # via anyio
44
63
  # via httpx
64
+ # via yarl
45
65
  importlib-metadata==7.0.0
46
66
  iniconfig==2.0.0
47
67
  # via pytest
@@ -49,6 +69,9 @@ markdown-it-py==3.0.0
49
69
  # via rich
50
70
  mdurl==0.1.2
51
71
  # via markdown-it-py
72
+ multidict==6.4.4
73
+ # via aiohttp
74
+ # via yarl
52
75
  mypy==1.14.1
53
76
  mypy-extensions==1.0.0
54
77
  # via mypy
@@ -63,6 +86,9 @@ platformdirs==3.11.0
63
86
  # via virtualenv
64
87
  pluggy==1.5.0
65
88
  # via pytest
89
+ propcache==0.3.1
90
+ # via aiohttp
91
+ # via yarl
66
92
  pydantic==2.10.3
67
93
  # via prelude-python-sdk
68
94
  pydantic-core==2.27.1
@@ -72,7 +98,9 @@ pygments==2.18.0
72
98
  pyright==1.1.399
73
99
  pytest==8.3.3
74
100
  # via pytest-asyncio
101
+ # via pytest-xdist
75
102
  pytest-asyncio==0.24.0
103
+ pytest-xdist==3.7.0
76
104
  python-dateutil==2.8.2
77
105
  # via time-machine
78
106
  pytz==2023.3.post1
@@ -93,6 +121,7 @@ tomli==2.0.2
93
121
  # via pytest
94
122
  typing-extensions==4.12.2
95
123
  # via anyio
124
+ # via multidict
96
125
  # via mypy
97
126
  # via prelude-python-sdk
98
127
  # via pydantic
@@ -100,5 +129,7 @@ typing-extensions==4.12.2
100
129
  # via pyright
101
130
  virtualenv==20.24.5
102
131
  # via nox
132
+ yarl==1.20.0
133
+ # via aiohttp
103
134
  zipp==3.17.0
104
135
  # via importlib-metadata
@@ -10,11 +10,22 @@
10
10
  # universal: false
11
11
 
12
12
  -e file:.
13
+ aiohappyeyeballs==2.6.1
14
+ # via aiohttp
15
+ aiohttp==3.12.8
16
+ # via httpx-aiohttp
17
+ # via prelude-python-sdk
18
+ aiosignal==1.3.2
19
+ # via aiohttp
13
20
  annotated-types==0.6.0
14
21
  # via pydantic
15
22
  anyio==4.4.0
16
23
  # via httpx
17
24
  # via prelude-python-sdk
25
+ async-timeout==5.0.1
26
+ # via aiohttp
27
+ attrs==25.3.0
28
+ # via aiohttp
18
29
  certifi==2023.7.22
19
30
  # via httpcore
20
31
  # via httpx
@@ -22,15 +33,28 @@ distro==1.8.0
22
33
  # via prelude-python-sdk
23
34
  exceptiongroup==1.2.2
24
35
  # via anyio
36
+ frozenlist==1.6.2
37
+ # via aiohttp
38
+ # via aiosignal
25
39
  h11==0.14.0
26
40
  # via httpcore
27
41
  httpcore==1.0.2
28
42
  # via httpx
29
43
  httpx==0.28.1
44
+ # via httpx-aiohttp
45
+ # via prelude-python-sdk
46
+ httpx-aiohttp==0.1.6
30
47
  # via prelude-python-sdk
31
48
  idna==3.4
32
49
  # via anyio
33
50
  # via httpx
51
+ # via yarl
52
+ multidict==6.4.4
53
+ # via aiohttp
54
+ # via yarl
55
+ propcache==0.3.1
56
+ # via aiohttp
57
+ # via yarl
34
58
  pydantic==2.10.3
35
59
  # via prelude-python-sdk
36
60
  pydantic-core==2.27.1
@@ -40,6 +64,9 @@ sniffio==1.3.0
40
64
  # via prelude-python-sdk
41
65
  typing-extensions==4.12.2
42
66
  # via anyio
67
+ # via multidict
43
68
  # via prelude-python-sdk
44
69
  # via pydantic
45
70
  # via pydantic-core
71
+ yarl==1.20.0
72
+ # via aiohttp
@@ -26,7 +26,7 @@ from ._exceptions import (
26
26
  UnprocessableEntityError,
27
27
  APIResponseValidationError,
28
28
  )
29
- from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
29
+ from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
30
30
  from ._utils._logs import setup_logging as _setup_logging
31
31
 
32
32
  __all__ = [
@@ -68,6 +68,7 @@ __all__ = [
68
68
  "DEFAULT_CONNECTION_LIMITS",
69
69
  "DefaultHttpxClient",
70
70
  "DefaultAsyncHttpxClient",
71
+ "DefaultAioHttpClient",
71
72
  ]
72
73
 
73
74
  if not _t.TYPE_CHECKING:
@@ -960,6 +960,9 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
960
960
  if self.custom_auth is not None:
961
961
  kwargs["auth"] = self.custom_auth
962
962
 
963
+ if options.follow_redirects is not None:
964
+ kwargs["follow_redirects"] = options.follow_redirects
965
+
963
966
  log.debug("Sending HTTP Request: %s %s", request.method, request.url)
964
967
 
965
968
  response = None
@@ -1068,7 +1071,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1068
1071
  ) -> ResponseT:
1069
1072
  origin = get_origin(cast_to) or cast_to
1070
1073
 
1071
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1074
+ if (
1075
+ inspect.isclass(origin)
1076
+ and issubclass(origin, BaseAPIResponse)
1077
+ # we only want to actually return the custom BaseAPIResponse class if we're
1078
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1079
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1080
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1081
+ ):
1072
1082
  if not issubclass(origin, APIResponse):
1073
1083
  raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
1074
1084
 
@@ -1279,6 +1289,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
1279
1289
  super().__init__(**kwargs)
1280
1290
 
1281
1291
 
1292
+ try:
1293
+ import httpx_aiohttp
1294
+ except ImportError:
1295
+
1296
+ class _DefaultAioHttpClient(httpx.AsyncClient):
1297
+ def __init__(self, **_kwargs: Any) -> None:
1298
+ raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
1299
+ else:
1300
+
1301
+ class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
1302
+ def __init__(self, **kwargs: Any) -> None:
1303
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1304
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1305
+ kwargs.setdefault("follow_redirects", True)
1306
+
1307
+ super().__init__(**kwargs)
1308
+
1309
+
1282
1310
  if TYPE_CHECKING:
1283
1311
  DefaultAsyncHttpxClient = httpx.AsyncClient
1284
1312
  """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
@@ -1287,8 +1315,12 @@ if TYPE_CHECKING:
1287
1315
  This is useful because overriding the `http_client` with your own instance of
1288
1316
  `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
1289
1317
  """
1318
+
1319
+ DefaultAioHttpClient = httpx.AsyncClient
1320
+ """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
1290
1321
  else:
1291
1322
  DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
1323
+ DefaultAioHttpClient = _DefaultAioHttpClient
1292
1324
 
1293
1325
 
1294
1326
  class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
@@ -1460,6 +1492,9 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1460
1492
  if self.custom_auth is not None:
1461
1493
  kwargs["auth"] = self.custom_auth
1462
1494
 
1495
+ if options.follow_redirects is not None:
1496
+ kwargs["follow_redirects"] = options.follow_redirects
1497
+
1463
1498
  log.debug("Sending HTTP Request: %s %s", request.method, request.url)
1464
1499
 
1465
1500
  response = None
@@ -1568,7 +1603,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1568
1603
  ) -> ResponseT:
1569
1604
  origin = get_origin(cast_to) or cast_to
1570
1605
 
1571
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1606
+ if (
1607
+ inspect.isclass(origin)
1608
+ and issubclass(origin, BaseAPIResponse)
1609
+ # we only want to actually return the custom BaseAPIResponse class if we're
1610
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1611
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1612
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1613
+ ):
1572
1614
  if not issubclass(origin, AsyncAPIResponse):
1573
1615
  raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
1574
1616
 
@@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
737
737
  idempotency_key: str
738
738
  json_data: Body
739
739
  extra_json: AnyMapping
740
+ follow_redirects: bool
740
741
 
741
742
 
742
743
  @final
@@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel):
750
751
  files: Union[HttpxRequestFiles, None] = None
751
752
  idempotency_key: Union[str, None] = None
752
753
  post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
754
+ follow_redirects: Union[bool, None] = None
753
755
 
754
756
  # It should be noted that we cannot use `json` here as that would override
755
757
  # a BaseModel method in an incompatible fashion.
@@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False):
100
100
  params: Query
101
101
  extra_json: AnyMapping
102
102
  idempotency_key: str
103
+ follow_redirects: bool
103
104
 
104
105
 
105
106
  # Sentinel class used until PEP 0661 is accepted
@@ -215,3 +216,4 @@ class _GenericAlias(Protocol):
215
216
 
216
217
  class HttpxSendArgs(TypedDict, total=False):
217
218
  auth: httpx.Auth
219
+ follow_redirects: bool
@@ -1,4 +1,4 @@
1
1
  # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
2
 
3
3
  __title__ = "prelude_python_sdk"
4
- __version__ = "0.4.0" # x-release-please-version
4
+ __version__ = "0.6.0" # x-release-please-version
@@ -86,7 +86,7 @@ class Options(TypedDict, total=False):
86
86
  """The custom code to use for OTP verification.
87
87
 
88
88
  To use the custom code feature, contact us to enable it for your account. For
89
- more details, refer to [Custom Code](/verify/v2/documentation/custom-code).
89
+ more details, refer to [Custom Code](/verify/v2/documentation/custom-codes).
90
90
  """
91
91
 
92
92
  locale: str
@@ -106,7 +106,7 @@ class Options(TypedDict, total=False):
106
106
  receive SMS messages.
107
107
  """
108
108
 
109
- preferred_channel: Literal["sms", "rcs", "whatsapp", "viber", "zalo"]
109
+ preferred_channel: Literal["sms", "rcs", "whatsapp", "viber", "zalo", "telegram", "silent", "voice"]
110
110
  """The preferred channel to be used in priority for verification."""
111
111
 
112
112
  sender_id: str
@@ -5,18 +5,23 @@ from typing_extensions import Literal
5
5
 
6
6
  from .._models import BaseModel
7
7
 
8
- __all__ = ["VerificationCreateResponse", "Metadata"]
8
+ __all__ = ["VerificationCreateResponse", "Metadata", "Silent"]
9
9
 
10
10
 
11
11
  class Metadata(BaseModel):
12
12
  correlation_id: Optional[str] = None
13
13
 
14
14
 
15
+ class Silent(BaseModel):
16
+ request_url: str
17
+ """The URL to start the silent verification towards."""
18
+
19
+
15
20
  class VerificationCreateResponse(BaseModel):
16
21
  id: str
17
22
  """The verification identifier."""
18
23
 
19
- method: Literal["message"]
24
+ method: Literal["message", "silent", "voice"]
20
25
  """The method used for verifying this phone number."""
21
26
 
22
27
  status: Literal["success", "retry", "blocked"]
@@ -28,4 +33,15 @@ class VerificationCreateResponse(BaseModel):
28
33
  metadata: Optional[Metadata] = None
29
34
  """The metadata for this verification."""
30
35
 
36
+ reason: Optional[
37
+ Literal["suspicious", "repeated_attempts", "invalid_phone_line", "invalid_phone_number", "in_block_list"]
38
+ ] = None
39
+ """The reason why the verification was blocked.
40
+
41
+ Only present when status is "blocked".
42
+ """
43
+
31
44
  request_id: Optional[str] = None
45
+
46
+ silent: Optional[Silent] = None
47
+ """The silent verification specific properties."""
@@ -65,7 +65,9 @@ class TestLookup:
65
65
 
66
66
 
67
67
  class TestAsyncLookup:
68
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
68
+ parametrize = pytest.mark.parametrize(
69
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
70
+ )
69
71
 
70
72
  @parametrize
71
73
  async def test_method_lookup(self, async_client: AsyncPrelude) -> None:
@@ -79,7 +79,9 @@ class TestTransactional:
79
79
 
80
80
 
81
81
  class TestAsyncTransactional:
82
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
82
+ parametrize = pytest.mark.parametrize(
83
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
84
+ )
83
85
 
84
86
  @pytest.mark.skip(
85
87
  reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url"
@@ -154,7 +154,9 @@ class TestVerification:
154
154
 
155
155
 
156
156
  class TestAsyncVerification:
157
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
157
+ parametrize = pytest.mark.parametrize(
158
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
159
+ )
158
160
 
159
161
  @pytest.mark.skip(
160
162
  reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url"
@@ -198,7 +198,9 @@ class TestWatch:
198
198
 
199
199
 
200
200
  class TestAsyncWatch:
201
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
201
+ parametrize = pytest.mark.parametrize(
202
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
203
+ )
202
204
 
203
205
  @parametrize
204
206
  async def test_method_predict(self, async_client: AsyncPrelude) -> None: