Skip to content

Commit 846b038

Browse files
release: 0.37.0 (#259)
Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Graden Rea <grea@groq.com>
1 parent 45155a6 commit 846b038

11 files changed

Lines changed: 165 additions & 114 deletions

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.36.0"
2+
".": "0.37.0"
33
}

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 17
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-50245ef9d4df0e66805d3dd75d7a68915c9007d64599af17c9d016f698919d02.yml
3-
openapi_spec_hash: b2d428817feb68795013e7300c4fc681
4-
config_hash: a4a6c3089a2e53425351cc9f42b4b5aa
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-aa20a6b53361210f495bb7c44a6edc36f6a59f7c434d79b660d433d7cb419e54.yml
3+
openapi_spec_hash: 7d29da2abb6833f7a891a53f49449122
4+
config_hash: 4719968e58eab04c8641284bcf18ef5d

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
# Changelog
22

3+
## 0.37.0 (2025-12-01)
4+
5+
Full Changelog: [v0.36.0...v0.37.0](https://github.com/groq/groq-python/compare/v0.36.0...v0.37.0)
6+
7+
### Features
8+
9+
* **api:** api update ([5d0d829](https://github.com/groq/groq-python/commit/5d0d829b558744b20f484bb51e21dbba5faea1c8))
10+
11+
12+
### Bug Fixes
13+
14+
* always call close in the streaming generators ([f19496e](https://github.com/groq/groq-python/commit/f19496e290c60dd3b368d2485bcab69ffd955dd0))
15+
* ensure streams are always closed ([ba33c5e](https://github.com/groq/groq-python/commit/ba33c5e0bb9cac681b4334f11423e7be70bd5149))
16+
17+
18+
### Chores
19+
20+
* add Python 3.14 classifier and testing ([26120a6](https://github.com/groq/groq-python/commit/26120a6a1bd7618413b5cca4324a1f7f4863d78e))
21+
* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([ceaffd2](https://github.com/groq/groq-python/commit/ceaffd2187418c99461e145efe1ea51fced6d4f3))
22+
323
## 0.36.0 (2025-11-20)
424

525
Full Changelog: [v0.35.0...v0.36.0](https://github.com/groq/groq-python/compare/v0.35.0...v0.36.0)

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "groq"
3-
version = "0.36.0"
3+
version = "0.37.0"
44
description = "The official Python library for the groq API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"
@@ -24,6 +24,7 @@ classifiers = [
2424
"Programming Language :: Python :: 3.11",
2525
"Programming Language :: Python :: 3.12",
2626
"Programming Language :: Python :: 3.13",
27+
"Programming Language :: Python :: 3.14",
2728
"Operating System :: OS Independent",
2829
"Operating System :: POSIX",
2930
"Operating System :: MacOS",
@@ -45,7 +46,7 @@ managed = true
4546
# version pins are in requirements-dev.lock
4647
dev-dependencies = [
4748
"pyright==1.1.399",
48-
"mypy",
49+
"mypy==1.17",
4950
"respx",
5051
"pytest",
5152
"pytest-asyncio",

requirements-dev.lock

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ mdurl==0.1.2
7272
multidict==6.4.4
7373
# via aiohttp
7474
# via yarl
75-
mypy==1.14.1
75+
mypy==1.17.0
7676
mypy-extensions==1.0.0
7777
# via mypy
7878
nodeenv==1.8.0
@@ -81,6 +81,8 @@ nox==2023.4.22
8181
packaging==23.2
8282
# via nox
8383
# via pytest
84+
pathspec==0.12.1
85+
# via mypy
8486
platformdirs==3.11.0
8587
# via virtualenv
8688
pluggy==1.5.0

requirements.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,21 @@ multidict==6.4.4
5555
propcache==0.3.1
5656
# via aiohttp
5757
# via yarl
58-
pydantic==2.11.9
58+
pydantic==2.12.5
5959
# via groq
60-
pydantic-core==2.33.2
60+
pydantic-core==2.41.5
6161
# via pydantic
6262
sniffio==1.3.0
6363
# via anyio
6464
# via groq
65-
typing-extensions==4.12.2
65+
typing-extensions==4.15.0
6666
# via anyio
6767
# via groq
6868
# via multidict
6969
# via pydantic
7070
# via pydantic-core
7171
# via typing-inspection
72-
typing-inspection==0.4.1
72+
typing-inspection==0.4.2
7373
# via pydantic
7474
yarl==1.20.0
7575
# via aiohttp

src/groq/_streaming.py

Lines changed: 88 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -55,49 +55,50 @@ def __stream__(self) -> Iterator[_T]:
5555
process_data = self._client._process_response_data
5656
iterator = self._iter_events()
5757

58-
for sse in iterator:
59-
if sse.data.startswith("[DONE]"):
60-
break
61-
62-
if sse.event is None:
63-
data = sse.json()
64-
if is_mapping(data) and data.get("error"):
65-
message = None
66-
error = data.get("error")
67-
if is_mapping(error):
68-
message = error.get("message")
69-
if not message or not isinstance(message, str):
70-
message = "An error occurred during streaming"
71-
72-
raise APIError(
73-
message=message,
74-
request=self.response.request,
75-
body=data["error"],
76-
)
77-
78-
yield process_data(data=data, cast_to=cast_to, response=response)
79-
80-
else:
81-
data = sse.json()
82-
83-
if sse.event == "error" and is_mapping(data) and data.get("error"):
84-
message = None
85-
error = data.get("error")
86-
if is_mapping(error):
87-
message = error.get("message")
88-
if not message or not isinstance(message, str):
89-
message = "An error occurred during streaming"
90-
91-
raise APIError(
92-
message=message,
93-
request=self.response.request,
94-
body=data["error"],
95-
)
96-
97-
yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response)
98-
99-
# As we might not fully consume the response stream, we need to close it explicitly
100-
response.close()
58+
try:
59+
for sse in iterator:
60+
if sse.data.startswith("[DONE]"):
61+
break
62+
63+
if sse.event is None:
64+
data = sse.json()
65+
if is_mapping(data) and data.get("error"):
66+
message = None
67+
error = data.get("error")
68+
if is_mapping(error):
69+
message = error.get("message")
70+
if not message or not isinstance(message, str):
71+
message = "An error occurred during streaming"
72+
73+
raise APIError(
74+
message=message,
75+
request=self.response.request,
76+
body=data["error"],
77+
)
78+
79+
yield process_data(data=data, cast_to=cast_to, response=response)
80+
81+
else:
82+
data = sse.json()
83+
84+
if sse.event == "error" and is_mapping(data) and data.get("error"):
85+
message = None
86+
error = data.get("error")
87+
if is_mapping(error):
88+
message = error.get("message")
89+
if not message or not isinstance(message, str):
90+
message = "An error occurred during streaming"
91+
92+
raise APIError(
93+
message=message,
94+
request=self.response.request,
95+
body=data["error"],
96+
)
97+
98+
yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response)
99+
finally:
100+
# Ensure the response is closed even if the consumer doesn't read all data
101+
response.close()
101102

102103
def __enter__(self) -> Self:
103104
return self
@@ -156,49 +157,50 @@ async def __stream__(self) -> AsyncIterator[_T]:
156157
process_data = self._client._process_response_data
157158
iterator = self._iter_events()
158159

159-
async for sse in iterator:
160-
if sse.data.startswith("[DONE]"):
161-
break
162-
163-
if sse.event is None:
164-
data = sse.json()
165-
if is_mapping(data) and data.get("error"):
166-
message = None
167-
error = data.get("error")
168-
if is_mapping(error):
169-
message = error.get("message")
170-
if not message or not isinstance(message, str):
171-
message = "An error occurred during streaming"
172-
173-
raise APIError(
174-
message=message,
175-
request=self.response.request,
176-
body=data["error"],
177-
)
178-
179-
yield process_data(data=data, cast_to=cast_to, response=response)
180-
181-
else:
182-
data = sse.json()
183-
184-
if sse.event == "error" and is_mapping(data) and data.get("error"):
185-
message = None
186-
error = data.get("error")
187-
if is_mapping(error):
188-
message = error.get("message")
189-
if not message or not isinstance(message, str):
190-
message = "An error occurred during streaming"
191-
192-
raise APIError(
193-
message=message,
194-
request=self.response.request,
195-
body=data["error"],
196-
)
197-
198-
yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response)
199-
200-
# As we might not fully consume the response stream, we need to close it explicitly
201-
await response.aclose()
160+
try:
161+
async for sse in iterator:
162+
if sse.data.startswith("[DONE]"):
163+
break
164+
165+
if sse.event is None:
166+
data = sse.json()
167+
if is_mapping(data) and data.get("error"):
168+
message = None
169+
error = data.get("error")
170+
if is_mapping(error):
171+
message = error.get("message")
172+
if not message or not isinstance(message, str):
173+
message = "An error occurred during streaming"
174+
175+
raise APIError(
176+
message=message,
177+
request=self.response.request,
178+
body=data["error"],
179+
)
180+
181+
yield process_data(data=data, cast_to=cast_to, response=response)
182+
183+
else:
184+
data = sse.json()
185+
186+
if sse.event == "error" and is_mapping(data) and data.get("error"):
187+
message = None
188+
error = data.get("error")
189+
if is_mapping(error):
190+
message = error.get("message")
191+
if not message or not isinstance(message, str):
192+
message = "An error occurred during streaming"
193+
194+
raise APIError(
195+
message=message,
196+
request=self.response.request,
197+
body=data["error"],
198+
)
199+
200+
yield process_data(data={"data": data, "event": sse.event}, cast_to=cast_to, response=response)
201+
finally:
202+
# Ensure the response is closed even if the consumer doesn't read all data
203+
await response.aclose()
202204

203205
async def __aenter__(self) -> Self:
204206
return self

src/groq/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "groq"
4-
__version__ = "0.36.0" # x-release-please-version
4+
__version__ = "0.37.0" # x-release-please-version

src/groq/resources/chat/completions.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ def create(
110110
extra_query: Query | None = None,
111111
extra_body: Body | None = None,
112112
timeout: float | httpx.Timeout | None | NotGiven = not_given,
113-
) -> ChatCompletion:
114-
...
113+
) -> ChatCompletion: ...
115114

116115
@overload
117116
def create(
@@ -174,8 +173,7 @@ def create(
174173
extra_query: Query | None = None,
175174
extra_body: Body | None = None,
176175
timeout: float | httpx.Timeout | None | NotGiven = not_given,
177-
) -> Stream[ChatCompletionChunk]:
178-
...
176+
) -> Stream[ChatCompletionChunk]: ...
179177

180178
@overload
181179
def create(
@@ -238,8 +236,7 @@ def create(
238236
extra_query: Query | None = None,
239237
extra_body: Body | None = None,
240238
timeout: float | httpx.Timeout | None | NotGiven = not_given,
241-
) -> ChatCompletion | Stream[ChatCompletionChunk]:
242-
...
239+
) -> ChatCompletion | Stream[ChatCompletionChunk]: ...
243240

244241
def create(
245242
self,
@@ -593,8 +590,7 @@ async def create(
593590
extra_query: Query | None = None,
594591
extra_body: Body | None = None,
595592
timeout: float | httpx.Timeout | None | NotGiven = not_given,
596-
) -> ChatCompletion:
597-
...
593+
) -> ChatCompletion: ...
598594

599595
@overload
600596
async def create(
@@ -657,8 +653,7 @@ async def create(
657653
extra_query: Query | None = None,
658654
extra_body: Body | None = None,
659655
timeout: float | httpx.Timeout | None | NotGiven = not_given,
660-
) -> AsyncStream[ChatCompletionChunk]:
661-
...
656+
) -> AsyncStream[ChatCompletionChunk]: ...
662657

663658
@overload
664659
async def create(
@@ -721,8 +716,7 @@ async def create(
721716
extra_query: Query | None = None,
722717
extra_body: Body | None = None,
723718
timeout: float | httpx.Timeout | None | NotGiven = not_given,
724-
) -> ChatCompletion | AsyncStream[ChatCompletionChunk]:
725-
...
719+
) -> ChatCompletion | AsyncStream[ChatCompletionChunk]: ...
726720

727721
async def create(
728722
self,

src/groq/types/chat/chat_completion_chunk.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class ChoiceDelta(BaseModel):
9797
systems.
9898
"""
9999

100+
100101
class ChoiceLogprobs(BaseModel):
101102
content: Optional[List[ChatCompletionTokenLogprob]] = None
102103
"""A list of message content tokens with log probability information."""

0 commit comments

Comments
 (0)