prelude-python-sdk 0.5.0__tar.gz → 0.7.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 (91) hide show
  1. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/.gitignore +0 -1
  2. prelude_python_sdk-0.7.0/.release-please-manifest.json +3 -0
  3. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/CHANGELOG.md +74 -0
  4. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/CONTRIBUTING.md +1 -2
  5. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/PKG-INFO +44 -3
  6. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/README.md +39 -2
  7. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/bin/check-release-environment +1 -1
  8. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/pyproject.toml +8 -3
  9. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/requirements-dev.lock +33 -2
  10. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/requirements.lock +29 -2
  11. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/__init__.py +2 -1
  12. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_base_client.py +59 -7
  13. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_compat.py +48 -48
  14. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_files.py +4 -4
  15. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_models.py +72 -46
  16. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_types.py +37 -1
  17. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/__init__.py +9 -2
  18. prelude_python_sdk-0.7.0/src/prelude_python_sdk/_utils/_compat.py +45 -0
  19. prelude_python_sdk-0.7.0/src/prelude_python_sdk/_utils/_datetime_parse.py +136 -0
  20. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_transform.py +11 -1
  21. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_typing.py +6 -1
  22. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_utils.py +0 -1
  23. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_version.py +1 -1
  24. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/resources/transactional.py +6 -2
  25. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/transactional_send_params.py +5 -1
  26. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/transactional_send_response.py +5 -1
  27. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/verification_check_response.py +5 -0
  28. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/verification_create_params.py +6 -2
  29. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/verification_create_response.py +16 -3
  30. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_predict_params.py +5 -1
  31. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_send_feedbacks_params.py +5 -1
  32. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/api_resources/test_lookup.py +3 -1
  33. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/api_resources/test_transactional.py +11 -25
  34. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/api_resources/test_verification.py +13 -27
  35. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/api_resources/test_watch.py +5 -3
  36. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/conftest.py +39 -6
  37. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_client.py +134 -79
  38. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_models.py +96 -24
  39. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_transform.py +8 -8
  40. prelude_python_sdk-0.7.0/tests/test_utils/test_datetime_parse.py +110 -0
  41. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/utils.py +13 -5
  42. prelude_python_sdk-0.5.0/.release-please-manifest.json +0 -3
  43. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/LICENSE +0 -0
  44. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/SECURITY.md +0 -0
  45. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/api.md +0 -0
  46. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/bin/publish-pypi +0 -0
  47. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/examples/.keep +0 -0
  48. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/mypy.ini +0 -0
  49. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/noxfile.py +0 -0
  50. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/release-please-config.json +0 -0
  51. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude/lib/.keep +0 -0
  52. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_client.py +0 -0
  53. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_constants.py +0 -0
  54. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_exceptions.py +0 -0
  55. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_qs.py +0 -0
  56. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_resource.py +0 -0
  57. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_response.py +0 -0
  58. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_streaming.py +0 -0
  59. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_logs.py +0 -0
  60. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_proxy.py +0 -0
  61. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_reflection.py +0 -0
  62. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_resources_proxy.py +0 -0
  63. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_streams.py +0 -0
  64. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/_utils/_sync.py +0 -0
  65. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/lib/.keep +0 -0
  66. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/py.typed +0 -0
  67. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/resources/__init__.py +0 -0
  68. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/resources/lookup.py +0 -0
  69. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/resources/verification.py +0 -0
  70. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/resources/watch.py +0 -0
  71. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/__init__.py +0 -0
  72. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/lookup_lookup_params.py +0 -0
  73. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/lookup_lookup_response.py +0 -0
  74. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/verification_check_params.py +0 -0
  75. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_predict_response.py +0 -0
  76. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_send_events_params.py +0 -0
  77. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_send_events_response.py +0 -0
  78. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_python_sdk/types/watch_send_feedbacks_response.py +0 -0
  79. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/src/prelude_sdk/lib/.keep +0 -0
  80. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/__init__.py +0 -0
  81. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/api_resources/__init__.py +0 -0
  82. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/sample_file.txt +0 -0
  83. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_deepcopy.py +0 -0
  84. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_extract_files.py +0 -0
  85. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_files.py +0 -0
  86. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_qs.py +0 -0
  87. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_required_args.py +0 -0
  88. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_response.py +0 -0
  89. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_streaming.py +0 -0
  90. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_utils/test_proxy.py +0 -0
  91. {prelude_python_sdk-0.5.0 → prelude_python_sdk-0.7.0}/tests/test_utils/test_typing.py +0 -0
