spitch 1.27.0__tar.gz → 1.28.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.
Potentially problematic release.
This version of spitch might be problematic. Click here for more details.
- {spitch-1.27.0 → spitch-1.28.0}/.gitignore +0 -1
- spitch-1.28.0/.release-please-manifest.json +3 -0
- {spitch-1.27.0 → spitch-1.28.0}/CHANGELOG.md +52 -0
- {spitch-1.27.0 → spitch-1.28.0}/PKG-INFO +43 -11
- {spitch-1.27.0 → spitch-1.28.0}/README.md +38 -10
- {spitch-1.27.0 → spitch-1.28.0}/bin/check-release-environment +1 -1
- {spitch-1.27.0 → spitch-1.28.0}/pyproject.toml +4 -1
- {spitch-1.27.0 → spitch-1.28.0}/requirements-dev.lock +32 -3
- {spitch-1.27.0 → spitch-1.28.0}/requirements.lock +31 -3
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/__init__.py +2 -1
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_base_client.py +34 -2
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_files.py +4 -4
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_models.py +31 -7
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_version.py +1 -1
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/resources/speech.py +50 -64
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/speech_generate_params.py +8 -7
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/speech_transcribe_params.py +4 -2
- spitch-1.28.0/src/spitch/types/speech_transcribe_response.py +23 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/text_tone_mark_response.py +1 -3
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/text_translate_response.py +1 -3
- {spitch-1.27.0 → spitch-1.28.0}/tests/api_resources/test_speech.py +11 -7
- {spitch-1.27.0 → spitch-1.28.0}/tests/api_resources/test_text.py +3 -1
- {spitch-1.27.0 → spitch-1.28.0}/tests/conftest.py +37 -6
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_client.py +16 -43
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_models.py +73 -1
- spitch-1.27.0/.release-please-manifest.json +0 -3
- spitch-1.27.0/src/spitch/types/speech_transcribe_response.py +0 -25
- {spitch-1.27.0 → spitch-1.28.0}/CONTRIBUTING.md +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/LICENSE +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/SECURITY.md +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/api.md +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/bin/publish-pypi +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/examples/.keep +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/examples/example.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/mypy.ini +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/noxfile.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/release-please-config.json +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_client.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_compat.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_constants.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_exceptions.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_qs.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_resource.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_response.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_streaming.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_types.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/__init__.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_logs.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_proxy.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_reflection.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_resources_proxy.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_streams.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_sync.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_transform.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_typing.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/_utils/_utils.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/lib/.keep +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/py.typed +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/resources/__init__.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/resources/text.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/__init__.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/text_tone_mark_params.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/src/spitch/types/text_translate_params.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/__init__.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/api_resources/__init__.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/sample_file.txt +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_deepcopy.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_extract_files.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_files.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_qs.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_required_args.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_response.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_streaming.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_transform.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_utils/test_proxy.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/test_utils/test_typing.py +0 -0
- {spitch-1.27.0 → spitch-1.28.0}/tests/utils.py +0 -0
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.28.0 (2025-08-01)
|
|
4
|
+
|
|
5
|
+
Full Changelog: [v1.27.1...v1.28.0](https://github.com/spi-tch/spitch-python/compare/v1.27.1...v1.28.0)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* **api:** update via SDK Studio ([9db6264](https://github.com/spi-tch/spitch-python/commit/9db6264b632e315387983917ab7b42387e7c40c3))
|
|
10
|
+
* **api:** update via SDK Studio ([8fff307](https://github.com/spi-tch/spitch-python/commit/8fff307f77fee14c52877ff581338f3ec08a173e))
|
|
11
|
+
* clean up environment call outs ([fd8997e](https://github.com/spi-tch/spitch-python/commit/fd8997e1a67c568cf3f6e7061124ac27ded0a742))
|
|
12
|
+
* **client:** add support for aiohttp ([716f429](https://github.com/spi-tch/spitch-python/commit/716f4298354f2018155a9fd0a22b5446116081e3))
|
|
13
|
+
* **client:** support file upload requests ([60d3ce3](https://github.com/spi-tch/spitch-python/commit/60d3ce3ebc58ab4c0639b19c8e36078123ac7cc3))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **ci:** correct conditional ([1734cf4](https://github.com/spi-tch/spitch-python/commit/1734cf46a42f752642f04df64c701dd2ca7d60f5))
|
|
19
|
+
* **ci:** release-doctor — report correct token name ([1a09341](https://github.com/spi-tch/spitch-python/commit/1a09341c5dc0adc06a53824a7effcb987c1a3f33))
|
|
20
|
+
* **client:** don't send Content-Type header on GET requests ([b5a10cf](https://github.com/spi-tch/spitch-python/commit/b5a10cf567f59d90c259c8c6400b0cdf06af4ab3))
|
|
21
|
+
* **parsing:** correctly handle nested discriminated unions ([3e1a25b](https://github.com/spi-tch/spitch-python/commit/3e1a25b7953ed4611ca17c7ff4c84ffd032b5e4c))
|
|
22
|
+
* **parsing:** ignore empty metadata ([fc15e0e](https://github.com/spi-tch/spitch-python/commit/fc15e0ec9875c16f7aa8e00d6d8d8d4c60a866a8))
|
|
23
|
+
* **parsing:** parse extra field types ([8be1102](https://github.com/spi-tch/spitch-python/commit/8be11026e3d93b62aa77b170dd90acb5f246203a))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Chores
|
|
27
|
+
|
|
28
|
+
* **ci:** change upload type ([d9bf40f](https://github.com/spi-tch/spitch-python/commit/d9bf40f2b21338b7e3e1201b01ccd652417acfe4))
|
|
29
|
+
* **ci:** only run for pushes and fork pull requests ([bcba93e](https://github.com/spi-tch/spitch-python/commit/bcba93e8a69c3dec830e9d8040c76ebdda50cecf))
|
|
30
|
+
* **internal:** bump pinned h11 dep ([bd7d84b](https://github.com/spi-tch/spitch-python/commit/bd7d84b66fd468aabbc7dd6943579a330598bb98))
|
|
31
|
+
* **internal:** codegen related update ([8c23505](https://github.com/spi-tch/spitch-python/commit/8c235055fa37c950b3559e57a70ecd925ddaf518))
|
|
32
|
+
* **package:** mark python 3.13 as supported ([12c842b](https://github.com/spi-tch/spitch-python/commit/12c842bc7b4d6dbdd4376b79bf1581398363258e))
|
|
33
|
+
* **project:** add settings file for vscode ([8b0274c](https://github.com/spi-tch/spitch-python/commit/8b0274cb3d4c369550a823600bb4e493eb7b3638))
|
|
34
|
+
* **readme:** fix version rendering on pypi ([bf4b720](https://github.com/spi-tch/spitch-python/commit/bf4b720b71d72a1073179e68a3e55f2208bd0649))
|
|
35
|
+
* **tests:** skip some failing tests on the latest python versions ([9f60f27](https://github.com/spi-tch/spitch-python/commit/9f60f27835eccba43797fab6d033cdb116ec2a59))
|
|
36
|
+
|
|
37
|
+
## 1.27.1 (2025-06-19)
|
|
38
|
+
|
|
39
|
+
Full Changelog: [v1.27.0...v1.27.1](https://github.com/spi-tch/spitch-python/compare/v1.27.0...v1.27.1)
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([e6df2f6](https://github.com/spi-tch/spitch-python/commit/e6df2f6b390f5f3313ff1e20ee2890fd2ac53265))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Chores
|
|
47
|
+
|
|
48
|
+
* **readme:** update badges ([d272526](https://github.com/spi-tch/spitch-python/commit/d2725265a638bba5ef65bf8ab468a33af6b5b594))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Documentation
|
|
52
|
+
|
|
53
|
+
* **client:** fix httpx.Timeout documentation reference ([d8af609](https://github.com/spi-tch/spitch-python/commit/d8af609deca7a01713250544babf4ced45dc2376))
|
|
54
|
+
|
|
3
55
|
## 1.27.0 (2025-06-17)
|
|
4
56
|
|
|
5
57
|
Full Changelog: [v1.26.0...v1.27.0](https://github.com/spi-tch/spitch-python/compare/v1.26.0...v1.27.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: spitch
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.28.0
|
|
4
4
|
Summary: The official Python library for the spitch API
|
|
5
5
|
Project-URL: Homepage, https://github.com/spi-tch/spitch-python
|
|
6
6
|
Project-URL: Repository, https://github.com/spi-tch/spitch-python
|
|
@@ -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
|
|
@@ -28,11 +29,15 @@ Requires-Dist: httpx<0.28.0,>=0.23.0
|
|
|
28
29
|
Requires-Dist: pydantic<3,>=1.9.0
|
|
29
30
|
Requires-Dist: sniffio
|
|
30
31
|
Requires-Dist: typing-extensions<5,>=4.7
|
|
32
|
+
Provides-Extra: aiohttp
|
|
33
|
+
Requires-Dist: aiohttp; extra == 'aiohttp'
|
|
34
|
+
Requires-Dist: httpx-aiohttp>=0.1.8; extra == 'aiohttp'
|
|
31
35
|
Description-Content-Type: text/markdown
|
|
32
36
|
|
|
33
37
|
# Spitch Python API library
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
<!-- prettier-ignore -->
|
|
40
|
+
[)](https://pypi.org/project/spitch/)
|
|
36
41
|
|
|
37
42
|
The Spitch Python library provides convenient access to the Spitch REST API from any Python 3.8+
|
|
38
43
|
application. The library includes type definitions for all request params and response fields,
|
|
@@ -56,12 +61,9 @@ pip install spitch
|
|
|
56
61
|
The full API of this library can be found in [api.md](https://github.com/spi-tch/spitch-python/tree/main/api.md).
|
|
57
62
|
|
|
58
63
|
```python
|
|
59
|
-
import os
|
|
60
64
|
from spitch import Spitch
|
|
61
65
|
|
|
62
|
-
client = Spitch(
|
|
63
|
-
api_key=os.environ.get("SPITCH_API_KEY"), # This is the default and can be omitted
|
|
64
|
-
)
|
|
66
|
+
client = Spitch()
|
|
65
67
|
|
|
66
68
|
response = client.speech.generate(
|
|
67
69
|
language="yo",
|
|
@@ -80,13 +82,10 @@ so that your API Key is not stored in source control.
|
|
|
80
82
|
Simply import `AsyncSpitch` instead of `Spitch` and use `await` with each API call:
|
|
81
83
|
|
|
82
84
|
```python
|
|
83
|
-
import os
|
|
84
85
|
import asyncio
|
|
85
86
|
from spitch import AsyncSpitch
|
|
86
87
|
|
|
87
|
-
client = AsyncSpitch(
|
|
88
|
-
api_key=os.environ.get("SPITCH_API_KEY"), # This is the default and can be omitted
|
|
89
|
-
)
|
|
88
|
+
client = AsyncSpitch()
|
|
90
89
|
|
|
91
90
|
|
|
92
91
|
async def main() -> None:
|
|
@@ -102,6 +101,39 @@ asyncio.run(main())
|
|
|
102
101
|
|
|
103
102
|
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
|
104
103
|
|
|
104
|
+
### With aiohttp
|
|
105
|
+
|
|
106
|
+
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
|
107
|
+
|
|
108
|
+
You can enable this by installing `aiohttp`:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
# install from PyPI
|
|
112
|
+
pip install spitch[aiohttp]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import asyncio
|
|
119
|
+
from spitch import DefaultAioHttpClient
|
|
120
|
+
from spitch import AsyncSpitch
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
async def main() -> None:
|
|
124
|
+
async with AsyncSpitch(
|
|
125
|
+
http_client=DefaultAioHttpClient(),
|
|
126
|
+
) as client:
|
|
127
|
+
response = await client.speech.generate(
|
|
128
|
+
language="yo",
|
|
129
|
+
text="text",
|
|
130
|
+
voice="sade",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
asyncio.run(main())
|
|
135
|
+
```
|
|
136
|
+
|
|
105
137
|
## Using types
|
|
106
138
|
|
|
107
139
|
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:
|
|
@@ -202,7 +234,7 @@ client.with_options(max_retries=5).speech.generate(
|
|
|
202
234
|
### Timeouts
|
|
203
235
|
|
|
204
236
|
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
|
205
|
-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
|
237
|
+
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
|
206
238
|
|
|
207
239
|
```python
|
|
208
240
|
from spitch import Spitch
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Spitch Python API library
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- prettier-ignore -->
|
|
4
|
+
[)](https://pypi.org/project/spitch/)
|
|
4
5
|
|
|
5
6
|
The Spitch Python library provides convenient access to the Spitch REST API from any Python 3.8+
|
|
6
7
|
application. The library includes type definitions for all request params and response fields,
|
|
@@ -24,12 +25,9 @@ pip install spitch
|
|
|
24
25
|
The full API of this library can be found in [api.md](api.md).
|
|
25
26
|
|
|
26
27
|
```python
|
|
27
|
-
import os
|
|
28
28
|
from spitch import Spitch
|
|
29
29
|
|
|
30
|
-
client = Spitch(
|
|
31
|
-
api_key=os.environ.get("SPITCH_API_KEY"), # This is the default and can be omitted
|
|
32
|
-
)
|
|
30
|
+
client = Spitch()
|
|
33
31
|
|
|
34
32
|
response = client.speech.generate(
|
|
35
33
|
language="yo",
|
|
@@ -48,13 +46,10 @@ so that your API Key is not stored in source control.
|
|
|
48
46
|
Simply import `AsyncSpitch` instead of `Spitch` and use `await` with each API call:
|
|
49
47
|
|
|
50
48
|
```python
|
|
51
|
-
import os
|
|
52
49
|
import asyncio
|
|
53
50
|
from spitch import AsyncSpitch
|
|
54
51
|
|
|
55
|
-
client = AsyncSpitch(
|
|
56
|
-
api_key=os.environ.get("SPITCH_API_KEY"), # This is the default and can be omitted
|
|
57
|
-
)
|
|
52
|
+
client = AsyncSpitch()
|
|
58
53
|
|
|
59
54
|
|
|
60
55
|
async def main() -> None:
|
|
@@ -70,6 +65,39 @@ asyncio.run(main())
|
|
|
70
65
|
|
|
71
66
|
Functionality between the synchronous and asynchronous clients is otherwise identical.
|
|
72
67
|
|
|
68
|
+
### With aiohttp
|
|
69
|
+
|
|
70
|
+
By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.
|
|
71
|
+
|
|
72
|
+
You can enable this by installing `aiohttp`:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
# install from PyPI
|
|
76
|
+
pip install spitch[aiohttp]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import asyncio
|
|
83
|
+
from spitch import DefaultAioHttpClient
|
|
84
|
+
from spitch import AsyncSpitch
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def main() -> None:
|
|
88
|
+
async with AsyncSpitch(
|
|
89
|
+
http_client=DefaultAioHttpClient(),
|
|
90
|
+
) as client:
|
|
91
|
+
response = await client.speech.generate(
|
|
92
|
+
language="yo",
|
|
93
|
+
text="text",
|
|
94
|
+
voice="sade",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
asyncio.run(main())
|
|
99
|
+
```
|
|
100
|
+
|
|
73
101
|
## Using types
|
|
74
102
|
|
|
75
103
|
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:
|
|
@@ -170,7 +198,7 @@ client.with_options(max_retries=5).speech.generate(
|
|
|
170
198
|
### Timeouts
|
|
171
199
|
|
|
172
200
|
By default requests time out after 1 minute. You can configure this with a `timeout` option,
|
|
173
|
-
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:
|
|
201
|
+
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
|
|
174
202
|
|
|
175
203
|
```python
|
|
176
204
|
from spitch import Spitch
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
errors=()
|
|
4
4
|
|
|
5
5
|
if [ -z "${PYPI_TOKEN}" ]; then
|
|
6
|
-
errors+=("The
|
|
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 = "spitch"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.28.0"
|
|
4
4
|
description = "The official Python library for the spitch API"
|
|
5
5
|
dynamic = ["readme"]
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -25,6 +25,7 @@ classifiers = [
|
|
|
25
25
|
"Programming Language :: Python :: 3.10",
|
|
26
26
|
"Programming Language :: Python :: 3.11",
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
28
29
|
"Operating System :: OS Independent",
|
|
29
30
|
"Operating System :: POSIX",
|
|
30
31
|
"Operating System :: MacOS",
|
|
@@ -38,6 +39,8 @@ classifiers = [
|
|
|
38
39
|
Homepage = "https://github.com/spi-tch/spitch-python"
|
|
39
40
|
Repository = "https://github.com/spi-tch/spitch-python"
|
|
40
41
|
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"]
|
|
41
44
|
|
|
42
45
|
[tool.rye]
|
|
43
46
|
managed = 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.13
|
|
16
|
+
# via httpx-aiohttp
|
|
17
|
+
# via spitch
|
|
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 spitch
|
|
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
|
|
@@ -34,16 +45,23 @@ execnet==2.1.1
|
|
|
34
45
|
# via pytest-xdist
|
|
35
46
|
filelock==3.12.4
|
|
36
47
|
# via virtualenv
|
|
37
|
-
|
|
48
|
+
frozenlist==1.7.0
|
|
49
|
+
# via aiohttp
|
|
50
|
+
# via aiosignal
|
|
51
|
+
h11==0.16.0
|
|
38
52
|
# via httpcore
|
|
39
|
-
httpcore==1.0.
|
|
53
|
+
httpcore==1.0.9
|
|
40
54
|
# via httpx
|
|
41
|
-
httpx==0.
|
|
55
|
+
httpx==0.27.2
|
|
56
|
+
# via httpx-aiohttp
|
|
42
57
|
# via respx
|
|
43
58
|
# via spitch
|
|
59
|
+
httpx-aiohttp==0.1.8
|
|
60
|
+
# via spitch
|
|
44
61
|
idna==3.4
|
|
45
62
|
# via anyio
|
|
46
63
|
# via httpx
|
|
64
|
+
# via yarl
|
|
47
65
|
importlib-metadata==7.0.0
|
|
48
66
|
iniconfig==2.0.0
|
|
49
67
|
# via pytest
|
|
@@ -51,6 +69,9 @@ markdown-it-py==3.0.0
|
|
|
51
69
|
# via rich
|
|
52
70
|
mdurl==0.1.2
|
|
53
71
|
# via markdown-it-py
|
|
72
|
+
multidict==6.5.0
|
|
73
|
+
# via aiohttp
|
|
74
|
+
# via yarl
|
|
54
75
|
mypy==1.14.1
|
|
55
76
|
mypy-extensions==1.0.0
|
|
56
77
|
# via mypy
|
|
@@ -65,6 +86,9 @@ platformdirs==3.11.0
|
|
|
65
86
|
# via virtualenv
|
|
66
87
|
pluggy==1.5.0
|
|
67
88
|
# via pytest
|
|
89
|
+
propcache==0.3.2
|
|
90
|
+
# via aiohttp
|
|
91
|
+
# via yarl
|
|
68
92
|
pydantic==2.9.2
|
|
69
93
|
# via spitch
|
|
70
94
|
pydantic-core==2.23.4
|
|
@@ -90,6 +114,7 @@ six==1.16.0
|
|
|
90
114
|
# via python-dateutil
|
|
91
115
|
sniffio==1.3.0
|
|
92
116
|
# via anyio
|
|
117
|
+
# via httpx
|
|
93
118
|
# via spitch
|
|
94
119
|
time-machine==2.9.0
|
|
95
120
|
tomli==2.0.2
|
|
@@ -97,11 +122,15 @@ tomli==2.0.2
|
|
|
97
122
|
# via pytest
|
|
98
123
|
typing-extensions==4.12.2
|
|
99
124
|
# via anyio
|
|
125
|
+
# via multidict
|
|
100
126
|
# via mypy
|
|
101
127
|
# via pydantic
|
|
102
128
|
# via pydantic-core
|
|
129
|
+
# via pyright
|
|
103
130
|
# via spitch
|
|
104
131
|
virtualenv==20.24.5
|
|
105
132
|
# via nox
|
|
133
|
+
yarl==1.20.1
|
|
134
|
+
# via aiohttp
|
|
106
135
|
zipp==3.17.0
|
|
107
136
|
# 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.13
|
|
16
|
+
# via httpx-aiohttp
|
|
17
|
+
# via spitch
|
|
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 spitch
|
|
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,24 +33,41 @@ distro==1.8.0
|
|
|
22
33
|
# via spitch
|
|
23
34
|
exceptiongroup==1.2.2
|
|
24
35
|
# via anyio
|
|
25
|
-
|
|
36
|
+
frozenlist==1.7.0
|
|
37
|
+
# via aiohttp
|
|
38
|
+
# via aiosignal
|
|
39
|
+
h11==0.16.0
|
|
26
40
|
# via httpcore
|
|
27
|
-
httpcore==1.0.
|
|
41
|
+
httpcore==1.0.9
|
|
28
42
|
# via httpx
|
|
29
|
-
httpx==0.
|
|
43
|
+
httpx==0.27.2
|
|
44
|
+
# via httpx-aiohttp
|
|
45
|
+
# via spitch
|
|
46
|
+
httpx-aiohttp==0.1.8
|
|
30
47
|
# via spitch
|
|
31
48
|
idna==3.4
|
|
32
49
|
# via anyio
|
|
33
50
|
# via httpx
|
|
51
|
+
# via yarl
|
|
52
|
+
multidict==6.5.0
|
|
53
|
+
# via aiohttp
|
|
54
|
+
# via yarl
|
|
55
|
+
propcache==0.3.2
|
|
56
|
+
# via aiohttp
|
|
57
|
+
# via yarl
|
|
34
58
|
pydantic==2.9.2
|
|
35
59
|
# via spitch
|
|
36
60
|
pydantic-core==2.23.4
|
|
37
61
|
# via pydantic
|
|
38
62
|
sniffio==1.3.0
|
|
39
63
|
# via anyio
|
|
64
|
+
# via httpx
|
|
40
65
|
# via spitch
|
|
41
66
|
typing-extensions==4.12.2
|
|
42
67
|
# via anyio
|
|
68
|
+
# via multidict
|
|
43
69
|
# via pydantic
|
|
44
70
|
# via pydantic-core
|
|
45
71
|
# via spitch
|
|
72
|
+
yarl==1.20.1
|
|
73
|
+
# 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__ = [
|
|
@@ -67,6 +67,7 @@ __all__ = [
|
|
|
67
67
|
"DEFAULT_CONNECTION_LIMITS",
|
|
68
68
|
"DefaultHttpxClient",
|
|
69
69
|
"DefaultAsyncHttpxClient",
|
|
70
|
+
"DefaultAioHttpClient",
|
|
70
71
|
]
|
|
71
72
|
|
|
72
73
|
if not _t.TYPE_CHECKING:
|
|
@@ -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
|
|
|
@@ -1289,6 +1299,24 @@ class _DefaultAsyncHttpxClient(httpx.AsyncClient):
|
|
|
1289
1299
|
super().__init__(**kwargs)
|
|
1290
1300
|
|
|
1291
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
|
+
|
|
1292
1320
|
if TYPE_CHECKING:
|
|
1293
1321
|
DefaultAsyncHttpxClient = httpx.AsyncClient
|
|
1294
1322
|
"""An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
|
|
@@ -1297,8 +1325,12 @@ if TYPE_CHECKING:
|
|
|
1297
1325
|
This is useful because overriding the `http_client` with your own instance of
|
|
1298
1326
|
`httpx.AsyncClient` will result in httpx's defaults being used, not ours.
|
|
1299
1327
|
"""
|
|
1328
|
+
|
|
1329
|
+
DefaultAioHttpClient = httpx.AsyncClient
|
|
1330
|
+
"""An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
|
|
1300
1331
|
else:
|
|
1301
1332
|
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
|
|
1333
|
+
DefaultAioHttpClient = _DefaultAioHttpClient
|
|
1302
1334
|
|
|
1303
1335
|
|
|
1304
1336
|
class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
|
|
@@ -69,12 +69,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes:
|
|
|
69
69
|
return file
|
|
70
70
|
|
|
71
71
|
if is_tuple_t(file):
|
|
72
|
-
return (file[0],
|
|
72
|
+
return (file[0], read_file_content(file[1]), *file[2:])
|
|
73
73
|
|
|
74
74
|
raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def
|
|
77
|
+
def read_file_content(file: FileContent) -> HttpxFileContent:
|
|
78
78
|
if isinstance(file, os.PathLike):
|
|
79
79
|
return pathlib.Path(file).read_bytes()
|
|
80
80
|
return file
|
|
@@ -111,12 +111,12 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes:
|
|
|
111
111
|
return file
|
|
112
112
|
|
|
113
113
|
if is_tuple_t(file):
|
|
114
|
-
return (file[0], await
|
|
114
|
+
return (file[0], await async_read_file_content(file[1]), *file[2:])
|
|
115
115
|
|
|
116
116
|
raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple")
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
async def
|
|
119
|
+
async def async_read_file_content(file: FileContent) -> HttpxFileContent:
|
|
120
120
|
if isinstance(file, os.PathLike):
|
|
121
121
|
return await anyio.Path(file).read_bytes()
|
|
122
122
|
|
|
@@ -2,9 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import inspect
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
|
|
6
6
|
from datetime import date, datetime
|
|
7
7
|
from typing_extensions import (
|
|
8
|
+
List,
|
|
8
9
|
Unpack,
|
|
9
10
|
Literal,
|
|
10
11
|
ClassVar,
|
|
@@ -206,14 +207,18 @@ class BaseModel(pydantic.BaseModel):
|
|
|
206
207
|
else:
|
|
207
208
|
fields_values[name] = field_get_default(field)
|
|
208
209
|
|
|
210
|
+
extra_field_type = _get_extra_fields_type(__cls)
|
|
211
|
+
|
|
209
212
|
_extra = {}
|
|
210
213
|
for key, value in values.items():
|
|
211
214
|
if key not in model_fields:
|
|
215
|
+
parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value
|
|
216
|
+
|
|
212
217
|
if PYDANTIC_V2:
|
|
213
|
-
_extra[key] =
|
|
218
|
+
_extra[key] = parsed
|
|
214
219
|
else:
|
|
215
220
|
_fields_set.add(key)
|
|
216
|
-
fields_values[key] =
|
|
221
|
+
fields_values[key] = parsed
|
|
217
222
|
|
|
218
223
|
object.__setattr__(m, "__dict__", fields_values)
|
|
219
224
|
|
|
@@ -365,7 +370,24 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
|
|
|
365
370
|
if type_ is None:
|
|
366
371
|
raise RuntimeError(f"Unexpected field type is None for {key}")
|
|
367
372
|
|
|
368
|
-
return construct_type(value=value, type_=type_)
|
|
373
|
+
return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None:
|
|
377
|
+
if not PYDANTIC_V2:
|
|
378
|
+
# TODO
|
|
379
|
+
return None
|
|
380
|
+
|
|
381
|
+
schema = cls.__pydantic_core_schema__
|
|
382
|
+
if schema["type"] == "model":
|
|
383
|
+
fields = schema["schema"]
|
|
384
|
+
if fields["type"] == "model-fields":
|
|
385
|
+
extras = fields.get("extras_schema")
|
|
386
|
+
if extras and "cls" in extras:
|
|
387
|
+
# mypy can't narrow the type
|
|
388
|
+
return extras["cls"] # type: ignore[no-any-return]
|
|
389
|
+
|
|
390
|
+
return None
|
|
369
391
|
|
|
370
392
|
|
|
371
393
|
def is_basemodel(type_: type) -> bool:
|
|
@@ -419,7 +441,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T:
|
|
|
419
441
|
return cast(_T, construct_type(value=value, type_=type_))
|
|
420
442
|
|
|
421
443
|
|
|
422
|
-
def construct_type(*, value: object, type_: object) -> object:
|
|
444
|
+
def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object:
|
|
423
445
|
"""Loose coercion to the expected type with construction of nested values.
|
|
424
446
|
|
|
425
447
|
If the given value does not match the expected type then it is returned as-is.
|
|
@@ -434,8 +456,10 @@ def construct_type(*, value: object, type_: object) -> object:
|
|
|
434
456
|
type_ = cast("type[object]", type_)
|
|
435
457
|
|
|
436
458
|
# unwrap `Annotated[T, ...]` -> `T`
|
|
437
|
-
if
|
|
438
|
-
meta: tuple[Any, ...] =
|
|
459
|
+
if metadata is not None and len(metadata) > 0:
|
|
460
|
+
meta: tuple[Any, ...] = tuple(metadata)
|
|
461
|
+
elif is_annotated_type(type_):
|
|
462
|
+
meta = get_args(type_)[1:]
|
|
439
463
|
type_ = extract_type_arg(type_, 0)
|
|
440
464
|
else:
|
|
441
465
|
meta = tuple()
|