@@ -1,5 +1,4 @@
1
1
  .prism.log
2
- .vscode
3
2
  _dev
4
3
 
5
4
  __pycache__
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.7.0"
3
+ }
@@ -1,5 +1,79 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0 (2025-09-03)
4
+
5
+ Full Changelog: [v0.6.0...v0.7.0](https://github.com/prelude-so/python-sdk/compare/v0.6.0...v0.7.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** api update ([cebd59c](https://github.com/prelude-so/python-sdk/commit/cebd59c1f67146b7e840bbccc6b4a2d17916bdca))
10
+ * **api:** update via SDK Studio ([609835d](https://github.com/prelude-so/python-sdk/commit/609835dc935b7c22bd0bfec3216278ede1771bed))
11
+ * clean up environment call outs ([ff48f3e](https://github.com/prelude-so/python-sdk/commit/ff48f3e5cb1fb68096e0f4957905ee48856d1df7))
12
+ * **client:** support file upload requests ([ac0a4c1](https://github.com/prelude-so/python-sdk/commit/ac0a4c1701251a38422125a077ae7add7416c1a5))
13
+ * improve future compat with pydantic v3 ([8ac53e8](https://github.com/prelude-so/python-sdk/commit/8ac53e8eb18c084e32881aa804eb003610133276))
14
+ * **types:** replace List[str] with SequenceNotStr in params ([a376204](https://github.com/prelude-so/python-sdk/commit/a3762043fce5190bf8e507a0eb45de86bbc52183))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * avoid newer type syntax ([a254a0e](https://github.com/prelude-so/python-sdk/commit/a254a0eaff6b2c7e4c0beb7ae704bf0e11a99f03))
20
+ * **ci:** correct conditional ([b7261ff](https://github.com/prelude-so/python-sdk/commit/b7261ff9886067756fb25e32b6909b15790377dc))
21
+ * **ci:** release-doctor — report correct token name ([77a8e56](https://github.com/prelude-so/python-sdk/commit/77a8e5698965234e6619e1050e703af72b57e48e))
22
+ * **client:** don't send Content-Type header on GET requests ([c613df9](https://github.com/prelude-so/python-sdk/commit/c613df92d49194b1a1f89e2a9e0f6ab0fac8d472))
23
+ * **parsing:** correctly handle nested discriminated unions ([3436bf4](https://github.com/prelude-so/python-sdk/commit/3436bf4532297cd94a44e997474ac0398483dd0c))
24
+ * **parsing:** ignore empty metadata ([c23e14b](https://github.com/prelude-so/python-sdk/commit/c23e14b9ec01412e132ee9d03ae4bbaff74f33ac))
25
+ * **parsing:** parse extra field types ([bf9be03](https://github.com/prelude-so/python-sdk/commit/bf9be03f3613d2babb797dd5f74da85c09c3c897))
26
+
27
+
28
+ ### Chores
29
+
30
+ * **ci:** change upload type ([7c6c5df](https://github.com/prelude-so/python-sdk/commit/7c6c5df63e1959589d2675e0ebf7137d4670e12f))
31
+ * **ci:** only run for pushes and fork pull requests ([b32650a](https://github.com/prelude-so/python-sdk/commit/b32650a2b717410e7e41e4a99e3fe65fc8a855f5))
32
+ * **internal:** add Sequence related utils ([7a7d144](https://github.com/prelude-so/python-sdk/commit/7a7d144d831e463f2ede025dc1324d9162ffc3ed))
33
+ * **internal:** bump pinned h11 dep ([0402574](https://github.com/prelude-so/python-sdk/commit/040257411723704ee4f230aeeb4afc23835903bf))
34
+ * **internal:** change ci workflow machines ([3248bbf](https://github.com/prelude-so/python-sdk/commit/3248bbfe138fe7d6ed1bef914d96e3e2c12953bb))
35
+ * **internal:** codegen related update ([b5e89fd](https://github.com/prelude-so/python-sdk/commit/b5e89fdf678bd950a842af41215cffdd15e8ed78))
36
+ * **internal:** fix ruff target version ([88b0123](https://github.com/prelude-so/python-sdk/commit/88b012325f232611a76989c3af466e499994ce97))
37
+ * **internal:** update comment in script ([786148a](https://github.com/prelude-so/python-sdk/commit/786148a170efc4290dbd513bc52036a9b129d179))
38
+ * **internal:** update pyright exclude list ([c160b8a](https://github.com/prelude-so/python-sdk/commit/c160b8a4fdce40e4408927204dfb602b808ad8de))
39
+ * **internal:** update test skipping reason ([80f788b](https://github.com/prelude-so/python-sdk/commit/80f788b5680588ef9970c40a7f8c26926acf2a3d))
40
+ * **package:** mark python 3.13 as supported ([17711c4](https://github.com/prelude-so/python-sdk/commit/17711c472c274e2b8bf5e094f392d12411c36fc1))
41
+ * **project:** add settings file for vscode ([7f5049f](https://github.com/prelude-so/python-sdk/commit/7f5049f0f71e4b0288d4102ffa67ebf60a1bd500))
42
+ * **readme:** fix version rendering on pypi ([fb60330](https://github.com/prelude-so/python-sdk/commit/fb60330a88cd4371ebee780ffbf5295953d8c43d))
43
+ * update @stainless-api/prism-cli to v5.15.0 ([16ee61e](https://github.com/prelude-so/python-sdk/commit/16ee61e3b8dd042fe52dd6b75b5216f8a0c314d4))
44
+ * update github action ([0541486](https://github.com/prelude-so/python-sdk/commit/054148684c50734248c3a12a78a59686bff5925f))
45
+
46
+ ## 0.6.0 (2025-06-23)
47
+
48
+ Full Changelog: [v0.5.0...v0.6.0](https://github.com/prelude-so/python-sdk/compare/v0.5.0...v0.6.0)
49
+
50
+ ### Features
51
+
52
+ * **client:** add follow_redirects request option ([da19e96](https://github.com/prelude-so/python-sdk/commit/da19e966164aceec4e1a1b0d48411972dd16ac57))
53
+ * **client:** add support for aiohttp ([fe01e14](https://github.com/prelude-so/python-sdk/commit/fe01e142af02731f76b0c6d4199a9384f1e9707e))
54
+
55
+
56
+ ### Bug Fixes
57
+
58
+ * **client:** correctly parse binary response | stream ([e3dfded](https://github.com/prelude-so/python-sdk/commit/e3dfded9ae983f50630cab36befb34dd6306eb1f))
59
+ * **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([77eef78](https://github.com/prelude-so/python-sdk/commit/77eef78d5df7e67d148a0e52a914b5b91a69b804))
60
+
61
+
62
+ ### Chores
63
+
64
+ * **ci:** enable for pull requests ([da78c21](https://github.com/prelude-so/python-sdk/commit/da78c212562c4561494ea3c648aa21289e2e15dc))
65
+ * **docs:** remove reference to rye shell ([17caed7](https://github.com/prelude-so/python-sdk/commit/17caed7d4f227f504f924cb7117923153dbe0c57))
66
+ * **internal:** update conftest.py ([4d73eac](https://github.com/prelude-so/python-sdk/commit/4d73eace815b6ac0422b55f1d52837fd7b515b46))
67
+ * **readme:** update badges ([a5f1b45](https://github.com/prelude-so/python-sdk/commit/a5f1b45fb802eea987c0dcadb5f464fe9071cf44))
68
+ * **tests:** add tests for httpx client instantiation & proxies ([c0a7434](https://github.com/prelude-so/python-sdk/commit/c0a743495858c5082d1a1634855e72efacaaaa22))
69
+ * **tests:** run tests in parallel ([646764a](https://github.com/prelude-so/python-sdk/commit/646764ac379ac82faf861bd1bf00ce593cbf13e9))
70
+ * **tests:** skip some failing tests on the latest python versions ([734cb0d](https://github.com/prelude-so/python-sdk/commit/734cb0dc7855541bc3379bd87c89a41a49f618c7))
71
+
72
+
73
+ ### Documentation
74
+
75
+ * **client:** fix httpx.Timeout documentation reference ([041dd82](https://github.com/prelude-so/python-sdk/commit/041dd82ad1711670db7e1fbd4ee11fd1eae0ea99))
76
+
3
77
  ## 0.5.0 (2025-06-02)
4
78
 
5
79
  Full Changelog: [v0.4.0...v0.5.0](https://github.com/prelude-so/python-sdk/compare/v0.4.0...v0.5.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.5.0
3
+ Version: 0.7.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
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
21
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
23
  Classifier: Typing :: Typed
23
24
  Requires-Python: >=3.8
@@ -27,11 +28,15 @@ Requires-Dist: httpx<1,>=0.23.0
27
28
  Requires-Dist: pydantic<3,>=1.9.0
28
29
  Requires-Dist: sniffio
29
30
  Requires-Dist: typing-extensions<5,>=4.10
31
+ Provides-Extra: aiohttp
32
+ Requires-Dist: aiohttp; extra == 'aiohttp'
33
+ Requires-Dist: httpx-aiohttp>=0.1.8; extra == 'aiohttp'
30
34
  Description-Content-Type: text/markdown
31
35
 
32
36
  # Prelude Python API library
33
37
 
34
- [![PyPI version](https://img.shields.io/pypi/v/prelude-python-sdk.svg)](https://pypi.org/project/prelude-python-sdk/)
38
+ <!-- prettier-ignore -->
39
+ [![PyPI version](https://img.shields.io/pypi/v/prelude-python-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/prelude-python-sdk/)
35
40
 
36
41
  The Prelude Python library provides convenient access to the Prelude REST API from any Python 3.8+
37
42
  application. The library includes type definitions for all request params and response fields,
@@ -105,6 +110,42 @@ asyncio.run(main())
105
110
 
106
111
  Functionality between the synchronous and asynchronous clients is otherwise identical.
107
112
 
113
+ ### With aiohttp
114
+
115
+ By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
116
+
117
+ You can enable this by installing `aiohttp`:
118
+
119
+ ```sh
120
+ # install from PyPI
121
+ pip install prelude-python-sdk[aiohttp]
122
+ ```
123
+
124
+ Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
125
+
126
+ ```python
127
+ import asyncio
128
+ from prelude_python_sdk import DefaultAioHttpClient
129
+ from prelude_python_sdk import AsyncPrelude
130
+
131
+
132
+ async def main() -> None:
133
+ async with AsyncPrelude(
134
+ api_token="My API Token",
135
+ http_client=DefaultAioHttpClient(),
136
+ ) as client:
137
+ verification = await client.verification.create(
138
+ target={
139
+ "type": "phone_number",
140
+ "value": "+30123456789",
141
+ },
142
+ )
143
+ print(verification.id)
144
+
145
+
146
+ asyncio.run(main())
147
+ ```
148
+
108
149
  ## Using types
109
150
 
110
151
  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 +248,7 @@ client.with_options(max_retries=5).verification.create(
207
248
  ### Timeouts
208
249
 
209
250
  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:
251
+ which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
211
252
 
212
253
  ```python
213
254
  from prelude_python_sdk import Prelude
@@ -1,6 +1,7 @@
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
+ <!-- prettier-ignore -->
4
+ [![PyPI version](https://img.shields.io/pypi/v/prelude-python-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/prelude-python-sdk/)
4
5
 
5
6
  The Prelude Python library provides convenient access to the Prelude REST API from any Python 3.8+
6
7
  application. The library includes type definitions for all request params and response fields,
@@ -74,6 +75,42 @@ asyncio.run(main())
74
75
 
75
76
  Functionality between the synchronous and asynchronous clients is otherwise identical.
76
77
 
78
+ ### With aiohttp
79
+
80
+ By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
81
+
82
+ You can enable this by installing `aiohttp`:
83
+
84
+ ```sh
85
+ # install from PyPI
86
+ pip install prelude-python-sdk[aiohttp]
87
+ ```
88
+
89
+ Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
90
+
91
+ ```python
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="My API Token",
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
@@ -3,7 +3,7 @@
3
3
  errors=()
4
4
 
5
5
  if [ -z "${PYPI_TOKEN}" ]; then
6
- errors+=("The PRELUDE_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
6
+ errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
7
7
  fi
8
8
 
9
9
  lenErrors=${#errors[@]}
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "prelude-python-sdk"
3
- version = "0.5.0"
3
+ version = "0.7.0"
4
4
  description = "The official Python library for the Prelude API"
5
5
  dynamic = ["readme"]
6
6
  license = "Apache-2.0"
@@ -24,6 +24,7 @@ classifiers = [
24
24
  "Programming Language :: Python :: 3.10",
25
25
  "Programming Language :: Python :: 3.11",
26
26
  "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
27
28
  "Operating System :: OS Independent",
28
29
  "Operating System :: POSIX",
29
30
  "Operating System :: MacOS",
@@ -37,6 +38,8 @@ classifiers = [
37
38
  Homepage = "https://github.com/prelude-so/python-sdk"
38
39
  Repository = "https://github.com/prelude-so/python-sdk"
39
40
 
41
+ [project.optional-dependencies]
42
+ aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"]
40
43
 
41
44
  [tool.rye]
42
45
  managed = true
@@ -54,6 +57,7 @@ dev-dependencies = [
54
57
  "importlib-metadata>=6.7.0",
55
58
  "rich>=13.7.1",
56
59
  "nest_asyncio==1.6.0",
60
+ "pytest-xdist>=3.6.1",
57
61
  ]
58
62
 
59
63
  [tool.rye.scripts]
@@ -125,7 +129,7 @@ replacement = '[\1](https://github.com/prelude-so/python-sdk/tree/main/\g<2>)'
125
129
 
126
130
  [tool.pytest.ini_options]
127
131
  testpaths = ["tests"]
128
- addopts = "--tb=short"
132
+ addopts = "--tb=short -n auto"
129
133
  xfail_strict = true
130
134
  asyncio_mode = "auto"
131
135
  asyncio_default_fixture_loop_scope = "session"
@@ -144,6 +148,7 @@ exclude = [
144
148
  "_dev",
145
149
  ".venv",
146
150
  ".nox",
151
+ ".git",
147
152
  ]
148
153
 
149
154
  reportImplicitOverride = true
@@ -155,7 +160,7 @@ reportPrivateUsage = false
155
160
  [tool.ruff]
156
161
  line-length = 120
157
162
  output-format = "grouped"
158
- target-version = "py37"
163
+ target-version = "py38"
159
164
 
160
165
  [tool.ruff.format]
161
166
  docstring-code-format = true
@@ -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
35
- h11==0.14.0
48
+ frozenlist==1.6.2
49
+ # via aiohttp
50
+ # via aiosignal
51
+ h11==0.16.0
36
52
  # via httpcore
37
- httpcore==1.0.2
53
+ httpcore==1.0.9
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.8
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
25
- h11==0.14.0
36
+ frozenlist==1.6.2
37
+ # via aiohttp
38
+ # via aiosignal
39
+ h11==0.16.0
26
40
  # via httpcore
27
- httpcore==1.0.2
41
+ httpcore==1.0.9
28
42
  # via httpx
29
43
  httpx==0.28.1
44
+ # via httpx-aiohttp
45
+ # via prelude-python-sdk
46
+ httpx-aiohttp==0.1.8
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:
@@ -59,7 +59,7 @@ from ._types import (
59
59
  ModelBuilderProtocol,
60
60
  )
61
61
  from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
62
- from ._compat import PYDANTIC_V2, model_copy, model_dump
62
+ from ._compat import PYDANTIC_V1, model_copy, model_dump
63
63
  from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
64
64
  from ._response import (
65
65
  APIResponse,
@@ -232,7 +232,7 @@ class BaseSyncPage(BasePage[_T], Generic[_T]):
232
232
  model: Type[_T],
233
233
  options: FinalRequestOptions,
234
234
  ) -> None:
235
- if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
235
+ if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
236
236
  self.__pydantic_private__ = {}
237
237
 
238
238
  self._model = model
@@ -320,7 +320,7 @@ class BaseAsyncPage(BasePage[_T], Generic[_T]):
320
320
  client: AsyncAPIClient,
321
321
  options: FinalRequestOptions,
322
322
  ) -> None:
323
- if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
323
+ if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
324
324
  self.__pydantic_private__ = {}
325
325
 
326
326
  self._model = model
@@ -529,6 +529,18 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
529
529
  # work around https://github.com/encode/httpx/discussions/2880
530
530
  kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")}
531
531
 
532
+ is_body_allowed = options.method.lower() != "get"
533
+
534
+ if is_body_allowed:
535
+ if isinstance(json_data, bytes):
536
+ kwargs["content"] = json_data
537
+ else:
538
+ kwargs["json"] = json_data if is_given(json_data) else None
539
+ kwargs["files"] = files
540
+ else:
541
+ headers.pop("Content-Type", None)
542
+ kwargs.pop("data", None)
543
+
532
544
  # TODO: report this error to httpx
533
545
  return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
534
546
  headers=headers,
@@ -540,8 +552,6 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
540
552
  # so that passing a `TypedDict` doesn't cause an error.
541
553
  # https://github.com/microsoft/pyright/issues/3526#event-6715453066
542
554
  params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
543
- json=json_data if is_given(json_data) else None,
544
- files=files,
545
555
  **kwargs,
546
556
  )
547
557
 
@@ -960,6 +970,9 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
960
970
  if self.custom_auth is not None:
961
971
  kwargs["auth"] = self.custom_auth
962
972
 
973
+ if options.follow_redirects is not None:
974
+ kwargs["follow_redirects"] = options.follow_redirects
975
+
963
976
  log.debug("Sending HTTP Request: %s %s", request.method, request.url)
964
977
 
965
978
  response = None
@@ -1068,7 +1081,14 @@ class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]):
1068
1081
  ) -> ResponseT:
1069
1082
  origin = get_origin(cast_to) or cast_to
1070
1083
 
1071
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1084
+ if (
1085
+ inspect.isclass(origin)
1086
+ and issubclass(origin, BaseAPIResponse)
1087
+ # we only want to actually return the custom BaseAPIResponse class if we're
1088
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1089
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1090
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1091
+ ):
1072
1092
  if not issubclass(origin, APIResponse):
1073
1093
  raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
1074
1094
 
@@ -1279,6 +1299,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
1279
1299
  super().__init__(**kwargs)
1280
1300
 
1281
1301
 
1302
+ try:
1303
+ import httpx_aiohttp
1304
+ except ImportError:
1305
+
1306
+ class _DefaultAioHttpClient(httpx.AsyncClient):
1307
+ def __init__(self, **_kwargs: Any) -> None:
1308
+ raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
1309
+ else:
1310
+
1311
+ class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
1312
+ def __init__(self, **kwargs: Any) -> None:
1313
+ kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1314
+ kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1315
+ kwargs.setdefault("follow_redirects", True)
1316
+
1317
+ super().__init__(**kwargs)
1318
+
1319
+
1282
1320
  if TYPE_CHECKING:
1283
1321
  DefaultAsyncHttpxClient = httpx.AsyncClient
1284
1322
  """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
@@ -1287,8 +1325,12 @@ if TYPE_CHECKING:
1287
1325
  This is useful because overriding the `http_client` with your own instance of
1288
1326
  `httpx.AsyncClient` will result in httpx's defaults being used, not ours.
1289
1327
  """
1328
+
1329
+ DefaultAioHttpClient = httpx.AsyncClient
1330
+ """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
1290
1331
  else:
1291
1332
  DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
1333
+ DefaultAioHttpClient = _DefaultAioHttpClient
1292
1334
 
1293
1335
 
1294
1336
  class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
@@ -1460,6 +1502,9 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1460
1502
  if self.custom_auth is not None:
1461
1503
  kwargs["auth"] = self.custom_auth
1462
1504
 
1505
+ if options.follow_redirects is not None:
1506
+ kwargs["follow_redirects"] = options.follow_redirects
1507
+
1463
1508
  log.debug("Sending HTTP Request: %s %s", request.method, request.url)
1464
1509
 
1465
1510
  response = None
@@ -1568,7 +1613,14 @@ class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]):
1568
1613
  ) -> ResponseT:
1569
1614
  origin = get_origin(cast_to) or cast_to
1570
1615
 
1571
- if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1616
+ if (
1617
+ inspect.isclass(origin)
1618
+ and issubclass(origin, BaseAPIResponse)
1619
+ # we only want to actually return the custom BaseAPIResponse class if we're
1620
+ # returning the raw response, or if we're not streaming SSE, as if we're streaming
1621
+ # SSE then `cast_to` doesn't actively reflect the type we need to parse into
1622
+ and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1623
+ ):
1572
1624
  if not issubclass(origin, AsyncAPIResponse):
1573
1625
  raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
1574
1626